feat(planting): 认种成功后检查实名认证状态
当CONTRACT_SIGNING_ENABLED=true时,认种成功后检查用户是否已完成实名认证: - 如果未完成实名认证,显示提示弹窗引导用户去认证 - 如果已完成或功能未启用,按原有流程返回个人中心 新增: - KycRequiredDialog 实名认证提示弹窗组件 - ContractSigningConfig 配置类和getConfig()方法 - kycServiceProvider 依赖注入 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
bc34907a84
commit
59e9cddf5b
|
|
@ -14,6 +14,7 @@ import '../services/notification_service.dart';
|
|||
import '../services/system_config_service.dart';
|
||||
import '../services/contract_signing_service.dart';
|
||||
import '../services/contract_check_service.dart';
|
||||
import '../../features/kyc/data/kyc_service.dart';
|
||||
|
||||
// Storage Providers
|
||||
final secureStorageProvider = Provider<SecureStorage>((ref) {
|
||||
|
|
@ -107,6 +108,12 @@ final contractCheckServiceProvider = Provider<ContractCheckService>((ref) {
|
|||
return ContractCheckService(contractSigningService: contractSigningService);
|
||||
});
|
||||
|
||||
// KYC Service Provider (调用 identity-service)
|
||||
final kycServiceProvider = Provider<KycService>((ref) {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
return KycService(apiClient: apiClient);
|
||||
});
|
||||
|
||||
// Override provider with initialized instance
|
||||
ProviderContainer createProviderContainer(LocalStorage localStorage) {
|
||||
return ProviderContainer(
|
||||
|
|
|
|||
|
|
@ -153,6 +153,30 @@ class ContractSigningService {
|
|||
|
||||
ContractSigningService({required ApiClient apiClient}) : _apiClient = apiClient;
|
||||
|
||||
/// 获取合同签署配置(公开接口,不需要认证)
|
||||
/// 用于判断是否需要在认种前检查实名认证
|
||||
Future<ContractSigningConfig> getConfig() async {
|
||||
try {
|
||||
debugPrint('[ContractSigningService] 获取合同签署配置');
|
||||
|
||||
final response = await _apiClient.get('/planting/contract-signing/config');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
if (data['success'] == true && data['data'] != null) {
|
||||
return ContractSigningConfig.fromJson(data['data']);
|
||||
}
|
||||
}
|
||||
|
||||
// 默认启用合同签署
|
||||
return ContractSigningConfig(contractSigningEnabled: true);
|
||||
} catch (e) {
|
||||
debugPrint('[ContractSigningService] 获取配置失败: $e');
|
||||
// 获取失败时默认启用合同签署
|
||||
return ContractSigningConfig(contractSigningEnabled: true);
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取待签署任务列表
|
||||
Future<List<ContractSigningTask>> getPendingTasks() async {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:go_router/go_router.dart';
|
||||
import 'package:city_pickers/city_pickers.dart';
|
||||
import '../widgets/planting_confirm_dialog.dart';
|
||||
import '../widgets/kyc_required_dialog.dart';
|
||||
import '../../../../core/di/injection_container.dart';
|
||||
import '../../../../routes/route_paths.dart';
|
||||
|
||||
/// 认种省市选择页面参数
|
||||
class PlantingLocationParams {
|
||||
|
|
@ -208,6 +210,37 @@ class _PlantingLocationPageState extends ConsumerState<PlantingLocationPage> {
|
|||
);
|
||||
}
|
||||
|
||||
/// 检查是否需要实名认证
|
||||
/// 仅在合同签署功能启用时才需要检查
|
||||
Future<bool> _checkKycRequirement() async {
|
||||
try {
|
||||
// 1. 获取合同签署配置
|
||||
final contractSigningService = ref.read(contractSigningServiceProvider);
|
||||
final config = await contractSigningService.getConfig();
|
||||
|
||||
// 如果合同签署功能未启用,不需要检查实名认证
|
||||
if (!config.contractSigningEnabled) {
|
||||
debugPrint('[PlantingLocationPage] 合同签署功能未启用,跳过实名认证检查');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 合同签署功能启用时,检查实名认证状态
|
||||
final kycService = ref.read(kycServiceProvider);
|
||||
final kycStatus = await kycService.getKycStatus();
|
||||
|
||||
// 检查层级1(实名认证)是否完成
|
||||
final isVerified = kycStatus.level1.verified;
|
||||
debugPrint('[PlantingLocationPage] 合同签署功能启用,实名认证状态: $isVerified');
|
||||
|
||||
// 返回是否需要去做实名认证(未完成实名认证则需要)
|
||||
return !isVerified;
|
||||
} catch (e) {
|
||||
debugPrint('[PlantingLocationPage] 检查实名认证状态失败: $e');
|
||||
// 检查失败时默认不阻止用户,让后端处理
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 提交认种请求
|
||||
Future<void> _submitPlanting() async {
|
||||
setState(() => _isSubmitting = true);
|
||||
|
|
@ -243,8 +276,22 @@ class _PlantingLocationPageState extends ConsumerState<PlantingLocationPage> {
|
|||
),
|
||||
);
|
||||
|
||||
// 5. 认种成功后,检查是否需要实名认证(仅在合同签署功能启用时)
|
||||
final needsKyc = await _checkKycRequirement();
|
||||
if (needsKyc && mounted) {
|
||||
// 显示实名认证提示弹窗
|
||||
final goToKyc = await KycRequiredDialog.show(context: context);
|
||||
if (goToKyc == true && mounted) {
|
||||
// 跳转到实名认证页面
|
||||
context.push(RoutePaths.kycEntry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 返回到个人中心
|
||||
context.go('/profile');
|
||||
if (mounted) {
|
||||
context.go('/profile');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('认种失败: $e');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,200 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 未实名认证提示弹窗
|
||||
/// 当用户未完成实名认证但尝试确认认种时显示
|
||||
class KycRequiredDialog extends StatelessWidget {
|
||||
const KycRequiredDialog({super.key});
|
||||
|
||||
/// 显示提示弹窗
|
||||
/// 返回 true 表示用户选择去实名认证,false 表示取消
|
||||
static Future<bool?> show({required BuildContext context}) {
|
||||
return showDialog<bool>(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
barrierColor: const Color(0x80000000),
|
||||
builder: (context) => const KycRequiredDialog(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
backgroundColor: Colors.transparent,
|
||||
insetPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
constraints: const BoxConstraints(maxWidth: 360),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Color(0x40000000),
|
||||
blurRadius: 50,
|
||||
offset: Offset(0, 25),
|
||||
spreadRadius: -12,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
// 主内容
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 32, 24, 24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// 图标
|
||||
_buildIcon(),
|
||||
const SizedBox(height: 16),
|
||||
// 标题
|
||||
_buildTitle(),
|
||||
const SizedBox(height: 12),
|
||||
// 说明文字
|
||||
_buildDescription(),
|
||||
const SizedBox(height: 24),
|
||||
// 按钮
|
||||
_buildButtons(context),
|
||||
],
|
||||
),
|
||||
),
|
||||
// 右上角关闭按钮
|
||||
Positioned(
|
||||
top: 8,
|
||||
right: 8,
|
||||
child: GestureDetector(
|
||||
onTap: () => Navigator.pop(context, false),
|
||||
child: Container(
|
||||
width: 32,
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0x0D000000),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.close,
|
||||
size: 18,
|
||||
color: Color(0xFF8B5A2B),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 构建图标
|
||||
Widget _buildIcon() {
|
||||
return Container(
|
||||
width: 64,
|
||||
height: 64,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFFFF7E6),
|
||||
borderRadius: BorderRadius.circular(32),
|
||||
),
|
||||
child: const Center(
|
||||
child: Icon(
|
||||
Icons.verified_user_outlined,
|
||||
color: Color(0xFFD4AF37),
|
||||
size: 32,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 构建标题
|
||||
Widget _buildTitle() {
|
||||
return const Text(
|
||||
'需要先完成实名认证',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontFamily: 'Inter',
|
||||
fontWeight: FontWeight.w700,
|
||||
height: 1.3,
|
||||
color: Color(0xFF5D4037),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
);
|
||||
}
|
||||
|
||||
/// 构建说明文字
|
||||
Widget _buildDescription() {
|
||||
return const Text(
|
||||
'为了保障您的权益,认种前需要完成实名认证。\n完成认证后即可继续认种。',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontFamily: 'Inter',
|
||||
height: 1.5,
|
||||
color: Color(0xFF745D43),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
);
|
||||
}
|
||||
|
||||
/// 构建按钮
|
||||
Widget _buildButtons(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
// 去实名认证按钮
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: GestureDetector(
|
||||
onTap: () => Navigator.pop(context, true),
|
||||
child: Container(
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFD4AF37),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'去实名认证',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Inter',
|
||||
fontWeight: FontWeight.w600,
|
||||
height: 1.5,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// 稍后再说按钮
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: GestureDetector(
|
||||
onTap: () => Navigator.pop(context, false),
|
||||
child: Container(
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: const Color(0xFFD4AF37),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'稍后再说',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Inter',
|
||||
fontWeight: FontWeight.w600,
|
||||
height: 1.5,
|
||||
color: Color(0xFFD4AF37),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue