新增训练计划模块,包括控制器、服务、模型及数据传输对象,更新应用模块以引入新模块,同时在AI教练模块中添加体态评估功能,支持体重识别与更新,优化用户体重历史记录管理。
This commit is contained in:
@@ -30,6 +30,7 @@ import { RevenueCatWebhookDto, RevenueCatEventType } from './dto/revenue-cat-web
|
||||
import { RestorePurchaseDto, RestorePurchaseResponseDto, RestoredPurchaseInfo, ActiveEntitlement, NonSubscriptionTransaction } from './dto/restore-purchase.dto';
|
||||
import { PurchaseRestoreLog, RestoreStatus, RestoreSource } from './models/purchase-restore-log.model';
|
||||
import { BlockedTransaction, BlockReason } from './models/blocked-transaction.model';
|
||||
import { UserWeightHistory, WeightUpdateSource } from './models/user-weight-history.model';
|
||||
|
||||
const DEFAULT_FREE_USAGE_COUNT = 10;
|
||||
|
||||
@@ -52,6 +53,8 @@ export class UsersService {
|
||||
private blockedTransactionModel: typeof BlockedTransaction,
|
||||
@InjectModel(UserProfile)
|
||||
private userProfileModel: typeof UserProfile,
|
||||
@InjectModel(UserWeightHistory)
|
||||
private userWeightHistoryModel: typeof UserWeightHistory,
|
||||
@InjectConnection()
|
||||
private sequelize: Sequelize,
|
||||
) { }
|
||||
@@ -157,7 +160,14 @@ export class UsersService {
|
||||
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 (weight !== undefined) {
|
||||
profile.weight = weight as any;
|
||||
try {
|
||||
await this.userWeightHistoryModel.create({ userId, weight, source: WeightUpdateSource.Manual });
|
||||
} catch (e) {
|
||||
this.logger.error(`记录体重历史失败: ${e instanceof Error ? e.message : String(e)}`);
|
||||
}
|
||||
}
|
||||
if (height !== undefined) profile.height = height as any;
|
||||
await profile.save();
|
||||
}
|
||||
@@ -172,6 +182,35 @@ export class UsersService {
|
||||
};
|
||||
}
|
||||
|
||||
async addWeightByVision(userId: string, weight: number): Promise<void> {
|
||||
const t = await this.sequelize.transaction();
|
||||
try {
|
||||
const [profile] = await this.userProfileModel.findOrCreate({ where: { userId }, defaults: { userId }, transaction: t });
|
||||
profile.weight = weight as any;
|
||||
await profile.save({ transaction: t });
|
||||
await this.userWeightHistoryModel.create({ userId, weight, source: WeightUpdateSource.Vision }, { transaction: t });
|
||||
await t.commit();
|
||||
} catch (e) {
|
||||
await t.rollback();
|
||||
this.logger.error(`addWeightByVision error: ${e instanceof Error ? e.message : String(e)}`);
|
||||
}
|
||||
}
|
||||
|
||||
async getWeightHistory(userId: string, params: { start?: Date; end?: Date; limit?: number } = {}) {
|
||||
const where: any = { userId };
|
||||
if (params.start || params.end) {
|
||||
where.createdAt = {} as any;
|
||||
if (params.start) where.createdAt.$gte = params.start as any;
|
||||
if (params.end) where.createdAt.$lte = params.end as any;
|
||||
}
|
||||
const limit = params.limit && params.limit > 0 ? Math.min(1000, params.limit) : 200;
|
||||
const rows = await this.userWeightHistoryModel.findAll({
|
||||
where,
|
||||
order: [['created_at', 'DESC']],
|
||||
limit,
|
||||
});
|
||||
return rows.map(r => ({ weight: r.weight, source: r.source, createdAt: r.createdAt }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Apple 登录
|
||||
|
||||
Reference in New Issue
Block a user