fix(#643): 门诊手术安排-术中医嘱删除改为状态回退,修复刷新后医嘱重现

- 前端:删除操作改为 UPDATE 状态回退(statusEnum ACTIVE→DRAFT),清除签发人/签发时间
  - 后端:回退时跳过发放/计费/绑耗逻辑,清除 signCode,回退 chargeItem 状态为 DRAFT
  - 后端:回退时保持原始 generateSourceEnum,避免刷新查询不到记录
  - 安全:回退前校验 encounterId 所有权,防止跨就诊 IDOR
This commit is contained in:
wangjian963
2026-06-15 15:27:31 +08:00
parent 17616a32cb
commit 5c73cc6987
3 changed files with 174 additions and 12 deletions

View File

@@ -1189,6 +1189,28 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
if (medicationRequest.getId() == null) {
firstTimeSave = true;
}
// 🔧 Bug #643: 检测是否为状态回退操作(已签发 → 待签发)
// 当 is_save=true 且已有记录的 statusEnum 为 ACTIVE(2) 时,
// 说明前端请求将已签发医嘱回退到待签发状态,需要清除签发信息
boolean isRollback = false;
if (is_save && !firstTimeSave) {
MedicationRequest existing = iMedicationRequestService.getById(medicationRequest.getId());
if (existing != null) {
// 所有权校验:确保操作的医嘱属于当前就诊
if (!existing.getEncounterId().equals(adviceSaveDto.getEncounterId())) {
log.error("Bug#643: 越权操作,医嘱 encounterId={} 与请求 encounterId={} 不匹配",
existing.getEncounterId(), adviceSaveDto.getEncounterId());
throw new ServiceException("无权操作此医嘱");
}
if (RequestStatus.ACTIVE.getValue().equals(existing.getStatusEnum())) {
isRollback = true;
// 保持原始 generateSourceEnum避免被默认值覆盖导致刷新查询不到
medicationRequest.setGenerateSourceEnum(existing.getGenerateSourceEnum());
log.info("Bug#643: 检测到状态回退操作, requestId={}, statusEnum {} → {}",
medicationRequest.getId(), existing.getStatusEnum(), RequestStatus.DRAFT.getValue());
}
}
}
// 确保 contentJson 包含 remark
if (adviceSaveDto.getRemark() != null && !adviceSaveDto.getRemark().isEmpty()) {
medicationRequest.setContentJson(injectRemarkIntoContentJson(medicationRequest.getContentJson(), adviceSaveDto.getRemark()));
@@ -1197,7 +1219,23 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
if (firstTimeSave) {
medRequestIdList.add(medicationRequest.getId().toString());
}
if (is_save) {
// 🔧 Bug #643: 回退操作跳过发放/计费/绑耗逻辑,只清除签发信息
if (isRollback) {
// 清除 medication_request.sign_code
UpdateWrapper<MedicationRequest> signClearWrapper = new UpdateWrapper<>();
signClearWrapper.eq("id", medicationRequest.getId());
signClearWrapper.set("sign_code", null);
iMedicationRequestService.update(null, signClearWrapper);
log.info("Bug#643: 已清除 signCode, requestId={}", medicationRequest.getId());
// 回退 adm_charge_item.status_enum 从 BILLABLE(2) 到 DRAFT(0)
UpdateWrapper<ChargeItem> chargeRollbackWrapper = new UpdateWrapper<>();
chargeRollbackWrapper.eq("service_id", medicationRequest.getId());
chargeRollbackWrapper.eq("service_table", CommonConstants.TableName.MED_MEDICATION_REQUEST);
chargeRollbackWrapper.set("status_enum", ChargeItemStatus.DRAFT.getValue());
iChargeItemService.update(null, chargeRollbackWrapper);
log.info("Bug#643: 已回退费用项状态为 DRAFT, requestId={}", medicationRequest.getId());
} else if (is_save) {
// 处理药品发放
Long dispenseId = iMedicationDispenseService.handleMedicationDispense(medicationRequest,
adviceSaveDto.getDbOpType());
@@ -1658,8 +1696,40 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
if (adviceSaveDto.getRemark() != null && !adviceSaveDto.getRemark().isEmpty()) {
deviceRequest.setContentJson(injectRemarkIntoContentJson(deviceRequest.getContentJson(), adviceSaveDto.getRemark()));
}
// 🔧 Bug #643: 检测是否为耗材状态回退操作(已签发 → 待签发)
boolean deviceFirstTimeSave = (deviceRequest.getId() == null);
boolean deviceIsRollback = false;
if (is_save && !deviceFirstTimeSave) {
DeviceRequest existingDevice = iDeviceRequestService.getById(deviceRequest.getId());
if (existingDevice != null) {
// 所有权校验
if (!existingDevice.getEncounterId().equals(adviceSaveDto.getEncounterId())) {
log.error("Bug#643: 越权操作(耗材),医嘱 encounterId={} 与请求 encounterId={} 不匹配",
existingDevice.getEncounterId(), adviceSaveDto.getEncounterId());
throw new ServiceException("无权操作此医嘱");
}
if (RequestStatus.ACTIVE.getValue().equals(existingDevice.getStatusEnum())) {
deviceIsRollback = true;
// 保持原始 generateSourceEnum避免被默认值覆盖导致刷新查询不到
deviceRequest.setGenerateSourceEnum(existingDevice.getGenerateSourceEnum());
log.info("Bug#643: 检测到耗材状态回退操作, requestId={}, statusEnum {} → {}",
deviceRequest.getId(), existingDevice.getStatusEnum(), RequestStatus.DRAFT.getValue());
}
}
}
iDeviceRequestService.saveOrUpdate(deviceRequest);
if (is_save) {
// 🔧 Bug #643: 耗材回退操作跳过发放/计费逻辑,只清除签发信息
if (deviceIsRollback) {
// 清除 wor_device_request.sign_code如果该表有此字段
// 回退 adm_charge_item.status_enum 从 BILLABLE(2) 到 DRAFT(0)
UpdateWrapper<ChargeItem> deviceChargeRollbackWrapper = new UpdateWrapper<>();
deviceChargeRollbackWrapper.eq("service_id", deviceRequest.getId());
deviceChargeRollbackWrapper.eq("service_table", CommonConstants.TableName.WOR_DEVICE_REQUEST);
deviceChargeRollbackWrapper.set("status_enum", ChargeItemStatus.DRAFT.getValue());
iChargeItemService.update(null, deviceChargeRollbackWrapper);
log.info("Bug#643: 已回退耗材费用项状态为 DRAFT, requestId={}", deviceRequest.getId());
} else if (is_save) {
// 处理耗材发放
Long dispenseId = iDeviceDispenseService.handleDeviceDispense(deviceRequest,
adviceSaveDto.getDbOpType());