fix: 添加遗漏的 registerByPhone 方法到 user-application.service.ts
修复构建错误:Property 'registerByPhone' does not exist on type 'UserApplicationService' 🤖 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
2897a0c74c
commit
b4dafc9e38
|
|
@ -43,6 +43,7 @@ import {
|
||||||
} from '@/domain/events';
|
} from '@/domain/events';
|
||||||
import {
|
import {
|
||||||
AutoCreateAccountCommand,
|
AutoCreateAccountCommand,
|
||||||
|
RegisterByPhoneCommand,
|
||||||
RecoverByMnemonicCommand,
|
RecoverByMnemonicCommand,
|
||||||
RecoverByPhoneCommand,
|
RecoverByPhoneCommand,
|
||||||
AutoLoginCommand,
|
AutoLoginCommand,
|
||||||
|
|
@ -206,6 +207,136 @@ export class UserApplicationService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机号注册 (验证码+密码一步到位)
|
||||||
|
*
|
||||||
|
* - 验证短信验证码
|
||||||
|
* - 创建账户并绑定手机号
|
||||||
|
* - 设置密码
|
||||||
|
* - 触发钱包生成
|
||||||
|
* - 返回 token
|
||||||
|
*/
|
||||||
|
async registerByPhone(
|
||||||
|
command: RegisterByPhoneCommand,
|
||||||
|
): Promise<AutoCreateAccountResult> {
|
||||||
|
const phoneNumber = PhoneNumber.create(command.phoneNumber);
|
||||||
|
|
||||||
|
// 1. 验证短信验证码
|
||||||
|
const cachedCode = await this.redisService.get(
|
||||||
|
`sms:register:${phoneNumber.value}`,
|
||||||
|
);
|
||||||
|
if (cachedCode !== command.smsCode) {
|
||||||
|
throw new ApplicationError('验证码错误或已过期');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 检查手机号是否已注册
|
||||||
|
const phoneValidation =
|
||||||
|
await this.validatorService.validatePhoneNumber(phoneNumber);
|
||||||
|
if (!phoneValidation.isValid) {
|
||||||
|
throw new ApplicationError(phoneValidation.errorMessage!);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 验证邀请码
|
||||||
|
let inviterSequence: AccountSequence | null = null;
|
||||||
|
if (command.inviterReferralCode) {
|
||||||
|
const referralCode = ReferralCode.create(command.inviterReferralCode);
|
||||||
|
const referralValidation =
|
||||||
|
await this.validatorService.validateReferralCode(referralCode);
|
||||||
|
if (!referralValidation.isValid) {
|
||||||
|
throw new ApplicationError(referralValidation.errorMessage!);
|
||||||
|
}
|
||||||
|
const inviter =
|
||||||
|
await this.userRepository.findByReferralCode(referralCode);
|
||||||
|
inviterSequence = inviter!.accountSequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 生成用户序列号
|
||||||
|
const accountSequence =
|
||||||
|
await this.sequenceGenerator.generateNextUserSequence();
|
||||||
|
|
||||||
|
// 5. 生成用户名和头像
|
||||||
|
const identity = generateIdentity(accountSequence.value);
|
||||||
|
|
||||||
|
// 6. 构建设备名称字符串
|
||||||
|
let deviceNameStr = '未命名设备';
|
||||||
|
if (command.deviceName) {
|
||||||
|
const parts: string[] = [];
|
||||||
|
if (command.deviceName.model) parts.push(command.deviceName.model);
|
||||||
|
if (command.deviceName.platform) parts.push(command.deviceName.platform);
|
||||||
|
if (command.deviceName.osVersion)
|
||||||
|
parts.push(command.deviceName.osVersion);
|
||||||
|
if (parts.length > 0) deviceNameStr = parts.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. 创建用户账户(带手机号)
|
||||||
|
const account = UserAccount.create({
|
||||||
|
accountSequence,
|
||||||
|
phoneNumber,
|
||||||
|
initialDeviceId: command.deviceId,
|
||||||
|
deviceName: deviceNameStr,
|
||||||
|
deviceInfo: command.deviceName,
|
||||||
|
inviterSequence,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 8. 设置随机用户名和头像
|
||||||
|
account.updateProfile({
|
||||||
|
nickname: identity.username,
|
||||||
|
avatarUrl: identity.avatarSvg,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 9. 保存账户
|
||||||
|
await this.userRepository.save(account);
|
||||||
|
|
||||||
|
// 10. 设置密码
|
||||||
|
const bcrypt = await import('bcrypt');
|
||||||
|
const passwordHash = await bcrypt.hash(command.password, 10);
|
||||||
|
await this.prisma.userAccount.update({
|
||||||
|
where: { userId: account.userId.value },
|
||||||
|
data: { passwordHash },
|
||||||
|
});
|
||||||
|
|
||||||
|
// 11. 删除验证码
|
||||||
|
await this.redisService.delete(`sms:register:${phoneNumber.value}`);
|
||||||
|
|
||||||
|
// 12. 生成 Token
|
||||||
|
const tokens = await this.tokenService.generateTokenPair({
|
||||||
|
userId: account.userId.toString(),
|
||||||
|
accountSequence: account.accountSequence.value,
|
||||||
|
deviceId: command.deviceId,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 13. 发布领域事件
|
||||||
|
await this.eventPublisher.publishAll(account.domainEvents);
|
||||||
|
account.clearDomainEvents();
|
||||||
|
|
||||||
|
// 14. 发布 MPC Keygen 请求事件 (触发后台生成钱包)
|
||||||
|
const sessionId = crypto.randomUUID();
|
||||||
|
await this.eventPublisher.publish(
|
||||||
|
new MpcKeygenRequestedEvent({
|
||||||
|
sessionId,
|
||||||
|
userId: account.userId.toString(),
|
||||||
|
accountSequence: account.accountSequence.value,
|
||||||
|
username: `user_${account.accountSequence.value}`,
|
||||||
|
threshold: 2,
|
||||||
|
totalParties: 3,
|
||||||
|
requireDelegate: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.logger.log(
|
||||||
|
`Account registered by phone: sequence=${accountSequence.value}, phone=${phoneNumber.value}, MPC keygen requested`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
userSerialNum: account.accountSequence.value,
|
||||||
|
referralCode: account.referralCode.value,
|
||||||
|
username: account.nickname,
|
||||||
|
avatarSvg: account.avatarUrl || identity.avatarSvg,
|
||||||
|
accessToken: tokens.accessToken,
|
||||||
|
refreshToken: tokens.refreshToken,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async recoverByMnemonic(
|
async recoverByMnemonic(
|
||||||
command: RecoverByMnemonicCommand,
|
command: RecoverByMnemonicCommand,
|
||||||
): Promise<RecoverAccountResult> {
|
): Promise<RecoverAccountResult> {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue