feat(kyc): 实名认证前检查手机号验证状态
- 点击实名认证时检查手机号是否已验证 - 未验证时显示提示弹窗,引导用户先验证手机号 - 实名认证卡片显示"请先验证手机号"提示 🤖 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
8b1db58318
commit
1d6cbf9335
|
|
@ -353,7 +353,55 @@
|
|||
"Bash(git -C \"c:/Users/dong/Desktop/rwadurian\" add backend/services/identity-service/src/api/controllers/internal.controller.ts)",
|
||||
"Bash(git -C \"c:/Users/dong/Desktop/rwadurian\" commit -m \"$\\(cat <<''EOF''\nfix\\(identity\\): 使用Prisma直接查询用户详情\n\ngetUserDetailBySequence 方法改用 Prisma 直接查询数据库,\n以获取 email 和 realName 等领域模型中未暴露的字段。\n\n之前的实现通过领域模型 UserAccount 访问这些字段会导致编译错误,\n因为领域模型没有直接暴露这些属性。\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
|
||||
"Bash(git -C \"c:/Users/dong/Desktop/rwadurian\" add backend/api-gateway/kong.yml frontend/mobile-app/lib/core/services/notification_service.dart)",
|
||||
"Bash(git -C \"c:/Users/dong/Desktop/rwadurian\" commit -m \"$\\(cat <<''EOF''\nfix\\(notification\\): 修复通知中心API路径\n\n问题: 前端调用 /admin-service/mobile/notifications 路径不存在于Kong网关\n\n修复:\n1. Kong网关添加 /api/v1/mobile/notifications 路由到 admin-service\n2. 前端 NotificationService 修正 API 路径:\n - /admin-service/mobile/notifications -> /mobile/notifications\n - /admin-service/mobile/notifications/unread-count -> /mobile/notifications/unread-count\n - /admin-service/mobile/notifications/mark-read -> /mobile/notifications/mark-read\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")"
|
||||
"Bash(git -C \"c:/Users/dong/Desktop/rwadurian\" commit -m \"$\\(cat <<''EOF''\nfix\\(notification\\): 修复通知中心API路径\n\n问题: 前端调用 /admin-service/mobile/notifications 路径不存在于Kong网关\n\n修复:\n1. Kong网关添加 /api/v1/mobile/notifications 路由到 admin-service\n2. 前端 NotificationService 修正 API 路径:\n - /admin-service/mobile/notifications -> /mobile/notifications\n - /admin-service/mobile/notifications/unread-count -> /mobile/notifications/unread-count\n - /admin-service/mobile/notifications/mark-read -> /mobile/notifications/mark-read\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
|
||||
"Bash(set DATABASE_URL=postgresql://postgres:postgres@localhost:5432/rwadurian_planting?schema=public:*)",
|
||||
"Bash($env:DATABASE_URL=\"postgresql://postgres:postgres@localhost:5432/rwadurian_planting?schema=public\")",
|
||||
"Bash(python -c:*)",
|
||||
"Bash(pip install:*)",
|
||||
"Bash(backend/services/planting-service/package.json )",
|
||||
"Bash(backend/services/planting-service/prisma/schema.prisma )",
|
||||
"Bash(backend/services/planting-service/prisma/migrations/20241224000000_add_contract_signing/ )",
|
||||
"Bash(backend/services/planting-service/prisma/seed.ts )",
|
||||
"Bash(backend/services/planting-service/src/api/api.module.ts )",
|
||||
"Bash(backend/services/planting-service/src/api/controllers/index.ts )",
|
||||
"Bash(backend/services/planting-service/src/api/controllers/contract-signing.controller.ts )",
|
||||
"Bash(backend/services/planting-service/src/application/application.module.ts )",
|
||||
"Bash(backend/services/planting-service/src/application/services/index.ts )",
|
||||
"Bash(backend/services/planting-service/src/application/services/planting-application.service.ts )",
|
||||
"Bash(backend/services/planting-service/src/application/services/contract-signing.service.ts )",
|
||||
"Bash(backend/services/planting-service/src/application/jobs/ )",
|
||||
"Bash(backend/services/planting-service/src/domain/aggregates/index.ts )",
|
||||
"Bash(backend/services/planting-service/src/domain/aggregates/contract-signing-task.aggregate.ts )",
|
||||
"Bash(backend/services/planting-service/src/domain/aggregates/contract-template.aggregate.ts )",
|
||||
"Bash(backend/services/planting-service/src/domain/repositories/index.ts )",
|
||||
"Bash(backend/services/planting-service/src/domain/repositories/contract-signing-task.repository.interface.ts )",
|
||||
"Bash(backend/services/planting-service/src/domain/repositories/contract-template.repository.interface.ts )",
|
||||
"Bash(backend/services/planting-service/src/domain/value-objects/index.ts )",
|
||||
"Bash(backend/services/planting-service/src/domain/value-objects/contract-signing-status.enum.ts )",
|
||||
"Bash(backend/services/planting-service/src/infrastructure/infrastructure.module.ts )",
|
||||
"Bash(backend/services/planting-service/src/infrastructure/kafka/event-publisher.service.ts )",
|
||||
"Bash(backend/services/planting-service/src/infrastructure/kafka/index.ts )",
|
||||
"Bash(backend/services/planting-service/src/infrastructure/kafka/contract-signing-event.consumer.ts )",
|
||||
"Bash(backend/services/planting-service/src/infrastructure/persistence/repositories/index.ts )",
|
||||
"Bash(backend/services/planting-service/src/infrastructure/persistence/repositories/contract-signing-task.repository.impl.ts )",
|
||||
"Bash(backend/services/planting-service/src/infrastructure/persistence/repositories/contract-template.repository.impl.ts )",
|
||||
"Bash(backend/services/planting-service/src/main.ts )",
|
||||
"Bash(backend/services/referral-service/src/application/event-handlers/index.ts )",
|
||||
"Bash(backend/services/referral-service/src/application/event-handlers/planting-created.handler.ts )",
|
||||
"Bash(backend/services/referral-service/src/application/event-handlers/contract-signing.handler.ts )",
|
||||
"Bash(backend/services/referral-service/src/infrastructure/external/index.ts )",
|
||||
"Bash(backend/services/referral-service/src/infrastructure/external/wallet-service.client.ts )",
|
||||
"Bash(backend/services/referral-service/src/modules/application.module.ts )",
|
||||
"Bash(backend/services/referral-service/src/modules/infrastructure.module.ts )",
|
||||
"Bash(backend/services/reward-service/src/application/services/reward-application.service.ts )",
|
||||
"Bash(backend/services/reward-service/src/domain/services/reward-calculation.service.ts )",
|
||||
"Bash(backend/services/reward-service/src/infrastructure/external/wallet-service/wallet-service.client.ts )",
|
||||
"Bash(backend/services/reward-service/src/infrastructure/kafka/event-consumer.controller.ts)",
|
||||
"Bash(frontend/mobile-app/lib/core/di/injection_container.dart )",
|
||||
"Bash(frontend/mobile-app/lib/core/services/contract_check_service.dart )",
|
||||
"Bash(frontend/mobile-app/lib/core/services/contract_signing_service.dart )",
|
||||
"Bash(frontend/mobile-app/lib/features/contract_signing/ )",
|
||||
"Bash(frontend/mobile-app/lib/features/home/presentation/pages/home_shell_page.dart )"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -226,27 +226,105 @@ class KycEntryPage extends ConsumerWidget {
|
|||
Widget _buildLevel1Card(BuildContext context, WidgetRef ref, KycStatusResponse status) {
|
||||
final level1 = status.level1;
|
||||
final isCompleted = level1.verified;
|
||||
// 必须先验证手机号才能进行实名认证
|
||||
final needsPhoneVerification = !status.phoneVerified;
|
||||
final isEnabled = !isCompleted;
|
||||
|
||||
String description;
|
||||
if (isCompleted) {
|
||||
description = '${level1.realName ?? ''} (${_maskIdCard(level1.idCardNumber)})';
|
||||
} else if (needsPhoneVerification) {
|
||||
description = '请先验证手机号';
|
||||
} else {
|
||||
description = '验证姓名和身份证号';
|
||||
}
|
||||
|
||||
return _buildStepCard(
|
||||
context: context,
|
||||
ref: ref,
|
||||
stepNumber: 1,
|
||||
title: '实名认证',
|
||||
subtitle: '二要素验证',
|
||||
description: isCompleted
|
||||
? '${level1.realName ?? ''} (${_maskIdCard(level1.idCardNumber)})'
|
||||
: '验证姓名和身份证号',
|
||||
description: description,
|
||||
isCompleted: isCompleted,
|
||||
isEnabled: isEnabled,
|
||||
isLocked: needsPhoneVerification && !isCompleted,
|
||||
onTap: () {
|
||||
if (isEnabled) {
|
||||
if (needsPhoneVerification) {
|
||||
// 手机号未验证,跳转到验证手机号页面
|
||||
_showPhoneVerificationRequiredDialog(context);
|
||||
} else {
|
||||
context.push(RoutePaths.kycId);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 显示需要先验证手机号的弹窗
|
||||
void _showPhoneVerificationRequiredDialog(BuildContext context) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16.r),
|
||||
),
|
||||
title: Row(
|
||||
children: [
|
||||
Icon(Icons.phone_android, color: const Color(0xFF2E7D32), size: 24.sp),
|
||||
SizedBox(width: 8.w),
|
||||
Text(
|
||||
'请先验证手机号',
|
||||
style: TextStyle(
|
||||
fontSize: 18.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
content: Text(
|
||||
'进行实名认证前,需要先验证您的手机号码。',
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp,
|
||||
color: const Color(0xFF666666),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(),
|
||||
child: Text(
|
||||
'稍后验证',
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp,
|
||||
color: const Color(0xFF999999),
|
||||
),
|
||||
),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(ctx).pop();
|
||||
context.push(RoutePaths.changePhone);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF2E7D32),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8.r),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
'去验证',
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 层级2: 实人认证卡片
|
||||
Widget _buildLevel2Card(BuildContext context, WidgetRef ref, KycStatusResponse status) {
|
||||
final level2 = status.level2;
|
||||
|
|
|
|||
Loading…
Reference in New Issue