feat(medications): 优化药物删除功能,添加事务处理和批量操作
- 在药物删除时使用事务确保数据一致性 - 删除药物时同时软删除所有相关用药记录 - 优化删除操作性能,使用批量更新替代循环删除 - 扩展删除范围,从删除未服用记录改为删除当天所有记录 - 添加完善的错误处理和日志记录
This commit is contained in:
@@ -4,14 +4,15 @@ import {
|
||||
ForbiddenException,
|
||||
Logger,
|
||||
} from '@nestjs/common';
|
||||
import { InjectModel } from '@nestjs/sequelize';
|
||||
import { InjectModel, InjectConnection } from '@nestjs/sequelize';
|
||||
import { Medication } from './models/medication.model';
|
||||
import { MedicationRecord } from './models/medication-record.model';
|
||||
import { CreateMedicationDto } from './dto/create-medication.dto';
|
||||
import { UpdateMedicationDto } from './dto/update-medication.dto';
|
||||
import { MedicationStatusEnum } from './enums/medication-status.enum';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { Op } from 'sequelize';
|
||||
import { Op, Transaction } from 'sequelize';
|
||||
import { Sequelize } from 'sequelize-typescript';
|
||||
import * as dayjs from 'dayjs';
|
||||
|
||||
/**
|
||||
@@ -26,6 +27,8 @@ export class MedicationsService {
|
||||
private readonly medicationModel: typeof Medication,
|
||||
@InjectModel(MedicationRecord)
|
||||
private readonly recordModel: typeof MedicationRecord,
|
||||
@InjectConnection()
|
||||
private readonly sequelize: Sequelize,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -181,12 +184,25 @@ export class MedicationsService {
|
||||
* 删除药物(软删除)
|
||||
*/
|
||||
async remove(id: string, userId: string): Promise<void> {
|
||||
const medication = await this.findOne(id, userId);
|
||||
const transaction = await this.sequelize.transaction();
|
||||
|
||||
try {
|
||||
const medication = await this.findOne(id, userId);
|
||||
|
||||
medication.deleted = true;
|
||||
await medication.save();
|
||||
// 软删除药物
|
||||
medication.deleted = true;
|
||||
await medication.save({ transaction });
|
||||
|
||||
this.logger.log(`成功删除药物 ${id}`);
|
||||
// 软删除所有相关的用药记录
|
||||
await this.deleteAllMedicationRecords(medication, transaction);
|
||||
|
||||
await transaction.commit();
|
||||
this.logger.log(`成功删除药物 ${id} 及其所有记录`);
|
||||
} catch (error) {
|
||||
await transaction.rollback();
|
||||
this.logger.error(`删除药物失败: ${error instanceof Error ? error.message : '未知错误'}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -307,52 +323,62 @@ export class MedicationsService {
|
||||
);
|
||||
}
|
||||
/**
|
||||
* 删除当天未服用的药物记录
|
||||
* 当药物被停用时,删除当天生成的但还未服用的记录
|
||||
* 删除当天的药物记录
|
||||
* 当药物被停用时,删除当天生成的所有记录
|
||||
*/
|
||||
private async deleteTodayUntakenRecords(medication: Medication): Promise<void> {
|
||||
// 使用当前时间作为基准,查询当前时间及未来的未服用记录
|
||||
const now = new Date();
|
||||
private async deleteTodayUntakenRecords(medication: Medication, transaction?: Transaction): Promise<void> {
|
||||
// 获取当天的开始和结束时间
|
||||
const today = dayjs().format('YYYY-MM-DD');
|
||||
const todayStart = dayjs(today).startOf('day').toDate();
|
||||
const todayEnd = dayjs(today).endOf('day').toDate();
|
||||
|
||||
this.logger.log(
|
||||
`开始删除药物 ${medication.id} 从现在起(${dayjs(now).format('YYYY-MM-DD HH:mm')})的未服用记录`,
|
||||
`开始删除药物 ${medication.id} 在 ${today} 的所有记录`,
|
||||
);
|
||||
|
||||
// 查询从现在开始的所有未服用记录(状态为 UPCOMING)
|
||||
const recordsToDelete = await this.recordModel.findAll({
|
||||
where: {
|
||||
medicationId: medication.id,
|
||||
userId: medication.userId,
|
||||
status: MedicationStatusEnum.UPCOMING,
|
||||
scheduledTime: {
|
||||
[Op.gte]: now, // 大于等于当前时间
|
||||
// 使用批量更新而不是循环删除,提高性能
|
||||
const [affectedCount] = await this.recordModel.update(
|
||||
{ deleted: true },
|
||||
{
|
||||
where: {
|
||||
medicationId: medication.id,
|
||||
userId: medication.userId,
|
||||
scheduledTime: {
|
||||
[Op.between]: [todayStart, todayEnd], // 当天的所有记录
|
||||
},
|
||||
deleted: false,
|
||||
},
|
||||
deleted: false,
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.log(
|
||||
`找到 ${recordsToDelete.length} 条需要删除的 ${medication.id} 记录`,
|
||||
transaction,
|
||||
}
|
||||
);
|
||||
|
||||
if (recordsToDelete.length === 0) {
|
||||
this.logger.log(`没有找到 ${medication.id} 需要删除的记录`);
|
||||
return;
|
||||
}
|
||||
this.logger.log(
|
||||
`成功批量软删除了 ${affectedCount} 条 ${medication.id} 的当天记录`,
|
||||
);
|
||||
}
|
||||
|
||||
// 软删除记录
|
||||
for (const record of recordsToDelete) {
|
||||
const scheduledTime = dayjs(record.scheduledTime).format('YYYY-MM-DD HH:mm');
|
||||
record.deleted = true;
|
||||
await record.save();
|
||||
|
||||
this.logger.log(
|
||||
`软删除记录 ${record.id},计划时间:${scheduledTime}`,
|
||||
);
|
||||
}
|
||||
/**
|
||||
* 删除药物的所有相关记录
|
||||
* 当药物被删除时,软删除所有相关的服药记录
|
||||
*/
|
||||
private async deleteAllMedicationRecords(medication: Medication, transaction?: Transaction): Promise<void> {
|
||||
this.logger.log(`开始删除药物 ${medication.id} 的所有相关记录`);
|
||||
|
||||
// 使用批量更新而不是循环删除,提高性能
|
||||
const [affectedCount] = await this.recordModel.update(
|
||||
{ deleted: true },
|
||||
{
|
||||
where: {
|
||||
medicationId: medication.id,
|
||||
userId: medication.userId,
|
||||
deleted: false,
|
||||
},
|
||||
transaction,
|
||||
}
|
||||
);
|
||||
|
||||
this.logger.log(
|
||||
`成功删除了 ${recordsToDelete.length} 条 ${medication.id} 的未服用记录`,
|
||||
`成功批量软删除了 ${affectedCount} 条 ${medication.id} 的记录`,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user