feat(users): 添加身体围度测量功能

新增用户身体围度的完整功能模块,包括数据库迁移、模型定义、API接口和历史记录追踪。
支持胸围、腰围、上臀围、臂围、大腿围、小腿围六项身体围度指标的管理。

- 添加数据库迁移脚本,扩展用户档案表字段
- 创建围度历史记录表用于数据追踪
- 实现围度数据的更新和历史查询API
- 添加数据验证和错误处理机制
This commit is contained in:
richarjiang
2025-09-22 09:49:42 +08:00
parent dc06dfbebd
commit e2fcb1c428
7 changed files with 398 additions and 0 deletions

View File

@@ -31,6 +31,7 @@ import { RestorePurchaseDto, RestorePurchaseResponseDto, RestoredPurchaseInfo, A
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';
import { UserBodyMeasurementHistory, BodyMeasurementType, MeasurementUpdateSource } from './models/user-body-measurement-history.model';
import { ActivityLogsService } from '../activity-logs/activity-logs.service';
import { UserActivityService } from './services/user-activity.service';
@@ -63,6 +64,8 @@ export class UsersService {
private userProfileModel: typeof UserProfile,
@InjectModel(UserWeightHistory)
private userWeightHistoryModel: typeof UserWeightHistory,
@InjectModel(UserBodyMeasurementHistory)
private userBodyMeasurementHistoryModel: typeof UserBodyMeasurementHistory,
@InjectConnection()
private sequelize: Sequelize,
@@ -114,6 +117,12 @@ export class UsersService {
height: profile?.height,
activityLevel: profile?.activityLevel,
dailyWaterGoal: profile?.dailyWaterGoal,
chestCircumference: profile?.chestCircumference,
waistCircumference: profile?.waistCircumference,
upperHipCircumference: profile?.upperHipCircumference,
armCircumference: profile?.armCircumference,
thighCircumference: profile?.thighCircumference,
calfCircumference: profile?.calfCircumference,
}
this.logger.log(`getProfile returnData: ${JSON.stringify(returnData, null, 2)}`);
@@ -2278,4 +2287,103 @@ export class UsersService {
};
}
}
/**
* 更新用户围度信息
*/
async updateBodyMeasurements(userId: string, measurements: any): Promise<{ code: any; message: string }> {
const transaction = await this.sequelize.transaction();
try {
// 获取或创建用户档案
const [profile] = await this.userProfileModel.findOrCreate({
where: { userId },
defaults: { userId },
transaction,
});
const updateFields: any = {};
const historyRecords: any[] = [];
// 映射字段名到围度类型
const fieldMappings = {
chestCircumference: BodyMeasurementType.ChestCircumference,
waistCircumference: BodyMeasurementType.WaistCircumference,
upperHipCircumference: BodyMeasurementType.UpperHipCircumference,
armCircumference: BodyMeasurementType.ArmCircumference,
thighCircumference: BodyMeasurementType.ThighCircumference,
calfCircumference: BodyMeasurementType.CalfCircumference,
};
// 处理每个传入的围度字段
for (const [fieldName, measurementType] of Object.entries(fieldMappings)) {
if (measurements[fieldName] !== undefined) {
const value = measurements[fieldName];
updateFields[fieldName] = value;
// 准备历史记录
historyRecords.push({
userId,
measurementType,
value,
source: MeasurementUpdateSource.Manual,
});
}
}
// 更新用户档案
if (Object.keys(updateFields).length > 0) {
await profile.update(updateFields, { transaction });
// 批量创建历史记录
if (historyRecords.length > 0) {
await this.userBodyMeasurementHistoryModel.bulkCreate(historyRecords, { transaction });
}
}
await transaction.commit();
this.logger.log(`用户 ${userId} 围度更新成功: ${JSON.stringify(updateFields)}`);
return {
code: ResponseCode.SUCCESS,
message: 'success',
};
} catch (error) {
await transaction.rollback();
this.logger.error(`更新用户围度失败: ${error instanceof Error ? error.message : '未知错误'}`);
throw new BadRequestException(`更新围度信息失败: ${error instanceof Error ? error.message : '未知错误'}`);
}
}
/**
* 获取用户围度历史记录
*/
async getBodyMeasurementHistory(userId: string, measurementType?: BodyMeasurementType): Promise<any> {
try {
const whereCondition: any = { userId };
if (measurementType) {
whereCondition.measurementType = measurementType;
}
const history = await this.userBodyMeasurementHistoryModel.findAll({
where: whereCondition,
order: [['createdAt', 'DESC']],
limit: 100, // 限制返回最近100条记录
});
return {
code: ResponseCode.SUCCESS,
message: 'success',
data: history,
};
} catch (error) {
this.logger.error(`获取围度历史记录失败: ${error instanceof Error ? error.message : '未知错误'}`);
return {
code: ResponseCode.ERROR,
message: `获取围度历史记录失败: ${error instanceof Error ? error.message : '未知错误'}`,
data: [],
};
}
}
}