From b4dafc9e38784d1e14aea465403c81f1d53bd099 Mon Sep 17 00:00:00 2001 From: hailin Date: Sun, 21 Dec 2025 20:22:44 -0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=B7=BB=E5=8A=A0=E9=81=97=E6=BC=8F?= =?UTF-8?q?=E7=9A=84=20registerByPhone=20=E6=96=B9=E6=B3=95=E5=88=B0=20use?= =?UTF-8?q?r-application.service.ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复构建错误:Property 'registerByPhone' does not exist on type 'UserApplicationService' 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../services/user-application.service.ts | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/backend/services/identity-service/src/application/services/user-application.service.ts b/backend/services/identity-service/src/application/services/user-application.service.ts index 207d8c8f..c1bb756f 100644 --- a/backend/services/identity-service/src/application/services/user-application.service.ts +++ b/backend/services/identity-service/src/application/services/user-application.service.ts @@ -43,6 +43,7 @@ import { } from '@/domain/events'; import { AutoCreateAccountCommand, + RegisterByPhoneCommand, RecoverByMnemonicCommand, RecoverByPhoneCommand, AutoLoginCommand, @@ -206,6 +207,136 @@ export class UserApplicationService { }; } + /** + * 手机号注册 (验证码+密码一步到位) + * + * - 验证短信验证码 + * - 创建账户并绑定手机号 + * - 设置密码 + * - 触发钱包生成 + * - 返回 token + */ + async registerByPhone( + command: RegisterByPhoneCommand, + ): Promise { + 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( command: RecoverByMnemonicCommand, ): Promise {