333 门诊医生站开立耗材医嘱时,类型误转为“中成药”且保存报错

This commit is contained in:
Ranyunqiao
2026-04-03 16:42:10 +08:00
parent f6b39a4815
commit 8a84b40ee5
4 changed files with 194 additions and 49 deletions

View File

@@ -1201,6 +1201,47 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
chargeItem.setServiceId(deviceRequest.getId()); // 医疗服务ID
chargeItem.setProductTable(adviceSaveDto.getAdviceTableName());// 产品所在表
chargeItem.setProductId(adviceSaveDto.getAdviceDefinitionId());// 收费项id
// 🔧 Bug Fix: 如果 definitionId 或 definitionDetailId 为 null从定价信息中获取
if (chargeItem.getDefinitionId() == null || chargeItem.getDefDetailId() == null) {
log.warn("耗材的 definitionId 或 definitionDetailId 为 null尝试从定价信息中获取: deviceDefId={}",
adviceSaveDto.getAdviceDefinitionId());
// 查询耗材定价信息
IPage<AdviceBaseDto> devicePage = doctorStationAdviceAppMapper.getAdviceBaseInfo(
new Page<>(1, 1),
PublicationStatus.ACTIVE.getValue(),
orgId,
CommonConstants.TableName.ADM_DEVICE_DEFINITION,
null,
null,
null,
Arrays.asList(adviceSaveDto.getAdviceDefinitionId()),
null,
null,
null,
null);
if (devicePage != null && !devicePage.getRecords().isEmpty()) {
AdviceBaseDto deviceBaseInfo = devicePage.getRecords().get(0);
if (deviceBaseInfo.getPriceList() != null && !deviceBaseInfo.getPriceList().isEmpty()) {
AdvicePriceDto devicePrice = deviceBaseInfo.getPriceList().get(0);
if (chargeItem.getDefinitionId() == null) {
chargeItem.setDefinitionId(devicePrice.getDefinitionId());
log.info("从定价信息中获取 definitionId: {}", devicePrice.getDefinitionId());
}
if (chargeItem.getDefDetailId() == null) {
chargeItem.setDefDetailId(devicePrice.getDefinitionDetailId());
log.info("从定价信息中获取 definitionDetailId: {}", devicePrice.getDefinitionDetailId());
}
}
}
}
// 🔧 Bug Fix: 确保定义ID不为null
if (chargeItem.getDefinitionId() == null) {
log.error("无法获取耗材的 definitionId: deviceDefId={}", adviceSaveDto.getAdviceDefinitionId());
throw new ServiceException("无法获取耗材的定价信息,请联系管理员");
}
// 🔧 Bug Fix: 如果accountId为null从就诊中获取账户ID如果没有则自动创建
Long accountId = adviceSaveDto.getAccountId();
if (accountId == null) {

View File

@@ -115,6 +115,15 @@ public class AdviceUtils {
matched = true;
// 检查库存是否充足
BigDecimal minUnitQuantity = saveDto.getMinUnitQuantity();
// 🔧 Bug Fix: 对于耗材类型如果没有设置minUnitQuantity则使用quantity作为默认值
if (minUnitQuantity == null) {
if (CommonConstants.TableName.ADM_DEVICE_DEFINITION.equals(inventoryDto.getItemTable())) {
// 耗材只有一个单位minUnitQuantity等于quantity
minUnitQuantity = saveDto.getQuantity();
} else {
return saveDto.getAdviceName() + "的小单位数量不能为空";
}
}
BigDecimal chineseHerbsDoseQuantity = saveDto.getChineseHerbsDoseQuantity(); // 中药付数
// 中草药医嘱的情况
if (chineseHerbsDoseQuantity != null && chineseHerbsDoseQuantity.compareTo(BigDecimal.ZERO) > 0) {

View File

@@ -273,7 +273,10 @@ function fetchFromApi(searchKey) {
minUnitCode_dictText: item.minUnitCode_dictText || item.unitCode_dictText || '',
volume: item.size || item.totalVolume || '',
partPercent: item.partPercent || 1,
inventoryList: [],
// 🔧 Bug Fix: 如果后端提供了inventoryList则使用否则为空数组
inventoryList: item.inventoryList || [],
// 🔧 Bug Fix: 构造stockList用于库存显示
stockList: item.inventoryList || [],
adviceDefinitionId: item.id,
chargeItemDefinitionId: item.id,
positionId: item.locationId,
@@ -354,6 +357,11 @@ function handleQuantity(row) {
const totalQuantity = row.inventoryList.reduce((sum, item) => sum + (item.quantity || 0), 0);
return totalQuantity.toString() + row.minUnitCode_dictText;
}
// 🔧 Bug Fix: 耗材类型可能没有inventoryList但可能有stockList
if (row.stockList && row.stockList.length > 0) {
const totalQuantity = row.stockList.reduce((sum, item) => sum + (item.quantity || 0), 0);
return totalQuantity.toString() + row.minUnitCode_dictText;
}
return 0;
}

View File

@@ -546,6 +546,11 @@
expandOrder = [];
// 当医嘱类型改变时,清空当前选择的项目名称,因为不同类型项目的数据结构可能不兼容
prescriptionList[scope.$index].adviceName = undefined;
prescriptionList[scope.$index].adviceType_dictText = '';
// 🔧 Bug Fix: 医嘱类型改变时重置minUnitQuantity和minUnitCode避免null值
prescriptionList[scope.$index].minUnitQuantity = prescriptionList[scope.$index].quantity || 1;
prescriptionList[scope.$index].minUnitCode = prescriptionList[scope.$index].unitCode;
prescriptionList[scope.$index].minUnitCode_dictText = prescriptionList[scope.$index].unitCode_dictText;
adviceQueryParams.adviceTypes = value; // 🎯 修复:改为 adviceTypes复数
// 根据选择的类型设置categoryCode用于药品分类筛选
@@ -956,25 +961,38 @@ const { method_code, unit_code, rate_code, distribution_category_code, drord_doc
// drord_doctor_type: 1=西药, 2=中成药, 3=诊疗, 4=耗材, 5=会诊, 6=手术
const adviceTypeList = computed(() => {
// 如果字典已加载,使用字典数据;否则使用默认值
let list = [];
if (drord_doctor_type.value && drord_doctor_type.value.length > 0) {
return drord_doctor_type.value.map(item => ({
label: item.label,
value: parseInt(item.value) || item.value
}));
// 过滤掉字典中已有的"全部"选项,避免重复
list = drord_doctor_type.value
.filter(item => item.label !== '全部')
.map(item => ({
label: item.label,
value: parseInt(item.value) || item.value
}));
} else {
// 默认返回值,确保页面正常显示
list = [
{ label: '西药', value: 1 },
{ label: '中成药', value: 2 },
{ label: '诊疗', value: 3 },
{ label: '耗材', value: 4 },
{ label: '会诊', value: 5 },
{ label: '手术', value: 6 },
];
}
// 默认返回值,确保页面正常显示
return [
{ label: '西药', value: 1 },
{ label: '中成药', value: 2 },
{ label: '诊疗', value: 3 },
{ label: '耗材', value: 4 },
{ label: '会诊', value: 5 },
{ label: '手术', value: 6 },
];
// 在最后添加"全部"选项
list.push({ label: '全部', value: 0 });
return list;
});
// 根据类型值获取显示标签,避免非编辑态出现空标签
const mapAdviceTypeLabel = (type) => {
const mapAdviceTypeLabel = (type, adviceTableName) => {
// 🔧 Bug Fix: 根据adviceTableName判断耗材类型
// 后端adviceType=2既表示中成药又表示耗材需要通过表名区分
if (type === 2 && adviceTableName === 'adm_device_definition') {
return '耗材';
}
const found = adviceTypeList.value.find((item) => item.value === type);
return found ? found.label : '';
};
@@ -1602,11 +1620,8 @@ function getListInfo(addNewRow) {
// 🔧 Bug Fix: 后端保存时将耗材(4)转换为中成药(2),显示时需要转换回来
// 检查 adviceTableName如果是耗材表则应该是耗材类型
const adviceTableName = contentJson?.adviceTableName || item.adviceTableName;
if (adviceType === 2 && adviceTableName === 'adm_device_definition') {
adviceType = 4; // 后端2(中成药) -> 前端4(耗材)
}
let adviceType_dictText = item.adviceType_dictText || mapAdviceTypeLabel(adviceType);
let adviceType_dictText = item.adviceType_dictText || mapAdviceTypeLabel(adviceType, adviceTableName);
// 如果是会诊类型,设置为会诊类型
if (isConsultation) {
@@ -2343,6 +2358,13 @@ function handleSave(prescriptionId) {
item.accountId = finalAccountId;
}
item.dbOpType = '1';
// 🔧 Bug Fix: 确保耗材的minUnitQuantity被正确设置
if (item.adviceType == 4) {
item.minUnitQuantity = item.quantity;
item.minUnitCode = item.unitCode;
item.minUnitCode_dictText = item.unitCode_dictText;
}
});
loading.value = true;
@@ -2366,20 +2388,25 @@ function handleSave(prescriptionId) {
finalUnitCode = item.minUnitCode;
}
item.minUnitQuantity = finalQuantity;
} else if (item.adviceType == 4) {
// 🔧 Bug Fix: 耗材类型只有一个单位minUnitQuantity等于quantity
item.minUnitQuantity = item.quantity;
// 🔧 Bug Fix: 确保minUnitCode等于unitCode
item.minUnitCode = item.unitCode;
item.minUnitCode_dictText = item.unitCode_dictText;
finalUnitCode = item.unitCode;
} else {
item.minUnitQuantity = item.quantity;
}
// --- 【修改点3Bug 1 修复 (类型转换)】 ---
let saveAdviceType = item.adviceType;
if (item.adviceType == 4) {
saveAdviceType = 2; // 耗材前端4 -> 后端2
} else if (item.adviceType == 2) {
saveAdviceType = 1; // 中成药前端2 -> 后端1
} else if (item.adviceType == 5) {
// 🔧 Bug Fix: 保持原类型,不进行转换
// 前端类型: 1=西药, 2=中成药, 3=诊疗, 4=耗材, 5=会诊, 6=手术
// 后端类型: 1=药品, 2=耗材, 3=医疗活动, 6=手术
// 后端会通过 ItemType.DEVICE.getValue() || adviceType == 4 来识别耗材
if (item.adviceType == 5) {
saveAdviceType = 3; // 会诊前端5 -> 后端3诊疗类
} else if (item.adviceType == 6) {
saveAdviceType = 6; // 🔧 BugFix#318: 手术类型保持为6
}
// 🔧 Bug Fix: Validate and fix NaN values before sending to backend
@@ -2439,6 +2466,8 @@ function handleSave(prescriptionId) {
quantity: finalQuantity,
unitCode: finalUnitCode,
totalPrice: item.totalPrice, // Ensure totalPrice is valid
// 🔧 Bug Fix: 确保 categoryEnum 被传递(耗材必填字段)
categoryEnum: item.categoryEnum || parsedContent.categoryEnum,
// 🔧 Bug Fix: 确保库存匹配成功的关键字段
adviceTableName: adviceTableNameVal,
locationId: locationIdVal,
@@ -2446,6 +2475,13 @@ function handleSave(prescriptionId) {
methodCode: item.methodCode || parsedContent.methodCode,
// 🔧 确保 accountId 被传递(用于预结算)
accountId: item.accountId || parsedContent.accountId,
// 🔧 Bug Fix: 确保minUnitQuantity被传递耗材必填字段
minUnitQuantity: item.minUnitQuantity,
minUnitCode: item.minUnitCode,
minUnitCode_dictText: item.minUnitCode_dictText,
// 🔧 Bug Fix: 确保 definitionId 和 definitionDetailId 被传递(费用项必填字段)
definitionId: item.definitionId || parsedContent.definitionId,
definitionDetailId: item.definitionDetailId || parsedContent.definitionDetailId,
// 🔧 更新 contentJson 中的 adviceType确保后端分类正确
contentJson: JSON.stringify({
...parsedContent,
@@ -2635,12 +2671,17 @@ function handleOrderBindInfo(bindIdInfo, currentMethodCode) {
encounterDiagnosisId: encounterDiagnosisId.value,
// 🔧 确保 adviceType 和显示文本正确设置
adviceType: item.adviceType,
adviceType_dictText: mapAdviceTypeLabel(item.adviceType),
adviceType_dictText: mapAdviceTypeLabel(item.adviceType, item.adviceTableName),
};
// 计算价格和总量
const unitInfo = unitCodeList.value.find((k) => k.value == item.unitCode);
if (unitInfo && unitInfo.type == 'minUnit') {
// 🔧 Bug Fix: 耗材类型只有一个单位minUnitQuantity等于quantity
if (item.adviceType == 4) {
newRow.price = newRow.unitPrice;
newRow.totalPrice = (item.quantity * newRow.unitPrice).toFixed(6);
newRow.minUnitQuantity = item.quantity;
} else if (unitInfo && unitInfo.type == 'minUnit') {
newRow.price = newRow.minUnitPrice;
newRow.totalPrice = (item.quantity * newRow.minUnitPrice).toFixed(6);
newRow.minUnitQuantity = item.quantity;
@@ -2705,6 +2746,12 @@ function handleSaveSign(row, index, prescriptionId) {
return;
}
// 🔧 Bug Fix: 验证医嘱类型不能为"全部"
if (row.adviceType === 0) {
proxy.$modal.msgWarning('请选择医嘱类型');
return;
}
// 重新查找索引,确保使用当前处方列表中的正确索引
const actualIndex = prescriptionList.value.findIndex(item => item.uniqueKey === row.uniqueKey);
if (actualIndex === -1) {
@@ -2774,14 +2821,18 @@ function handleSaveSign(row, index, prescriptionId) {
row.encounterId = props.patientInfo.encounterId;
row.accountId = accountId.value;
// 确保非编辑态显示正确的医嘱类型标签
row.adviceType_dictText = mapAdviceTypeLabel(row.adviceType);
row.adviceType_dictText = mapAdviceTypeLabel(row.adviceType, row.adviceTableName);
// 更新本地显示的最小单位数量(仅用于前端逻辑,不影响显示单位)
if (row.adviceType == 1 || row.adviceType == 2) {
row.minUnitQuantity =
row.minUnitCode == row.unitCode ? row.quantity : row.quantity * row.partPercent;
} else {
// 🔧 Bug Fix: 耗材和其他类型minUnitQuantity等于quantity
row.minUnitQuantity = row.quantity;
// 🔧 Bug Fix: 确保minUnitCode等于unitCode耗材只有一个单位
row.minUnitCode = row.unitCode;
row.minUnitCode_dictText = row.unitCode_dictText;
}
row.conditionId = conditionId.value;
@@ -2976,14 +3027,12 @@ function handleSaveBatch(prescriptionId) {
// --- Bug 1 修复:类型转换 ---
let saveAdviceType = item.adviceType;
if (item.adviceType == 4) {
saveAdviceType = 2; // 耗材前端4 -> 后端2
} else if (item.adviceType == 2) {
saveAdviceType = 1; // 中成药前端2 -> 后端1
} else if (item.adviceType == 5) {
// 🔧 Bug Fix: 保持原类型,不进行转换
// 前端类型: 1=西药, 2=中成药, 3=诊疗, 4=耗材, 5=会诊, 6=手术
// 后端类型: 1=药品, 2=耗材, 3=医疗活动, 6=手术
// 后端会通过 ItemType.DEVICE.getValue() || adviceType == 4 来识别耗材
if (item.adviceType == 5) {
saveAdviceType = 3; // 会诊前端5 -> 后端3诊疗类
} else if (item.adviceType == 6) {
saveAdviceType = 6; // 🔧 BugFix#318: 手术类型保持为6
}
// 🔧 BugFix#318: 过滤掉手术特有字段,只保留标准医嘱字段
@@ -2994,7 +3043,11 @@ function handleSaveBatch(prescriptionId) {
'encounterId', 'groupId', 'injectFlag', 'lotNumber', 'methodCode', 'partPercent',
'patientId', 'positionId', 'positionName', 'prescriptionNo', 'quantity', 'rateCode',
'requestId', 'skinTestFlag', 'sortNumber', 'statusEnum', 'totalPrice',
'unitCode', 'unitPrice', 'volume', 'ybClassEnum'
'unitCode', 'unitPrice', 'volume', 'ybClassEnum',
// 🔧 Bug Fix: 添加 definitionId 和 definitionDetailId 字段
'definitionId', 'definitionDetailId',
// 🔧 Bug Fix: 添加 categoryEnum 字段(耗材必填)
'categoryEnum'
];
let filteredItem = {};
standardItemFields.forEach(field => {
@@ -3193,17 +3246,26 @@ function syncGroupFields(row) {
function setValue(row) {
unitCodeList.value = [];
unitCodeList.value.push({ value: row.unitCode, label: row.unitCode_dictText, type: 'unit' });
unitCodeList.value.push({
value: row.doseUnitCode,
label: row.doseUnitCode_dictText,
type: 'dose',
});
unitCodeList.value.push({
value: row.minUnitCode,
label: row.minUnitCode_dictText,
type: 'minUnit',
});
// 🔧 Bug Fix: 耗材类型只有一个单位不需要dose和minUnit选项
if (row.adviceType == 4) {
// 耗材只添加一个单位选项
row.minUnitCode = row.unitCode;
row.minUnitCode_dictText = row.unitCode_dictText;
} else {
// 药品类型添加dose和minUnit选项
unitCodeList.value.push({
value: row.doseUnitCode,
label: row.doseUnitCode_dictText,
type: 'dose',
});
unitCodeList.value.push({
value: row.minUnitCode,
label: row.minUnitCode_dictText,
type: 'minUnit',
});
}
if (row.adviceType == 2 && row.minUnitCode != row.unitCode) {
unitCodeList.value.push({
value: row.minUnitCode,
@@ -3237,8 +3299,15 @@ function setValue(row) {
prescriptionList.value[rowIndex.value].unitCodeList = unitCodeList.value;
prescriptionList.value[rowIndex.value].doseUnitCode = row.doseUnitCode;
prescriptionList.value[rowIndex.value].minUnitCode = row.minUnitCode;
prescriptionList.value[rowIndex.value].unitCode =
row.partAttributeEnum == 1 ? row.minUnitCode : row.unitCode;
// 🔧 Bug Fix: 耗材类型只有一个单位minUnitCode应该等于unitCode
if (Number(row.adviceType) == 4) {
prescriptionList.value[rowIndex.value].minUnitCode = row.unitCode;
prescriptionList.value[rowIndex.value].minUnitCode_dictText = row.unitCode_dictText;
prescriptionList.value[rowIndex.value].unitCode = row.unitCode;
} else {
prescriptionList.value[rowIndex.value].unitCode =
row.partAttributeEnum == 1 ? row.minUnitCode : row.unitCode;
}
prescriptionList.value[rowIndex.value].categoryEnum = row.categoryCode;
prescriptionList.value[rowIndex.value].skinTestFlag = row.skinTestFlag;
prescriptionList.value[rowIndex.value].definitionId = row.chargeItemDefinitionId;
@@ -3307,6 +3376,10 @@ function setValue(row) {
// 🔧 Bug #218 修复保留组套中的quantity如果没有则默认1
prescriptionList.value[rowIndex.value].quantity = row.quantity || 1;
prescriptionList.value[rowIndex.value].totalPrice = validPrice * (row.quantity || 1);
// 🔧 Bug Fix: 设置耗材的minUnitQuantity避免保存时null错误
prescriptionList.value[rowIndex.value].minUnitQuantity = row.quantity || 1;
// 🔧 Bug Fix: 设置耗材的categoryEnum避免数据库约束错误
prescriptionList.value[rowIndex.value].categoryEnum = row.categoryCode || 3; // 默认为3
prescriptionList.value[rowIndex.value].positionName = row.positionName || '';
// 🔧 Bug Fix: 使用 positionId如果为空则使用患者信息中的 orgId
console.log('设置耗材locationId:', {
@@ -3325,6 +3398,10 @@ function setValue(row) {
prescriptionList.value[rowIndex.value].minUnitPrice = 0;
prescriptionList.value[rowIndex.value].quantity = row.quantity || 1;
prescriptionList.value[rowIndex.value].totalPrice = 0;
// 🔧 Bug Fix: 设置耗材的minUnitQuantity避免保存时null错误
prescriptionList.value[rowIndex.value].minUnitQuantity = row.quantity || 1;
// 🔧 Bug Fix: 设置耗材的categoryEnum避免数据库约束错误
prescriptionList.value[rowIndex.value].categoryEnum = row.categoryCode || 3; // 默认为3
prescriptionList.value[rowIndex.value].positionName = row.positionName || '';
const finalLocationId = row.positionId || props.patientInfo.orgId;
prescriptionList.value[rowIndex.value].locationId = finalLocationId;
@@ -3967,6 +4044,16 @@ function convertDoseValues(row, index) {
// 总量计算,仅适用只有两种单位的情况
function calculateTotalAmount(row, index) {
nextTick(() => {
// 🔧 Bug Fix: 处理耗材类型的总金额计算
if (row.adviceType == 4) {
row.totalPrice = (row.quantity * row.unitPrice).toFixed(6);
// 🔧 Bug Fix: 确保耗材的minUnitQuantity和minUnitCode正确设置
row.minUnitQuantity = row.quantity;
row.minUnitCode = row.unitCode;
row.minUnitCode_dictText = row.unitCode_dictText;
return;
}
if (row.adviceType == 2) {
calculateTotalPrice(row, index);
return;