新增AI教练模块,包括控制器、服务、模型及数据传输对象,更新应用模块以引入新模块,同时在打卡模块中添加按时间范围返回每日打卡状态的功能

This commit is contained in:
richarjiang
2025-08-14 09:12:44 +08:00
parent 866143d3ad
commit d1a6e3d42e
15 changed files with 556 additions and 5 deletions

View File

@@ -25,6 +25,7 @@ import { DeleteAccountDto, DeleteAccountResponseDto } from './dto/delete-account
import { GuestLoginDto, GuestLoginResponseDto, RefreshGuestTokenDto, RefreshGuestTokenResponseDto } from './dto/guest-login.dto';
import { AppStoreServerNotificationDto, ProcessNotificationResponseDto, NotificationType } from './dto/app-store-notification.dto';
import { RevenueCatEvent } from './models/revenue-cat-event.model';
import { UserProfile } from './models/user-profile.model';
import { RevenueCatWebhookDto, RevenueCatEventType } from './dto/revenue-cat-webhook.dto';
import { RestorePurchaseDto, RestorePurchaseResponseDto, RestoredPurchaseInfo, ActiveEntitlement, NonSubscriptionTransaction } from './dto/restore-purchase.dto';
import { PurchaseRestoreLog, RestoreStatus, RestoreSource } from './models/purchase-restore-log.model';
@@ -49,6 +50,8 @@ export class UsersService {
private applePurchaseService: ApplePurchaseService,
@InjectModel(BlockedTransaction)
private blockedTransactionModel: typeof BlockedTransaction,
@InjectModel(UserProfile)
private userProfileModel: typeof UserProfile,
@InjectConnection()
private sequelize: Sequelize,
) { }
@@ -77,10 +80,18 @@ export class UsersService {
};
}
const profile = await this.userProfileModel.findByPk(existingUser.id);
const returnData = {
...existingUser.toJSON(),
maxUsageCount: DEFAULT_FREE_USAGE_COUNT,
isVip: existingUser.isVip,
profile: profile ? {
dailyStepsGoal: profile.dailyStepsGoal,
dailyCaloriesGoal: profile.dailyCaloriesGoal,
pilatesPurposes: profile.pilatesPurposes,
weight: profile.weight,
height: profile.height,
} : undefined,
}
this.logger.log(`getProfile returnData: ${JSON.stringify(returnData, null, 2)}`);
@@ -107,7 +118,7 @@ export class UsersService {
// 更新用户昵称、头像
async updateUser(updateUserDto: UpdateUserDto): Promise<UpdateUserResponseDto> {
const { userId, name, avatar, gender, birthDate } = updateUserDto;
const { userId, name, avatar, gender, birthDate, dailyStepsGoal, dailyCaloriesGoal, pilatesPurposes, weight, height } = updateUserDto;
this.logger.log(`updateUser: ${JSON.stringify(updateUserDto, null, 2)}`);
@@ -136,7 +147,19 @@ export class UsersService {
await user.save();
// 更新或创建扩展信息
if (dailyStepsGoal !== undefined || dailyCaloriesGoal !== undefined || pilatesPurposes !== undefined || weight !== undefined || height !== undefined) {
const [profile] = await this.userProfileModel.findOrCreate({
where: { userId },
defaults: { userId },
});
if (dailyStepsGoal !== undefined) profile.dailyStepsGoal = dailyStepsGoal as any;
if (dailyCaloriesGoal !== undefined) profile.dailyCaloriesGoal = dailyCaloriesGoal as any;
if (pilatesPurposes !== undefined) profile.pilatesPurposes = pilatesPurposes as any;
if (weight !== undefined) profile.weight = weight as any;
if (height !== undefined) profile.height = height as any;
await profile.save();
}
return {
code: ResponseCode.SUCCESS,
@@ -192,6 +215,9 @@ export class UsersService {
isNewUser = true;
this.logger.log(`创建新的Apple用户: ${userId}`);
// 创建默认扩展记录
await this.userProfileModel.findOrCreate({ where: { userId }, defaults: { userId } });
} else {
// 更新现有用户的登录时间
user.lastLogin = new Date();
@@ -204,11 +230,19 @@ export class UsersService {
const refreshToken = this.appleAuthService.generateRefreshToken(userId);
// 构造用户数据
const profileForLogin = await this.userProfileModel.findByPk(user.id);
const userData = {
...user.toJSON(),
isNew: isNewUser,
isVip: user.isVip,
maxUsageCount: DEFAULT_FREE_USAGE_COUNT,
profile: profileForLogin ? {
dailyStepsGoal: profileForLogin.dailyStepsGoal,
dailyCaloriesGoal: profileForLogin.dailyCaloriesGoal,
pilatesPurposes: profileForLogin.pilatesPurposes,
weight: profileForLogin.weight,
height: profileForLogin.height,
} : undefined,
};
return {
@@ -295,6 +329,12 @@ export class UsersService {
transaction,
});
// 2. 删除用户扩展信息
await this.userProfileModel.destroy({
where: { userId },
transaction,
});
// 最后删除用户本身
await this.userModel.destroy({
where: { id: userId },
@@ -364,6 +404,8 @@ export class UsersService {
isNewUser = true;
this.logger.log(`创建新的游客用户: ${guestUserId}`);
await this.userProfileModel.findOrCreate({ where: { userId: guestUserId }, defaults: { userId: guestUserId } });
} else {
// 更新现有游客用户的登录时间和设备信息
user.lastLogin = new Date();
@@ -378,12 +420,20 @@ export class UsersService {
const refreshToken = this.appleAuthService.generateRefreshToken(guestUserId);
// 构造用户数据
const profileForGuest = await this.userProfileModel.findByPk(user.id);
const userData = {
...user.toJSON(),
isNew: isNewUser,
isVip: user.membershipExpiration ? dayjs(user.membershipExpiration).isAfter(dayjs()) : false,
isGuest: true,
maxUsageCount: DEFAULT_FREE_USAGE_COUNT,
profile: profileForGuest ? {
dailyStepsGoal: profileForGuest.dailyStepsGoal,
dailyCaloriesGoal: profileForGuest.dailyCaloriesGoal,
pilatesPurposes: profileForGuest.pilatesPurposes,
weight: profileForGuest.weight,
height: profileForGuest.height,
} : undefined,
};
return {