feat(mobile-app): 添加后台定时检测未签署合同和KYC需求

- 添加 60-180 秒随机间隔的后台定时器
- 检测已KYC但未签署合同的用户,强制跳转签署页面
- 检测已付款但未完成KYC的用户,强制跳转实名认证页面
- 使用 PopScope 替代已弃用的 WillPopScope
- 防止重复弹窗的状态管理

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2025-12-25 21:23:22 -08:00
parent f62a96f3f1
commit b63aa0737c
1 changed files with 123 additions and 4 deletions

View File

@ -1,9 +1,9 @@
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../../core/theme/app_colors.dart';
import '../../../../core/theme/app_dimensions.dart';
import '../../../../core/di/injection_container.dart';
import '../../../../core/services/contract_check_service.dart';
import '../../../../routes/route_paths.dart';
@ -27,6 +27,12 @@ class _HomeShellPageState extends ConsumerState<HomeShellPage>
///
static bool _hasCheckedContracts = false;
///
Timer? _contractCheckTimer;
///
bool _isShowingDialog = false;
@override
void initState() {
super.initState();
@ -35,12 +41,15 @@ class _HomeShellPageState extends ConsumerState<HomeShellPage>
WidgetsBinding.instance.addPostFrameCallback((_) {
_checkForUpdateIfNeeded();
_checkContractsAndKyc();
//
_startBackgroundContractCheck();
});
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
_contractCheckTimer?.cancel();
super.dispose();
}
@ -49,6 +58,11 @@ class _HomeShellPageState extends ConsumerState<HomeShellPage>
//
if (state == AppLifecycleState.resumed) {
_checkForUpdateIfNeeded();
//
_scheduleNextContractCheck();
} else if (state == AppLifecycleState.paused) {
//
_contractCheckTimer?.cancel();
}
}
@ -64,6 +78,57 @@ class _HomeShellPageState extends ConsumerState<HomeShellPage>
}
}
///
void _startBackgroundContractCheck() {
_scheduleNextContractCheck();
}
/// 60-180
void _scheduleNextContractCheck() {
_contractCheckTimer?.cancel();
// 60-180 1-3
final randomSeconds = 60 + Random().nextInt(121); // 60 + 0~120 = 60~180
debugPrint('[HomeShellPage] 下次合同检查将在 $randomSeconds 秒后执行');
_contractCheckTimer = Timer(Duration(seconds: randomSeconds), () async {
await _performBackgroundContractCheck();
//
if (mounted) {
_scheduleNextContractCheck();
}
});
}
/// + KYC
Future<void> _performBackgroundContractCheck() async {
if (!mounted || _isShowingDialog) return;
try {
debugPrint('[HomeShellPage] 执行后台综合检查...');
final contractCheckService = ref.read(contractCheckServiceProvider);
final result = await contractCheckService.checkAll();
if (!mounted || _isShowingDialog) return;
// 1.
if (result.hasPendingContracts) {
debugPrint('[HomeShellPage] 后台检测到待签署合同,显示弹窗');
await _showContractRequiredDialog();
return;
}
// 2. KYC
if (result.requiresKyc) {
debugPrint('[HomeShellPage] 后台检测到需要KYC显示弹窗');
await _showKycRequiredDialog(result);
}
} catch (e) {
debugPrint('[HomeShellPage] 后台综合检查失败: $e');
}
}
/// KYC
Future<void> _checkContractsAndKyc() async {
//
@ -94,16 +159,67 @@ class _HomeShellPageState extends ConsumerState<HomeShellPage>
}
}
///
Future<void> _showContractRequiredDialog() async {
if (_isShowingDialog) return;
_isShowingDialog = true;
const message =
'系统检测到您已认种了榴莲树但尚未按国家法规签署合规的认种合同。请先完成合同签署才能继续使用APP。';
await showDialog(
context: context,
barrierDismissible: false, //
builder: (context) => PopScope(
canPop: false, //
child: AlertDialog(
title: Row(
children: [
Icon(Icons.description_outlined, color: Colors.orange[700], size: 28),
const SizedBox(width: 8),
const Text('需要签署合同'),
],
),
content: const Text(
message,
style: TextStyle(fontSize: 15, height: 1.5),
),
actions: [
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
_isShowingDialog = false;
//
context.push(RoutePaths.pendingContracts, extra: true);
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primary,
foregroundColor: Colors.white,
minimumSize: const Size(double.infinity, 48),
),
child: const Text('立即签署', style: TextStyle(fontSize: 16)),
),
],
),
),
);
_isShowingDialog = false;
}
/// KYC
Future<void> _showKycRequiredDialog(ContractCheckResult result) async {
if (_isShowingDialog) return;
_isShowingDialog = true;
final message = result.kycMessage ??
'系统检测到您已认种了榴莲树但尚未按国家法规完成实名认证无法签署合同。请先完成实名认证后才能继续使用APP。';
await showDialog(
context: context,
barrierDismissible: false, //
builder: (context) => WillPopScope(
onWillPop: () async => false, //
builder: (context) => PopScope(
canPop: false, //
child: AlertDialog(
title: Row(
children: [
@ -125,7 +241,7 @@ class _HomeShellPageState extends ConsumerState<HomeShellPage>
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.orange.withOpacity(0.1),
color: Colors.orange.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(8),
),
child: Row(
@ -151,6 +267,7 @@ class _HomeShellPageState extends ConsumerState<HomeShellPage>
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
_isShowingDialog = false;
// KYC
context.push(RoutePaths.kycEntry);
},
@ -165,6 +282,8 @@ class _HomeShellPageState extends ConsumerState<HomeShellPage>
),
),
);
_isShowingDialog = false;
}
///