fix(doctorstation): 解决医嘱管理中的状态控制和数据处理问题

- 修复了已收费医嘱仍可被勾选的问题,添加了选择条件限制
- 实现了过滤已作废会诊医嘱的功能,防止无效数据展示
- 完善了医嘱删除逻辑,支持草稿、待签发和已作废状态的医嘱删除
- 修复了医嘱撤回功能中的大整数精度丢失问题
- 优化了签退医嘱的服务端处理逻辑,统一处理各种类型的医嘱作废
- 添加了详细的操作日志记录便于问题排查
- 修复了前端医嘱列表加载和操作过程中的数据类型转换问题
This commit is contained in:
2026-03-24 18:27:30 +08:00
parent 8fa0a239b5
commit c542b057b5
5 changed files with 125 additions and 44 deletions

View File

@@ -1397,7 +1397,12 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
*/ */
@Override @Override
public R<?> signOffAdvice(List<Long> requestIdList) { public R<?> signOffAdvice(List<Long> requestIdList) {
// 根据请求编号列表查询收费项目信息 log.info("BugFix#219: signOffAdvice - requestIdList={}", requestIdList);
// 🔧 BugFix: 直接对所有requestId进行作废操作不再先查询分类
// 药品、耗材、诊疗请求都尝试作废,只有存在的才会被更新
// 根据请求编号列表查询收费项目信息(用于检查是否已收费)
List<ChargeItem> chargeItemList = iChargeItemService.getChargeItemInfoByReqId(requestIdList); List<ChargeItem> chargeItemList = iChargeItemService.getChargeItemInfoByReqId(requestIdList);
if (chargeItemList != null && !chargeItemList.isEmpty()) { if (chargeItemList != null && !chargeItemList.isEmpty()) {
@@ -1406,39 +1411,24 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
throw new ServiceException("已收费的项目无法签退,请刷新页面后重试"); throw new ServiceException("已收费的项目无法签退,请刷新页面后重试");
} }
} }
// 分别获取各个请求id列表
List<Long> medReqIdList = new ArrayList<>();
List<Long> devReqIdList = new ArrayList<>();
List<Long> serReqIdList = new ArrayList<>();
chargeItemList.forEach(item -> {
switch (item.getServiceTable()) {
case CommonConstants.TableName.MED_MEDICATION_REQUEST ->
medReqIdList.add(item.getServiceId());
case CommonConstants.TableName.WOR_DEVICE_REQUEST ->
devReqIdList.add(item.getServiceId());
case CommonConstants.TableName.WOR_SERVICE_REQUEST ->
serReqIdList.add(item.getServiceId());
}
});
List<Long> chargeItemIdList = chargeItemList.stream().map(ChargeItem::getId).collect(Collectors.toList()); List<Long> chargeItemIdList = chargeItemList.stream().map(ChargeItem::getId).collect(Collectors.toList());
// 根据id更新收费项目状态 // 根据id更新收费项目状态
iChargeItemService.updatePaymentStatus(chargeItemIdList, ChargeItemStatus.DRAFT.getValue());// 撤回后需要更新为草稿 iChargeItemService.updatePaymentStatus(chargeItemIdList, ChargeItemStatus.DRAFT.getValue());
if (!medReqIdList.isEmpty()) {
// 根据请求id更新请求状态
iMedicationRequestService.updateDraftStatusBatch(medReqIdList, null, null);
}
if (!devReqIdList.isEmpty()) {
// 根据请求id更新请求状态
iDeviceRequestService.updateDraftStatusBatch(devReqIdList);
}
if (!serReqIdList.isEmpty()) {
// 根据请求id更新请求状态
iServiceRequestService.updateDraftStatusBatch(serReqIdList);
}
} else {
return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00006, null));
} }
// 🔧 BugFix: 直接对所有requestId进行作废操作
log.info("BugFix#219: signOffAdvice - 作废所有请求, requestIdList={}", requestIdList);
// 尝试作废药品请求(只有存在的才会更新)
iMedicationRequestService.updateCancelledStatusBatch(requestIdList, null, null);
// 尝试作废耗材请求(只有存在的才会更新)
iDeviceRequestService.updateCancelledStatusBatch(requestIdList);
// 尝试作废诊疗请求(只有存在的才会更新)
iServiceRequestService.updateCancelledStatusBatch(requestIdList);
log.info("BugFix#219: signOffAdvice - 所有请求作废完成");
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null)); return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null));
} }

View File

@@ -15,6 +15,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
/** /**
* 医生站-医嘱/处方 controller * 医生站-医嘱/处方 controller
@@ -91,12 +92,16 @@ public class DoctorStationAdviceController {
/** /**
* 门诊签退医嘱 * 门诊签退医嘱
* *
* @param requestIdList 请求id列表 * @param requestIdList 请求id列表(字符串类型,避免前端大整数精度丢失)
* @return 结果 * @return 结果
*/ */
@PostMapping(value = "/sign-off") @PostMapping(value = "/sign-off")
public R<?> signOffAdvice(@RequestBody List<Long> requestIdList) { public R<?> signOffAdvice(@RequestBody List<String> requestIdList) {
return iDoctorStationAdviceAppService.signOffAdvice(requestIdList); // 🔧 BugFix: 将字符串转换为Long
List<Long> ids = requestIdList.stream()
.map(Long::parseLong)
.collect(Collectors.toList());
return iDoctorStationAdviceAppService.signOffAdvice(ids);
} }
/** /**

View File

@@ -102,6 +102,13 @@ public interface IServiceRequestService extends IService<ServiceRequest> {
*/ */
void updateDraftStatusBatch(List<Long> serReqIdList); void updateDraftStatusBatch(List<Long> serReqIdList);
/**
* 🔧 BugFix#219: 更新服务状态:已作废
*
* @param serReqIdList 请求id列表
*/
void updateCancelledStatusBatch(List<Long> serReqIdList);
/** /**
* 更新服务申请里的打印次数字段 * 更新服务申请里的打印次数字段
* *

View File

@@ -191,6 +191,18 @@ public class ServiceRequestServiceImpl extends ServiceImpl<ServiceRequestMapper,
.in(ServiceRequest::getId, serReqIdList)); .in(ServiceRequest::getId, serReqIdList));
} }
/**
* 🔧 BugFix#219: 更新服务状态:已作废
*
* @param serReqIdList 请求id列表
*/
@Override
public void updateCancelledStatusBatch(List<Long> serReqIdList) {
baseMapper.update(null,
new LambdaUpdateWrapper<ServiceRequest>().set(ServiceRequest::getStatusEnum, RequestStatus.CANCELLED.getValue())
.in(ServiceRequest::getId, serReqIdList));
}
/** /**
* 更新服务申请里的打印次数字段 * 更新服务申请里的打印次数字段
* *

View File

@@ -529,7 +529,13 @@
</el-form> </el-form>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column type="selection" align="center" width="60" /> <el-table-column type="selection" align="center" width="60"
:selectable="(row) => {
// 🔧 BugFix: 已收费的医嘱(statusEnum=3或其他)不能勾选
// 只有草稿(1)、待签发/已签发(2)、已作废(5)状态的医嘱可以勾选
const canSelect = row.statusEnum == 1 || row.statusEnum == 2 || row.statusEnum == 5;
return canSelect;
}" />
<el-table-column label="" align="center" width="60" prop="groupIcon" /> <el-table-column label="" align="center" width="60" prop="groupIcon" />
<el-table-column label="医嘱类型" align="center" prop="productName" width="130"> <el-table-column label="医嘱类型" align="center" prop="productName" width="130">
<template #default="scope"> <template #default="scope">
@@ -1554,7 +1560,32 @@ function getListInfo(addNewRow) {
isAdding.value = false; isAdding.value = false;
const res = await getPrescriptionList(props.patientInfo.encounterId); const res = await getPrescriptionList(props.patientInfo.encounterId);
prescriptionList.value = res.data.map((item) => { // 🔧 BugFix: 过滤掉已作废statusEnum=5的会诊医嘱
const filteredData = res.data.filter(item => {
// 防止 contentJson 为空或 undefined 导致 JSON.parse 报错
let contentJson = {};
try {
contentJson = item.contentJson ? JSON.parse(item.contentJson) : {};
} catch (e) {
contentJson = {};
}
// 判断是否为会诊医嘱
const categoryEnum = contentJson?.categoryEnum || contentJson?.category_enum || item.category_enum;
const isConsultation = categoryEnum === 31 || categoryEnum === '31' ||
contentJson?.consultationType ||
contentJson?.consultationId ||
contentJson?.consultationRequestId;
// 如果是会诊医嘱且状态为已作废5则过滤掉
if (isConsultation && item.statusEnum === 5) {
console.log('BugFix#219: 过滤掉已作废的会诊医嘱, requestId=', item.requestId);
return false;
}
return true;
});
prescriptionList.value = filteredData.map((item) => {
// 防止 contentJson 为空或 undefined 导致 JSON.parse 报错 // 防止 contentJson 为空或 undefined 导致 JSON.parse 报错
let contentJson = {}; let contentJson = {};
try { try {
@@ -2119,13 +2150,14 @@ function handleDelete() {
'statusEnum=', deleteItem.statusEnum, 'requestId=', deleteItem.requestId); 'statusEnum=', deleteItem.statusEnum, 'requestId=', deleteItem.requestId);
} }
// 通过requestId判断是否已保存如果选中项未保存 直接从数组中移除,如果已保存,调接口删除 // 通过requestId判断是否已保存如果选中项未保存 直接从数组中移除,如果已保存,调接口删除
// 🔧 BugFix: 放宽条件,支持 statusEnum 为 1(草稿)2(待签发/已签发) 的医嘱都可以删除 // 🔧 BugFix: 支持 statusEnum 为 1(草稿)2(待签发/已签发)、5(已作废) 的医嘱都可以删除
if (index != -1 && (deleteItem.statusEnum == 1 || deleteItem.statusEnum == 2) && !deleteItem.requestId) { const canDelete = deleteItem.statusEnum == 1 || deleteItem.statusEnum == 2 || deleteItem.statusEnum == 5;
if (index != -1 && canDelete && !deleteItem.requestId) {
console.log('BugFix#219: 删除未保存的医嘱, i=', i); console.log('BugFix#219: 删除未保存的医嘱, i=', i);
prescriptionList.value.splice(i, 1); prescriptionList.value.splice(i, 1);
sum++; sum++;
} else if (index != -1 && (deleteItem.statusEnum == 1 || deleteItem.statusEnum == 2) && deleteItem.requestId) { } else if (index != -1 && canDelete && deleteItem.requestId) {
console.log('BugFix#219: 添加到删除列表, requestId=', deleteItem.requestId); console.log('BugFix#219: 添加到删除列表, requestId=', deleteItem.requestId, 'statusEnum=', deleteItem.statusEnum);
deleteList.push({ deleteList.push({
requestId: deleteItem.requestId, requestId: deleteItem.requestId,
dbOpType: '3', dbOpType: '3',
@@ -2133,6 +2165,8 @@ function handleDelete() {
encounterId: deleteItem.encounterId, // 🔧 BugFix#219: 添加就诊ID encounterId: deleteItem.encounterId, // 🔧 BugFix#219: 添加就诊ID
patientId: deleteItem.patientId, // 🔧 BugFix#219: 添加患者ID patientId: deleteItem.patientId, // 🔧 BugFix#219: 添加患者ID
}); });
} else if (index != -1) {
console.log('BugFix#219: 该医嘱不能删除, statusEnum=', deleteItem.statusEnum);
} }
} }
@@ -3461,6 +3495,13 @@ function escKeyListener(e) {
function handleSingOut() { function handleSingOut() {
let selectRows = prescriptionRef.value.getSelectionRows(); let selectRows = prescriptionRef.value.getSelectionRows();
console.log('BugFix#219: handleSingOut called, selectRows=', selectRows); console.log('BugFix#219: handleSingOut called, selectRows=', selectRows);
console.log('BugFix#219: 选中行详情:', selectRows.map(item => ({
adviceName: item.adviceName,
adviceType: item.adviceType,
statusEnum: item.statusEnum,
statusEnumType: typeof item.statusEnum,
requestId: item.requestId
})));
if (selectRows.length == 0) { if (selectRows.length == 0) {
proxy.$modal.msgWarning('请选择要撤回的医嘱'); proxy.$modal.msgWarning('请选择要撤回的医嘱');
@@ -3472,6 +3513,12 @@ function handleSingOut() {
let normalRows = selectRows.filter(item => item.adviceType !== 5); let normalRows = selectRows.filter(item => item.adviceType !== 5);
console.log('BugFix#219: consultationRows=', consultationRows.length, 'normalRows=', normalRows.length); console.log('BugFix#219: consultationRows=', consultationRows.length, 'normalRows=', normalRows.length);
console.log('BugFix#219: normalRows详情:', normalRows.map(item => ({
adviceName: item.adviceName,
statusEnum: item.statusEnum,
statusEnumType: typeof item.statusEnum,
requestId: item.requestId
})));
// 处理会诊医嘱撤回 // 处理会诊医嘱撤回
if (consultationRows.length > 0) { if (consultationRows.length > 0) {
@@ -3586,10 +3633,22 @@ function handleSingOut() {
adviceName: item.adviceName adviceName: item.adviceName
}))); })));
// 🔧 BugFix: 放宽条件,支持 statusEnum 为 1(草稿) 或 2(已签发) 的医嘱都可以撤回 // 🔧 BugFix: 将requestId转换为数字类型
let requestIdList = normalRows let requestIdList = normalRows
.filter((item) => item.statusEnum == 1 || item.statusEnum == 2) .filter((item) => {
.map((item) => item.requestId); // 🔧 BugFix: 支持 statusEnum 为 1(草稿)、2(已签发)、5(已作废) 的医嘱都可以撤回
const canRecall = item.statusEnum == 1 || item.statusEnum == 2 || item.statusEnum == 5;
console.log('BugFix#219: 检查撤回条件, adviceName=', item.adviceName,
'statusEnum=', item.statusEnum, 'canRecall=', canRecall);
return canRecall;
})
.map((item) => {
// 🔧 BugFix: 保持requestId为字符串避免JavaScript大整数精度丢失
// JavaScript Number只能精确表示2^53-1(9007199254740991)以内的整数
// requestId如2034267613248606210会丢失精度变成2034267613248606200
console.log('BugFix#219: 使用requestId字符串, 值=', item.requestId, '类型=', typeof item.requestId);
return item.requestId; // 保持原始字符串类型
});
console.log('BugFix#219: 可撤回的普通医嘱, requestIdList=', requestIdList); console.log('BugFix#219: 可撤回的普通医嘱, requestIdList=', requestIdList);
@@ -3598,11 +3657,19 @@ function handleSingOut() {
return; return;
} }
console.log('BugFix#219: 调用singOut接口, requestIdList=', requestIdList, '请求体=', JSON.stringify(requestIdList));
singOut(requestIdList).then((res) => { singOut(requestIdList).then((res) => {
console.log('BugFix#219: singOut接口返回, res=', res);
if (res.code == 200) { if (res.code == 200) {
proxy.$modal.msgSuccess('操作成功'); proxy.$modal.msgSuccess('操作成功');
getListInfo(false); getListInfo(false);
} else {
proxy.$modal.msgError('撤回失败: ' + (res.msg || '未知错误'));
} }
}).catch((err) => {
console.error('BugFix#219: singOut接口错误, err=', err);
proxy.$modal.msgError('撤回失败: ' + (err.message || '网络错误'));
}); });
} }