feat:新增活动日志模块,包括控制器、服务、模型及数据传输对象,更新应用模块以引入新模块,并在打卡和训练计划模块中集成活动日志记录功能。
This commit is contained in:
@@ -31,6 +31,8 @@ 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 { ActivityLogsService } from '../activity-logs/activity-logs.service';
|
||||
import { ActivityActionType, ActivityEntityType } from '../activity-logs/models/activity-log.model';
|
||||
|
||||
const DEFAULT_FREE_USAGE_COUNT = 10;
|
||||
|
||||
@@ -57,6 +59,7 @@ export class UsersService {
|
||||
private userWeightHistoryModel: typeof UserWeightHistory,
|
||||
@InjectConnection()
|
||||
private sequelize: Sequelize,
|
||||
private readonly activityLogsService: ActivityLogsService,
|
||||
) { }
|
||||
|
||||
async getProfile(user: AccessTokenPayload): Promise<UserResponseDto> {
|
||||
@@ -134,17 +137,23 @@ export class UsersService {
|
||||
throw new NotFoundException(`ID为${userId}的用户不存在`);
|
||||
}
|
||||
|
||||
const profileChanges: Record<string, any> = {};
|
||||
const userChanges: Record<string, any> = {};
|
||||
if (name) {
|
||||
user.name = name;
|
||||
userChanges.name = name;
|
||||
}
|
||||
if (avatar) {
|
||||
user.avatar = avatar;
|
||||
userChanges.avatar = avatar;
|
||||
}
|
||||
if (gender) {
|
||||
user.gender = gender;
|
||||
userChanges.gender = gender;
|
||||
}
|
||||
if (birthDate) {
|
||||
user.birthDate = dayjs(birthDate * 1000).startOf('day').toDate();
|
||||
userChanges.birthDate = birthDate;
|
||||
}
|
||||
|
||||
this.logger.log(`updateUser user: ${JSON.stringify(user, null, 2)}`);
|
||||
@@ -157,9 +166,9 @@ export class UsersService {
|
||||
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 (dailyStepsGoal !== undefined) { profile.dailyStepsGoal = dailyStepsGoal as any; profileChanges.dailyStepsGoal = dailyStepsGoal; }
|
||||
if (dailyCaloriesGoal !== undefined) { profile.dailyCaloriesGoal = dailyCaloriesGoal as any; profileChanges.dailyCaloriesGoal = dailyCaloriesGoal; }
|
||||
if (pilatesPurposes !== undefined) { profile.pilatesPurposes = pilatesPurposes as any; profileChanges.pilatesPurposes = pilatesPurposes; }
|
||||
if (weight !== undefined) {
|
||||
profile.weight = weight as any;
|
||||
try {
|
||||
@@ -167,11 +176,32 @@ export class UsersService {
|
||||
} catch (e) {
|
||||
this.logger.error(`记录体重历史失败: ${e instanceof Error ? e.message : String(e)}`);
|
||||
}
|
||||
profileChanges.weight = weight;
|
||||
}
|
||||
if (height !== undefined) profile.height = height as any;
|
||||
if (height !== undefined) { profile.height = height as any; profileChanges.height = height; }
|
||||
await profile.save();
|
||||
}
|
||||
|
||||
// 记录用户基础与扩展信息更新
|
||||
if (Object.keys(userChanges).length > 0) {
|
||||
await this.activityLogsService.record({
|
||||
userId,
|
||||
entityType: ActivityEntityType.USER,
|
||||
action: ActivityActionType.UPDATE,
|
||||
entityId: userId,
|
||||
changes: userChanges,
|
||||
});
|
||||
}
|
||||
if (Object.keys(profileChanges).length > 0) {
|
||||
await this.activityLogsService.record({
|
||||
userId,
|
||||
entityType: ActivityEntityType.USER_PROFILE,
|
||||
action: ActivityActionType.UPDATE,
|
||||
entityId: userId,
|
||||
changes: profileChanges,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
code: ResponseCode.SUCCESS,
|
||||
message: 'success',
|
||||
@@ -190,6 +220,14 @@ export class UsersService {
|
||||
await profile.save({ transaction: t });
|
||||
await this.userWeightHistoryModel.create({ userId, weight, source: WeightUpdateSource.Vision }, { transaction: t });
|
||||
await t.commit();
|
||||
await this.activityLogsService.record({
|
||||
userId,
|
||||
entityType: ActivityEntityType.USER_PROFILE,
|
||||
action: ActivityActionType.UPDATE,
|
||||
entityId: userId,
|
||||
changes: { weight },
|
||||
metadata: { source: 'vision' },
|
||||
});
|
||||
} catch (e) {
|
||||
await t.rollback();
|
||||
this.logger.error(`addWeightByVision error: ${e instanceof Error ? e.message : String(e)}`);
|
||||
@@ -285,6 +323,16 @@ export class UsersService {
|
||||
} : undefined,
|
||||
};
|
||||
|
||||
// 登录行为也可视为活动(可选,记录创建或登录行为)
|
||||
await this.activityLogsService.record({
|
||||
userId,
|
||||
entityType: ActivityEntityType.USER,
|
||||
action: ActivityActionType.UPDATE,
|
||||
entityId: userId,
|
||||
changes: { lastLogin: user.lastLogin },
|
||||
metadata: { source: 'appleLogin' },
|
||||
});
|
||||
|
||||
return {
|
||||
code: ResponseCode.SUCCESS,
|
||||
message: 'success',
|
||||
@@ -387,6 +435,16 @@ export class UsersService {
|
||||
|
||||
this.logger.log(`用户账号删除成功: ${userId}`);
|
||||
|
||||
// 记录删除账户行为
|
||||
await this.activityLogsService.record({
|
||||
userId,
|
||||
entityType: ActivityEntityType.USER,
|
||||
action: ActivityActionType.DELETE,
|
||||
entityId: userId,
|
||||
changes: null,
|
||||
metadata: { reason: 'deleteAccount' },
|
||||
});
|
||||
|
||||
return {
|
||||
code: ResponseCode.SUCCESS,
|
||||
message: '账号删除成功',
|
||||
@@ -476,6 +534,15 @@ export class UsersService {
|
||||
} : undefined,
|
||||
};
|
||||
|
||||
await this.activityLogsService.record({
|
||||
userId: guestUserId,
|
||||
entityType: ActivityEntityType.USER,
|
||||
action: ActivityActionType.UPDATE,
|
||||
entityId: guestUserId,
|
||||
changes: { lastLogin: user.lastLogin },
|
||||
metadata: { source: 'guestLogin' },
|
||||
});
|
||||
|
||||
return {
|
||||
code: ResponseCode.SUCCESS,
|
||||
message: 'success',
|
||||
|
||||
Reference in New Issue
Block a user