From b63aa0737c97e91bf57fa98e535b51c3b7c5439f Mon Sep 17 00:00:00 2001 From: hailin Date: Thu, 25 Dec 2025 21:23:22 -0800 Subject: [PATCH] =?UTF-8?q?feat(mobile-app):=20=E6=B7=BB=E5=8A=A0=E5=90=8E?= =?UTF-8?q?=E5=8F=B0=E5=AE=9A=E6=97=B6=E6=A3=80=E6=B5=8B=E6=9C=AA=E7=AD=BE?= =?UTF-8?q?=E7=BD=B2=E5=90=88=E5=90=8C=E5=92=8CKYC=E9=9C=80=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 60-180 秒随机间隔的后台定时器 - 检测已KYC但未签署合同的用户,强制跳转签署页面 - 检测已付款但未完成KYC的用户,强制跳转实名认证页面 - 使用 PopScope 替代已弃用的 WillPopScope - 防止重复弹窗的状态管理 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../presentation/pages/home_shell_page.dart | 127 +++++++++++++++++- 1 file changed, 123 insertions(+), 4 deletions(-) diff --git a/frontend/mobile-app/lib/features/home/presentation/pages/home_shell_page.dart b/frontend/mobile-app/lib/features/home/presentation/pages/home_shell_page.dart index 448dbc96..108e489c 100644 --- a/frontend/mobile-app/lib/features/home/presentation/pages/home_shell_page.dart +++ b/frontend/mobile-app/lib/features/home/presentation/pages/home_shell_page.dart @@ -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 /// 是否已检查过合同(防止重复检查) static bool _hasCheckedContracts = false; + /// 后台合同检查定时器 + Timer? _contractCheckTimer; + + /// 是否正在显示弹窗(防止重复弹窗) + bool _isShowingDialog = false; + @override void initState() { super.initState(); @@ -35,12 +41,15 @@ class _HomeShellPageState extends ConsumerState 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 // 从后台恢复时检查更新 if (state == AppLifecycleState.resumed) { _checkForUpdateIfNeeded(); + // 从后台恢复时也触发一次检查 + _scheduleNextContractCheck(); + } else if (state == AppLifecycleState.paused) { + // 进入后台时取消定时器 + _contractCheckTimer?.cancel(); } } @@ -64,6 +78,57 @@ class _HomeShellPageState extends ConsumerState } } + /// 启动后台合同检查定时器 + 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 _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 _checkContractsAndKyc() async { // 每次会话只检查一次 @@ -94,16 +159,67 @@ class _HomeShellPageState extends ConsumerState } } + /// 显示合同签署必需弹窗(后台检测触发) + Future _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 _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 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 ElevatedButton( onPressed: () { Navigator.of(context).pop(); + _isShowingDialog = false; // 跳转到 KYC 入口页面 context.push(RoutePaths.kycEntry); }, @@ -165,6 +282,8 @@ class _HomeShellPageState extends ConsumerState ), ), ); + + _isShowingDialog = false; } /// 重置合同检查状态(用于用户切换账号时)