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:
hailin 2025-12-24 21:00:53 -08:00
parent 8b1db58318
commit 1d6cbf9335
3 changed files with 131 additions and 5 deletions

View File

@ -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": []

BIN
contract.docx Normal file

Binary file not shown.

View File

@ -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) {
context.push(RoutePaths.kycId);
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;