feat(ai-coach,checkins): 实现软删除功能
在AI教练和打卡模块中添加deleted字段,将物理删除改为软删除: - 在AiConversation和AiMessage模型中添加deleted布尔字段 - 在Checkin模型中添加deleted字段 - 更新所有查询条件添加deleted: false过滤 - 修改删除操作为标记deleted: true而非物理删除 - 在打卡服务中添加重复记录检查逻辑
This commit is contained in:
@@ -54,7 +54,7 @@ export class AiCoachService {
|
|||||||
|
|
||||||
buildChatHistory = async (userId: string, conversationId: string) => {
|
buildChatHistory = async (userId: string, conversationId: string) => {
|
||||||
const history = await AiMessage.findAll({
|
const history = await AiMessage.findAll({
|
||||||
where: { userId, conversationId },
|
where: { userId, conversationId, deleted: false },
|
||||||
order: [['created_at', 'ASC']],
|
order: [['created_at', 'ASC']],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ export class AiCoachService {
|
|||||||
const pageSize = Math.min(50, Math.max(1, params.pageSize || 20));
|
const pageSize = Math.min(50, Math.max(1, params.pageSize || 20));
|
||||||
const offset = (page - 1) * pageSize;
|
const offset = (page - 1) * pageSize;
|
||||||
const { rows, count } = await AiConversation.findAndCountAll({
|
const { rows, count } = await AiConversation.findAndCountAll({
|
||||||
where: { userId },
|
where: { userId, deleted: false },
|
||||||
order: [['last_message_at', 'DESC']],
|
order: [['last_message_at', 'DESC']],
|
||||||
offset,
|
offset,
|
||||||
limit: pageSize,
|
limit: pageSize,
|
||||||
@@ -147,10 +147,10 @@ export class AiCoachService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getConversationDetail(userId: string, conversationId: string) {
|
async getConversationDetail(userId: string, conversationId: string) {
|
||||||
const conv = await AiConversation.findOne({ where: { id: conversationId, userId } });
|
const conv = await AiConversation.findOne({ where: { id: conversationId, userId, deleted: false } });
|
||||||
if (!conv) return null;
|
if (!conv) return null;
|
||||||
const messages = await AiMessage.findAll({
|
const messages = await AiMessage.findAll({
|
||||||
where: { userId, conversationId },
|
where: { userId, conversationId, deleted: false },
|
||||||
order: [['created_at', 'ASC']],
|
order: [['created_at', 'ASC']],
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
@@ -163,10 +163,10 @@ export class AiCoachService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async deleteConversation(userId: string, conversationId: string): Promise<boolean> {
|
async deleteConversation(userId: string, conversationId: string): Promise<boolean> {
|
||||||
const conv = await AiConversation.findOne({ where: { id: conversationId, userId } });
|
const conv = await AiConversation.findOne({ where: { id: conversationId, userId, deleted: false } });
|
||||||
if (!conv) return false;
|
if (!conv) return false;
|
||||||
await AiMessage.destroy({ where: { userId, conversationId } });
|
await AiMessage.update({ deleted: true }, { where: { userId, conversationId } });
|
||||||
await AiConversation.destroy({ where: { id: conversationId, userId } });
|
await AiConversation.update({ deleted: true }, { where: { id: conversationId, userId } });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,13 @@ export class AiConversation extends Model {
|
|||||||
})
|
})
|
||||||
declare updatedAt: Date;
|
declare updatedAt: Date;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
type: DataType.BOOLEAN,
|
||||||
|
allowNull: false,
|
||||||
|
defaultValue: false,
|
||||||
|
})
|
||||||
|
declare deleted: boolean;
|
||||||
|
|
||||||
@HasMany(() => AiMessage)
|
@HasMany(() => AiMessage)
|
||||||
declare messages?: AiMessage[];
|
declare messages?: AiMessage[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,13 @@ export class AiMessage extends Model {
|
|||||||
})
|
})
|
||||||
declare updatedAt: Date;
|
declare updatedAt: Date;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
type: DataType.BOOLEAN,
|
||||||
|
allowNull: false,
|
||||||
|
defaultValue: false,
|
||||||
|
})
|
||||||
|
declare deleted: boolean;
|
||||||
|
|
||||||
@BelongsTo(() => AiConversation)
|
@BelongsTo(() => AiConversation)
|
||||||
declare conversation?: AiConversation;
|
declare conversation?: AiConversation;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,21 @@ export class CheckinsService {
|
|||||||
) { }
|
) { }
|
||||||
|
|
||||||
async create(dto: CreateCheckinDto): Promise<CheckinResponseDto> {
|
async create(dto: CreateCheckinDto): Promise<CheckinResponseDto> {
|
||||||
|
// 检查是否已存在未删除的记录
|
||||||
|
const existingRecord = await this.checkinModel.findOne({
|
||||||
|
where: {
|
||||||
|
userId: dto.userId,
|
||||||
|
workoutId: dto.workoutId || null,
|
||||||
|
planId: dto.planId || null,
|
||||||
|
checkinDate: dto.checkinDate || null,
|
||||||
|
deleted: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (existingRecord) {
|
||||||
|
return { code: ResponseCode.SUCCESS, message: 'success', data: existingRecord.toJSON() };
|
||||||
|
}
|
||||||
|
|
||||||
const record = await this.checkinModel.create({
|
const record = await this.checkinModel.create({
|
||||||
userId: dto.userId,
|
userId: dto.userId,
|
||||||
workoutId: dto.workoutId || null,
|
workoutId: dto.workoutId || null,
|
||||||
@@ -43,7 +58,12 @@ export class CheckinsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async update(dto: UpdateCheckinDto, userId: string): Promise<CheckinResponseDto> {
|
async update(dto: UpdateCheckinDto, userId: string): Promise<CheckinResponseDto> {
|
||||||
const record = await this.checkinModel.findByPk(dto.id);
|
const record = await this.checkinModel.findOne({
|
||||||
|
where: {
|
||||||
|
id: dto.id,
|
||||||
|
deleted: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
if (!record) {
|
if (!record) {
|
||||||
throw new NotFoundException('打卡记录不存在');
|
throw new NotFoundException('打卡记录不存在');
|
||||||
}
|
}
|
||||||
@@ -75,7 +95,12 @@ export class CheckinsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async complete(dto: CompleteCheckinDto, userId: string): Promise<CheckinResponseDto> {
|
async complete(dto: CompleteCheckinDto, userId: string): Promise<CheckinResponseDto> {
|
||||||
const record = await this.checkinModel.findByPk(dto.id);
|
const record = await this.checkinModel.findOne({
|
||||||
|
where: {
|
||||||
|
id: dto.id,
|
||||||
|
deleted: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
if (!record) {
|
if (!record) {
|
||||||
throw new NotFoundException('打卡记录不存在');
|
throw new NotFoundException('打卡记录不存在');
|
||||||
}
|
}
|
||||||
@@ -114,7 +139,8 @@ export class CheckinsService {
|
|||||||
if (record.userId !== userId) {
|
if (record.userId !== userId) {
|
||||||
throw new ForbiddenException('无权操作该打卡记录');
|
throw new ForbiddenException('无权操作该打卡记录');
|
||||||
}
|
}
|
||||||
await record.destroy();
|
record.deleted = true;
|
||||||
|
await record.save();
|
||||||
await this.activityLogsService.record({
|
await this.activityLogsService.record({
|
||||||
userId: record.userId,
|
userId: record.userId,
|
||||||
entityType: ActivityEntityType.CHECKIN,
|
entityType: ActivityEntityType.CHECKIN,
|
||||||
@@ -139,6 +165,7 @@ export class CheckinsService {
|
|||||||
const rows = await this.checkinModel.findAll({
|
const rows = await this.checkinModel.findAll({
|
||||||
where: {
|
where: {
|
||||||
userId,
|
userId,
|
||||||
|
deleted: false,
|
||||||
[Op.or]: [
|
[Op.or]: [
|
||||||
{ checkinDate: target.format('YYYY-MM-DD') as any },
|
{ checkinDate: target.format('YYYY-MM-DD') as any },
|
||||||
{
|
{
|
||||||
@@ -170,6 +197,7 @@ export class CheckinsService {
|
|||||||
const rows = await this.checkinModel.findAll({
|
const rows = await this.checkinModel.findAll({
|
||||||
where: {
|
where: {
|
||||||
userId,
|
userId,
|
||||||
|
deleted: false,
|
||||||
[Op.or]: [
|
[Op.or]: [
|
||||||
{
|
{
|
||||||
checkinDate: {
|
checkinDate: {
|
||||||
|
|||||||
@@ -111,6 +111,12 @@ export class Checkin extends Model {
|
|||||||
defaultValue: DataType.NOW,
|
defaultValue: DataType.NOW,
|
||||||
})
|
})
|
||||||
declare updatedAt: Date;
|
declare updatedAt: Date;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
type: DataType.BOOLEAN,
|
||||||
|
defaultValue: false,
|
||||||
|
})
|
||||||
|
declare deleted: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user