fix: 修复internal用户详情接口路由和KYC状态检查

问题1: /internal/users/:accountSequence/detail 返回404
原因: 路由顺序问题,通配路由在前拦截了请求
修复: 将 /detail 路由移到通配路由之前

问题2: planting-service 只接受 kycStatus='VERIFIED'
原因: identity-service 使用 REAL_NAME_VERIFIED 等状态
修复: 接受所有有效的KYC状态

同时:
- identity-service 返回 idCardNumber 用于合同签署
- planting-service 使用 idCardNumber

🤖 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 07:51:11 -08:00
parent b3014744ab
commit 1c3ddb0f9b
2 changed files with 37 additions and 33 deletions

View File

@ -40,6 +40,7 @@ interface UserDetailInfo {
inviterSequence?: string; // 推荐人序列号
kycStatus: string;
realName?: string; // 敏感信息
idCardNumber?: string; // 敏感信息 - 用于合同签署
}
/**
@ -86,33 +87,6 @@ export class InternalController {
}
}
@Public()
@Get('users/:accountSequence')
@ApiOperation({ summary: '获取单个用户信息(内部调用,按 accountSequence' })
@ApiResponse({ status: 200, description: '返回用户信息' })
async getUserBySequence(@Param('accountSequence') accountSequence: string): Promise<UserBasicInfo | null> {
this.logger.debug(`[getUserBySequence] 查询用户: ${accountSequence}`);
try {
const sequence = AccountSequence.create(accountSequence);
const user = await this.userRepository.findByAccountSequence(sequence);
if (!user) {
return null;
}
return {
userId: user.userId.value.toString(),
accountSequence: user.accountSequence.value,
nickname: user.nickname,
avatarUrl: user.avatarUrl || undefined,
};
} catch (error) {
this.logger.error(`[getUserBySequence] 查询失败:`, error);
return null;
}
}
@Public()
@Get('users/:accountSequence/detail')
@ApiOperation({ summary: '获取用户详情(内部调用,包含敏感信息)' })
@ -141,10 +115,38 @@ export class InternalController {
inviterSequence: user.inviterSequence || undefined,
kycStatus: user.kycStatus,
realName: user.realName || undefined,
idCardNumber: user.idCardNumber || undefined,
};
} catch (error) {
this.logger.error(`[getUserDetailBySequence] 查询失败:`, error);
return null;
}
}
@Public()
@Get('users/:accountSequence')
@ApiOperation({ summary: '获取单个用户信息(内部调用,按 accountSequence' })
@ApiResponse({ status: 200, description: '返回用户信息' })
async getUserBySequence(@Param('accountSequence') accountSequence: string): Promise<UserBasicInfo | null> {
this.logger.debug(`[getUserBySequence] 查询用户: ${accountSequence}`);
try {
const sequence = AccountSequence.create(accountSequence);
const user = await this.userRepository.findByAccountSequence(sequence);
if (!user) {
return null;
}
return {
userId: user.userId.value.toString(),
accountSequence: user.accountSequence.value,
nickname: user.nickname,
avatarUrl: user.avatarUrl || undefined,
};
} catch (error) {
this.logger.error(`[getUserBySequence] 查询失败:`, error);
return null;
}
}
}

View File

@ -17,6 +17,7 @@ export interface UserDetailInfo {
inviterSequence?: string;
kycStatus: string;
realName?: string;
idCardNumber?: string;
}
/**
@ -25,7 +26,7 @@ export interface UserDetailInfo {
export interface UserKycInfo {
phoneNumber?: string;
realName?: string;
idCardNumber?: string; // 身份证号目前 identity-service 不返回,需要单独处理
idCardNumber?: string;
}
/**
@ -178,10 +179,12 @@ export class IdentityServiceClient {
return null;
}
// 检查 KYC 状态 - 未认证不允许签署合同
if (userDetail.kycStatus !== 'VERIFIED') {
// 检查 KYC 状态 - 实名认证通过即可签署合同
// 接受的状态: REAL_NAME_VERIFIED, FACE_VERIFIED, KYC_VERIFIED, COMPLETED, VERIFIED
const validKycStatuses = ['REAL_NAME_VERIFIED', 'FACE_VERIFIED', 'KYC_VERIFIED', 'COMPLETED', 'VERIFIED'];
if (!validKycStatuses.includes(userDetail.kycStatus)) {
this.logger.warn(
`User ${accountSequence} KYC status is ${userDetail.kycStatus}, not VERIFIED. Cannot create contract.`,
`User ${accountSequence} KYC status is ${userDetail.kycStatus}, not in ${validKycStatuses.join('/')}. Cannot create contract.`,
);
return null;
}
@ -189,8 +192,7 @@ export class IdentityServiceClient {
return {
phoneNumber: userDetail.phoneNumber,
realName: userDetail.realName,
// 身份证号暂时不从 identity-service 获取(涉及敏感数据处理)
idCardNumber: undefined,
idCardNumber: userDetail.idCardNumber,
};
}
}