fix(prescription): 解决处方列表中手术类型和其他医嘱类型的问题

- 更新 lodash.template 修复脚本以处理 assignWith 函数的自定义器参数
- 在多个处方组件中引入 drord_doctor_type 字典用于动态生成医嘱类型列表
- 修复手术类型(adviceType=6)的特殊处理逻辑,包括类型映射和字段过滤
- 调整后端医嘱保存服务中的类型分类逻辑,正确处理手术类型
- 更新数据库查询映射以支持手术类型的正确显示和数据传输
- 修复费用对话框和订单表单中的相关类型显示问题
This commit is contained in:
2026-04-01 18:24:24 +08:00
parent 6694ae52ba
commit ac1cd3afc8
16 changed files with 306 additions and 186 deletions

View File

@@ -564,13 +564,15 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
// 耗材前端adviceType=4后端ItemType.DEVICE=2 // 耗材前端adviceType=4后端ItemType.DEVICE=2
List<AdviceSaveDto> deviceList = adviceSaveList.stream() List<AdviceSaveDto> deviceList = adviceSaveList.stream()
.filter(e -> ItemType.DEVICE.getValue().equals(e.getAdviceType()) .filter(e -> ItemType.DEVICE.getValue().equals(e.getAdviceType())
|| e.getAdviceType() == 4) // 🔧 BugFix: 前端耗材类型值为4 || e.getAdviceType() == 4) // 前端耗材类型值为4
.collect(Collectors.toList()); .collect(Collectors.toList());
// 诊疗活动包括普通诊疗前端adviceType=3会诊前端adviceType=5
// 诊疗活动前端adviceType=3诊疗、adviceType=5会诊、adviceType=6手术
List<AdviceSaveDto> activityList = adviceSaveList.stream() List<AdviceSaveDto> activityList = adviceSaveList.stream()
.filter(e -> ItemType.ACTIVITY.getValue().equals(e.getAdviceType()) .filter(e -> ItemType.ACTIVITY.getValue().equals(e.getAdviceType())
|| e.getAdviceType() == 3 // 🔧 BugFix: 前端诊疗类型值为3 || e.getAdviceType() == 3 // 前端诊疗类型值为3
|| e.getAdviceType() == 5) // 🔧 BugFix: 前端会诊类型值为5 || e.getAdviceType() == 5 // 前端会诊类型值为5
|| ItemType.SURGERY.getValue().equals(e.getAdviceType())) // 🔧 BugFix#318: 手术类型值为6
.collect(Collectors.toList()); .collect(Collectors.toList());
// 🔍 Debug日志: 记录分类结果 // 🔍 Debug日志: 记录分类结果
@@ -599,11 +601,12 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
iDeviceDispenseService.deleteDeviceDispense(adviceSaveDto.getRequestId()); iDeviceDispenseService.deleteDeviceDispense(adviceSaveDto.getRequestId());
} }
// 🔧 Bug Fix: 跳过耗材的库存校验(耗材的库存校验逻辑不同) // 🔧 Bug Fix: 跳过耗材、诊疗、手术的库存校验
List<AdviceSaveDto> needCheckList = adviceSaveList.stream() List<AdviceSaveDto> needCheckList = adviceSaveList.stream()
.filter(e -> !DbOpType.DELETE.getCode().equals(e.getDbOpType()) .filter(e -> !DbOpType.DELETE.getCode().equals(e.getDbOpType())
&& !ItemType.ACTIVITY.getValue().equals(e.getAdviceType()) && !ItemType.ACTIVITY.getValue().equals(e.getAdviceType())
&& !ItemType.DEVICE.getValue().equals(e.getAdviceType())) // 排除耗材 && !ItemType.DEVICE.getValue().equals(e.getAdviceType())
&& !ItemType.SURGERY.getValue().equals(e.getAdviceType())) // 🔧 BugFix#318: 排除手术类型
.collect(Collectors.toList()); .collect(Collectors.toList());
// 校验库存 // 校验库存
String tipRes = adviceUtils.checkInventory(needCheckList); String tipRes = adviceUtils.checkInventory(needCheckList);

View File

@@ -161,6 +161,11 @@ public class RequestBaseDto {
private String doseUnitCode; private String doseUnitCode;
private String doseUnitCode_dictText; private String doseUnitCode_dictText;
/**
* 单价
*/
private BigDecimal unitPrice;
/** /**
* 总价 * 总价
*/ */
@@ -215,4 +220,16 @@ public class RequestBaseDto {
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long basedOnId; private Long basedOnId;
/**
* 就诊id
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long encounterId;
/**
* 患者id
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long patientId;
} }

View File

@@ -292,7 +292,7 @@ public class RequestFormManageAppServiceImpl implements IRequestFormManageAppSer
surgeryChargeItem.setBusNo(AssignSeqEnum.CHARGE_ITEM_NO.getPrefix().concat(surgeryServiceRequest.getBusNo())); surgeryChargeItem.setBusNo(AssignSeqEnum.CHARGE_ITEM_NO.getPrefix().concat(surgeryServiceRequest.getBusNo()));
surgeryChargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); surgeryChargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue());
surgeryChargeItem.setPatientId(patientId); surgeryChargeItem.setPatientId(patientId);
surgeryChargeItem.setContextEnum(3); // 3-诊疗 surgeryChargeItem.setContextEnum(6); // 6-手术
surgeryChargeItem.setEncounterId(encounterId); surgeryChargeItem.setEncounterId(encounterId);
surgeryChargeItem.setEntererId(practitionerId); surgeryChargeItem.setEntererId(practitionerId);
surgeryChargeItem.setEnteredDate(curDate); surgeryChargeItem.setEnteredDate(curDate);

View File

@@ -468,6 +468,7 @@
T1.dose AS dose, T1.dose AS dose,
T1.dose_unit_code AS dose_unit_code, T1.dose_unit_code AS dose_unit_code,
T4.id AS charge_item_id, T4.id AS charge_item_id,
T4.unit_price AS unit_price,
T4.total_price AS total_price, T4.total_price AS total_price,
T4.status_enum AS charge_status, T4.status_enum AS charge_status,
al.id AS position_id, al.id AS position_id,
@@ -477,7 +478,9 @@
ccd.name AS condition_definition_name, ccd.name AS condition_definition_name,
T1.sort_number AS sort_number, T1.sort_number AS sort_number,
T1.based_on_id AS based_on_id, T1.based_on_id AS based_on_id,
T1.category_enum AS category_enum T1.category_enum AS category_enum,
T1.encounter_id AS encounter_id,
T1.patient_id AS patient_id
FROM med_medication_request AS T1 FROM med_medication_request AS T1
LEFT JOIN med_medication_definition AS T2 ON T2.ID = T1.medication_id LEFT JOIN med_medication_definition AS T2 ON T2.ID = T1.medication_id
AND T2.delete_flag = '0' AND T2.delete_flag = '0'
@@ -520,6 +523,7 @@
NULL AS dose, NULL AS dose,
'' AS dose_unit_code, '' AS dose_unit_code,
T3.id AS charge_item_id, T3.id AS charge_item_id,
T3.unit_price AS unit_price,
T3.total_price AS total_price, T3.total_price AS total_price,
T3.status_enum AS charge_status, T3.status_enum AS charge_status,
al.id AS position_id, al.id AS position_id,
@@ -529,7 +533,9 @@
'' AS condition_definition_name, '' AS condition_definition_name,
99 AS sort_number, 99 AS sort_number,
T1.based_on_id AS based_on_id, T1.based_on_id AS based_on_id,
T1.category_enum AS category_enum T1.category_enum AS category_enum,
T1.encounter_id AS encounter_id,
T1.patient_id AS patient_id
FROM wor_device_request AS T1 FROM wor_device_request AS T1
LEFT JOIN adm_device_definition AS T2 ON T2.ID = T1.device_def_id LEFT JOIN adm_device_definition AS T2 ON T2.ID = T1.device_def_id
AND T2.delete_flag = '0' AND T2.delete_flag = '0'
@@ -547,7 +553,7 @@
AND T1.refund_device_id IS NULL AND T1.refund_device_id IS NULL
ORDER BY T1.status_enum) ORDER BY T1.status_enum)
UNION ALL UNION ALL
(SELECT COALESCE(T1.category_enum, 3) AS advice_type, (SELECT CASE WHEN T1.category_enum = 4 THEN 6 ELSE COALESCE(T1.category_enum, 3) END AS advice_type,
T1.id AS request_id, T1.id AS request_id,
T1.id || '-3' AS unique_key, T1.id || '-3' AS unique_key,
'' AS prescription_no, '' AS prescription_no,
@@ -561,15 +567,16 @@
COALESCE(T2.NAME, T1.content_json::jsonb->>'surgeryName', T1.content_json::jsonb->>'adviceName') AS advice_name, COALESCE(T2.NAME, T1.content_json::jsonb->>'surgeryName', T1.content_json::jsonb->>'adviceName') AS advice_name,
'' AS volume, '' AS volume,
'' AS lot_number, '' AS lot_number,
T1.quantity AS quantity, T1.quantity AS quantity,
T1.unit_code AS unit_code, T1.unit_code AS unit_code,
T1.status_enum AS status_enum, T1.status_enum AS status_enum,
'' AS method_code, '' AS method_code,
'' AS rate_code, '' AS rate_code,
NULL AS dose, NULL AS dose,
'' AS dose_unit_code, '' AS dose_unit_code,
T3.id AS charge_item_id, T3.id AS charge_item_id,
T3.total_price AS total_price, T3.unit_price AS unit_price,
T3.total_price AS total_price,
T3.status_enum AS charge_status, T3.status_enum AS charge_status,
ao.id AS position_id, ao.id AS position_id,
ao.name AS position_name, ao.name AS position_name,
@@ -577,9 +584,11 @@
1 AS part_percent, 1 AS part_percent,
'' AS condition_definition_name, '' AS condition_definition_name,
99 AS sort_number, 99 AS sort_number,
T1.based_on_id AS based_on_id, T1.based_on_id AS based_on_id,
T1.category_enum AS category_enum T1.category_enum AS category_enum,
FROM wor_service_request AS T1 T1.encounter_id AS encounter_id,
T1.patient_id AS patient_id
FROM wor_service_request AS T1
LEFT JOIN wor_activity_definition AS T2 LEFT JOIN wor_activity_definition AS T2
ON T2.ID = T1.activity_id ON T2.ID = T1.activity_id
AND T2.delete_flag = '0' AND T2.delete_flag = '0'

View File

@@ -203,6 +203,7 @@
T1.dose AS dose, T1.dose AS dose,
T1.dose_unit_code AS dose_unit_code, T1.dose_unit_code AS dose_unit_code,
T4.id AS charge_item_id, T4.id AS charge_item_id,
T4.unit_price AS unit_price,
T4.total_price AS total_price, T4.total_price AS total_price,
T4.status_enum AS charge_status, T4.status_enum AS charge_status,
al.id AS position_id, al.id AS position_id,
@@ -254,6 +255,7 @@
NULL AS dose, NULL AS dose,
'' AS dose_unit_code, '' AS dose_unit_code,
T3.id AS charge_item_id, T3.id AS charge_item_id,
T3.unit_price AS unit_price,
T3.total_price AS total_price, T3.total_price AS total_price,
T3.status_enum AS charge_status, T3.status_enum AS charge_status,
al.id AS position_id, al.id AS position_id,
@@ -281,7 +283,7 @@
AND T1.refund_device_id IS NULL AND T1.refund_device_id IS NULL
ORDER BY T1.status_enum) ORDER BY T1.status_enum)
UNION ALL UNION ALL
(SELECT COALESCE(T1.category_enum, 3) AS advice_type, (SELECT CASE WHEN T1.category_enum = 4 THEN 6 ELSE COALESCE(T1.category_enum, 3) END AS advice_type,
T1.id AS request_id, T1.id AS request_id,
T1.id || '-3' AS unique_key, T1.id || '-3' AS unique_key,
T1.requester_id AS requester_id, T1.requester_id AS requester_id,
@@ -302,6 +304,7 @@
NULL AS dose, NULL AS dose,
'' AS dose_unit_code, '' AS dose_unit_code,
T3.id AS charge_item_id, T3.id AS charge_item_id,
T3.unit_price AS unit_price,
T3.total_price AS total_price, T3.total_price AS total_price,
T3.status_enum AS charge_status, T3.status_enum AS charge_status,
ao.id AS position_id, ao.id AS position_id,

View File

@@ -26,12 +26,13 @@
<select id="getRequestFormDetail" resultType="com.openhis.web.regdoctorstation.dto.RequestFormDetailQueryDto"> <select id="getRequestFormDetail" resultType="com.openhis.web.regdoctorstation.dto.RequestFormDetailQueryDto">
SELECT wsr.quantity, SELECT wsr.quantity,
wsr.unit_code, wsr.unit_code,
wad.NAME AS advice_name, COALESCE(wad.NAME, wsr.content_json::jsonb->>'surgeryName') AS advice_name,
aci.total_price aci.total_price
FROM wor_service_request AS wsr FROM wor_service_request AS wsr
LEFT JOIN wor_activity_definition AS wad ON wad.ID = wsr.activity_id LEFT JOIN wor_activity_definition AS wad ON wad.ID = wsr.activity_id
AND wad.delete_flag = '0' AND wad.delete_flag = '0'
LEFT JOIN adm_charge_item AS aci ON aci.service_id = wsr.ID LEFT JOIN adm_charge_item AS aci ON aci.service_id = wsr.ID
AND aci.service_table = 'wor_service_request'
AND aci.delete_flag = '0' AND aci.delete_flag = '0'
WHERE wsr.delete_flag = '0' WHERE wsr.delete_flag = '0'
AND wsr.prescription_no = #{prescriptionNo} AND wsr.prescription_no = #{prescriptionNo}

View File

@@ -23,14 +23,19 @@ public enum ItemType implements HisEnumInterface {
MEDICINE(1, "1", "药品"), MEDICINE(1, "1", "药品"),
/** /**
* 耗材 * 医疗活动
*/
ACTIVITY(3, "3", "医疗活动"),
/**
* 耗材前端使用值2
*/ */
DEVICE(2, "2", "耗材"), DEVICE(2, "2", "耗材"),
/** /**
* 医疗活动 * 手术前端使用值6避免与耗材冲突
*/ */
ACTIVITY(3, "3", "医疗活动"); SURGERY(6, "6", "手术");
@EnumValue @EnumValue
private Integer value; private Integer value;

View File

@@ -1,4 +1,3 @@
#!/usr/bin/env node
/** /**
* Fix lodash.template assignWith issue - Manual fix script * Fix lodash.template assignWith issue - Manual fix script
* Run this after npm/yarn install and before build * Run this after npm/yarn install and before build
@@ -18,34 +17,35 @@ if (!fs.existsSync(lodashTemplatePath)) {
let content = fs.readFileSync(lodashTemplatePath, 'utf8'); let content = fs.readFileSync(lodashTemplatePath, 'utf8');
// Check if already patched // Check if already patched with new version
if (content.includes('/* LODASH_TEMPLATE_PATCHED */')) { if (content.includes('/* LODASH_TEMPLATE_PATCHED_V2 */')) {
console.log('✓ lodash.template already patched'); console.log('✓ lodash.template already patched with v2');
process.exit(0); process.exit(0);
} }
// Check if assignWith is actually missing // Remove old patch if exists
if (content.includes('assignWith')) { if (content.includes('/* LODASH_TEMPLATE_PATCHED */')) {
// Check if it's used but not defined console.log('🔄 Removing old patch...');
const hasFunctionDefinition = /function\s+assignWith|var\s+assignWith\s*=/.test(content); content = content.replace(/\/\* LODASH_TEMPLATE_PATCHED \*\/\n.*assignWith[\s\S]*?^\}/m, '');
if (hasFunctionDefinition) {
console.log('✓ assignWith is already defined in lodash.template');
process.exit(0);
}
} }
console.log('🔧 Patching lodash.template...'); console.log('🔧 Patching lodash.template with v2...');
// Simple assignWith implementation // Correct assignWith implementation that handles undefined customizer
const assignWithImpl = `/* LODASH_TEMPLATE_PATCHED */ const assignWithImpl = `/* LODASH_TEMPLATE_PATCHED_V2 */
// assignWith polyfill for lodash.template // assignWith polyfill for lodash.template - Fixed version
function assignWith(object, source, customizer) { function assignWith(object, source, customizer) {
if (object == null) return object; if (object == null) return object;
if (typeof customizer !== 'function') {
customizer = function(objValue, srcValue) {
return srcValue;
};
}
var props = Object.keys(Object(source)); var props = Object.keys(Object(source));
for (var i = 0; i < props.length; i++) { for (var i = 0; i < props.length; i++) {
var key = props[i]; var key = props[i];
var value = source[key]; var value = source[key];
var assignedValue = customizer ? customizer(object[key], value, key, object, source) : value; var assignedValue = customizer(object[key], value, key, object, source);
if (assignedValue !== undefined) { if (assignedValue !== undefined) {
object[key] = assignedValue; object[key] = assignedValue;
} }
@@ -74,5 +74,5 @@ const after = content.substring(insertPos);
content = before + '\n' + assignWithImpl + after; content = before + '\n' + assignWithImpl + after;
fs.writeFileSync(lodashTemplatePath, content); fs.writeFileSync(lodashTemplatePath, content);
console.log('✅ Successfully patched lodash.template with assignWith function'); console.log('✅ Successfully patched lodash.template with assignWith function (v2)');
console.log(' File:', lodashTemplatePath); console.log(' File:', lodashTemplatePath);

View File

@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# Fix lodash.template assignWith issue for Linux/Mac servers # Fix lodash.template assignWith issue for Linux/Mac servers - V2
# Run this script after npm/yarn install # Run this script after npm/yarn install
LODGASH_TEMPLATE="node_modules/lodash.template/index.js" LODGASH_TEMPLATE="node_modules/lodash.template/index.js"
@@ -9,34 +9,43 @@ if [ ! -f "$LODGASH_TEMPLATE" ]; then
exit 1 exit 1
fi fi
# Check if already patched # Check if already patched with v2
if grep -q "LODASH_TEMPLATE_PATCHED" "$LODGASH_TEMPLATE"; then if grep -q "LODASH_TEMPLATE_PATCHED_V2" "$LODGASH_TEMPLATE"; then
echo "✓ lodash.template already patched" echo "✓ lodash.template already patched with v2"
exit 0 exit 0
fi fi
echo "🔧 Patching lodash.template..." # Remove old patch if exists
if grep -q "LODASH_TEMPLATE_PATCHED" "$LODGASH_TEMPLATE"; then
echo "🔄 Removing old patch..."
# Use sed to remove old patch (multi-line)
sed -i '/\/\* LODASH_TEMPLATE_PATCHED \*\//,/^}$/d' "$LODGASH_TEMPLATE"
fi
echo "🔧 Patching lodash.template with v2..."
# Create a temporary file with the patch # Create a temporary file with the patch
PATCH=$(cat <<'EOF' PATCH='/* LODASH_TEMPLATE_PATCHED_V2 */
/* LODASH_TEMPLATE_PATCHED */ // assignWith polyfill for lodash.template - Fixed version
// assignWith polyfill for lodash.template
function assignWith(object, source, customizer) { function assignWith(object, source, customizer) {
if (object == null) return object; if (object == null) return object;
if (typeof customizer !== "function") {
customizer = function(objValue, srcValue) {
return srcValue;
};
}
var props = Object.keys(Object(source)); var props = Object.keys(Object(source));
for (var i = 0; i < props.length; i++) { for (var i = 0; i < props.length; i++) {
var key = props[i]; var key = props[i];
var value = source[key]; var value = source[key];
var assignedValue = customizer ? customizer(object[key], value, key, object, source) : value; var assignedValue = customizer(object[key], value, key, object, source);
if (assignedValue !== undefined) { if (assignedValue !== undefined) {
object[key] = assignedValue; object[key] = assignedValue;
} }
} }
return object; return object;
} }
'
EOF
)
# Insert after the first line (license comment) # Insert after the first line (license comment)
{ {
@@ -45,4 +54,4 @@ EOF
tail -n +2 "$LODGASH_TEMPLATE" tail -n +2 "$LODGASH_TEMPLATE"
} > "$LODGASH_TEMPLATE.tmp" && mv "$LODGASH_TEMPLATE.tmp" "$LODGASH_TEMPLATE" } > "$LODGASH_TEMPLATE.tmp" && mv "$LODGASH_TEMPLATE.tmp" "$LODGASH_TEMPLATE"
echo "✅ Successfully patched lodash.template with assignWith function" echo "✅ Successfully patched lodash.template with assignWith function (v2)"

View File

@@ -9,7 +9,10 @@
"predev": "node utils/check.js dev && vdoing", "predev": "node utils/check.js dev && vdoing",
"prebuild": "node utils/check.js build && vdoing", "prebuild": "node utils/check.js build && vdoing",
"updateTheme": "yarn remove vuepress-theme-vdoing && rm -rf node_modules && yarn && yarn add vuepress-theme-vdoing -D", "updateTheme": "yarn remove vuepress-theme-vdoing && rm -rf node_modules && yarn && yarn add vuepress-theme-vdoing -D",
"editFm": "node utils/editFrontmatter.js" "editFm": "node utils/editFrontmatter.js",
"fix-lodash": "node fix-lodash-manual.js",
"build:fixed": "npm run fix-lodash && npm run build",
"build:win:fixed": "npm run fix-lodash && npm run build:win"
}, },
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -23,6 +26,7 @@
"inquirer": "^7.1.0", "inquirer": "^7.1.0",
"json2yaml": "^1.1.0", "json2yaml": "^1.1.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"lodash.assignwith": "^4.2.0",
"vuepress": "1.9.9", "vuepress": "1.9.9",
"vuepress-plugin-baidu-tongji": "^1.0.1", "vuepress-plugin-baidu-tongji": "^1.0.1",
"vuepress-plugin-demo-block": "^0.7.2", "vuepress-plugin-demo-block": "^0.7.2",
@@ -33,5 +37,13 @@
"vuepress-theme-vdoing": "^1.12.9", "vuepress-theme-vdoing": "^1.12.9",
"yamljs": "^0.3.0" "yamljs": "^0.3.0"
}, },
"dependencies": {} "dependencies": {},
"resolutions": {
"lodash": "^4.17.21",
"lodash.template": "^4.5.0"
},
"overrides": {
"lodash": "^4.17.21",
"lodash.template": "^4.5.0"
}
} }

View File

@@ -571,7 +571,7 @@
<script setup> <script setup>
import {getOrgTree, saveOrderGroup} from './api'; import {getOrgTree, saveOrderGroup} from './api';
import adviceBaseList from './adviceBaseList'; import adviceBaseList from './adviceBaseList';
import {getCurrentInstance, nextTick, watch} from 'vue'; import {computed, getCurrentInstance, nextTick, ref, watch} from 'vue';
import {calculateQuantityByDays, formatNumber} from '@/utils/his'; import {calculateQuantityByDays, formatNumber} from '@/utils/his';
const emit = defineEmits(['selectDiagnosis']); const emit = defineEmits(['selectDiagnosis']);
@@ -620,31 +620,31 @@ const stockList = ref([]);
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const inputRefs = ref({}); // 存储输入框实例 const inputRefs = ref({}); // 存储输入框实例
const requiredProps = ref([]); // 存储必填项 prop 顺序 const requiredProps = ref([]); // 存储必填项 prop 顺序
const { method_code, unit_code, rate_code, distribution_category_code } = proxy.useDict( const { method_code, unit_code, rate_code, distribution_category_code, drord_doctor_type } = proxy.useDict(
'method_code', 'method_code',
'unit_code', 'unit_code',
'rate_code', 'rate_code',
'distribution_category_code' 'distribution_category_code',
'drord_doctor_type'
); );
const adviceTypeList = ref([ // 使用 drord_doctor_type 字典
{ const adviceTypeList = computed(() => {
label: '西药中成药', if (drord_doctor_type.value && drord_doctor_type.value.length > 0) {
value: 1, const list = drord_doctor_type.value.map(item => ({
}, label: item.label,
{ value: parseInt(item.value) || item.value
label: '耗材', }));
value: 2, return [...list, { label: '全部', value: undefined }];
}, }
{ // 默认值
label: '诊疗', return [
value: 3, { label: '西药中成药', value: 1 },
}, { label: '耗材', value: 4 },
{ { label: '诊疗', value: 3 },
label: '全部', { label: '全部', value: undefined },
value: undefined, ];
}, });
]);
onMounted(() => { onMounted(() => {
document.addEventListener('keydown', escKeyListener); document.addEventListener('keydown', escKeyListener);
}); });

View File

@@ -289,7 +289,7 @@
<script setup> <script setup>
import {getOrgTree, getPrescriptionList, savePrescription, savePrescriptionSign, singOut,} from './api'; import {getOrgTree, getPrescriptionList, savePrescription, savePrescriptionSign, singOut,} from './api';
import adviceBaseList from './adviceBaseList'; import adviceBaseList from './adviceBaseList';
import {getCurrentInstance, nextTick, ref, watch} from 'vue'; import {computed, getCurrentInstance, nextTick, ref, watch} from 'vue';
const emit = defineEmits(['selectDiagnosis']); const emit = defineEmits(['selectDiagnosis']);
const prescriptionList = ref([]); const prescriptionList = ref([]);
@@ -334,28 +334,35 @@ const groupList = ref([])
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const inputRefs = ref({}); // 存储输入框实例 const inputRefs = ref({}); // 存储输入框实例
const requiredProps = ref([]); // 存储必填项 prop 顺序 const requiredProps = ref([]); // 存储必填项 prop 顺序
const { method_code, unit_code, rate_code, distribution_category_code } = proxy.useDict( const { method_code, unit_code, rate_code, distribution_category_code, drord_doctor_type } = proxy.useDict(
'method_code', 'method_code',
'unit_code', 'unit_code',
'rate_code', 'rate_code',
'distribution_category_code' 'distribution_category_code',
'drord_doctor_type'
); );
const handleSaveDisabled = ref(false) //签发状态 const handleSaveDisabled = ref(false) //签发状态
const handleSingOutDisabled = ref(false) //签退状态 const handleSingOutDisabled = ref(false) //签退状态
const adviceTypeList = ref([ // 使用 drord_doctor_type 字典
{ const adviceTypeList = computed(() => {
label: '耗材', if (drord_doctor_type.value && drord_doctor_type.value.length > 0) {
value: 2, // 只保留耗材(4)和诊疗(3)类型,并添加全部选项
}, const filtered = drord_doctor_type.value.filter(item => {
{ const val = parseInt(item.value);
label: '诊疗', return val === 3 || val === 4; // 诊疗和耗材
value: 3, }).map(item => ({
}, label: item.label,
{ value: parseInt(item.value)
label: '全部', }));
value: undefined, return [...filtered, { label: '全部', value: undefined }];
}, }
]); // 默认值
return [
{ label: '耗材', value: 4 },
{ label: '诊疗', value: 3 },
{ label: '全部', value: undefined },
];
});
watch( watch(
() => expandOrder.value, () => expandOrder.value,
(newValue) => { (newValue) => {

View File

@@ -957,34 +957,26 @@ const { method_code, unit_code, rate_code, distribution_category_code, drord_doc
'drord_doctor_type' 'drord_doctor_type'
); );
// 删除硬编码的adviceTypeList直接使用drord_doctor_type字典 // 使用 drord_doctor_type 字典,不再硬编码
// drord_doctor_type: 1=西药, 2=中成药, 3=诊疗, 4=耗材, 5=会诊, 6=全部 // drord_doctor_type: 1=西药, 2=中成药, 3=诊疗, 4=耗材, 5=会诊, 6=手术
const adviceTypeList = ref([ const adviceTypeList = computed(() => {
{ // 如果字典已加载,使用字典数据;否则使用默认值
label: '西药', if (drord_doctor_type.value && drord_doctor_type.value.length > 0) {
value: 1, return drord_doctor_type.value.map(item => ({
}, label: item.label,
{ value: parseInt(item.value) || item.value
label: '中成药', }));
value: 2, }
}, // 默认返回值,确保页面正常显示
{ return [
label: '诊疗', { label: '西药', value: 1 },
value: 3, { label: '中成药', value: 2 },
}, { label: '诊疗', value: 3 },
{ { label: '耗材', value: 4 },
label: '耗材', { label: '会诊', value: 5 },
value: 4, { label: '手术', value: 6 },
}, ];
{ });
label: '会诊',
value: 5,
},
{
label: '全部',
value: '',
},
]);
// 根据类型值获取显示标签,避免非编辑态出现空标签 // 根据类型值获取显示标签,避免非编辑态出现空标签
const mapAdviceTypeLabel = (type) => { const mapAdviceTypeLabel = (type) => {
@@ -2394,6 +2386,8 @@ function handleSave(prescriptionId) {
saveAdviceType = 1; // 中成药前端2 -> 后端1 saveAdviceType = 1; // 中成药前端2 -> 后端1
} else if (item.adviceType == 5) { } else if (item.adviceType == 5) {
saveAdviceType = 3; // 会诊前端5 -> 后端3诊疗类 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 // 🔧 Bug Fix: Validate and fix NaN values before sending to backend
@@ -2403,6 +2397,21 @@ function handleSave(prescriptionId) {
console.warn('Fixed NaN totalPrice for item:', item.adviceName); console.warn('Fixed NaN totalPrice for item:', item.adviceName);
} }
// 🔧 BugFix#318: 从 parsedContent 提取标准医嘱字段,排除手术特有字段
const standardFields = [
'accountId', 'chargeItemId', 'conditionDefinitionId', 'conditionId',
'contentJson', 'definitionDetailId', 'definitionId', 'diagnosisName',
'dosageInstruction', 'effectiveOrgId', 'encounterDiagnosisId',
'encounterId', 'lotNumber', 'patientId', 'practitionerId',
'prescriptionNo', 'skinTestFlag', 'unitPrice', 'volume', 'ybClassEnum'
];
let filteredContent = {};
standardFields.forEach(field => {
if (parsedContent[field] !== undefined) {
filteredContent[field] = parsedContent[field];
}
});
// 构造请求参数 // 构造请求参数
// 🔧 Bug Fix: 确保库存匹配成功的关键字段 // 🔧 Bug Fix: 确保库存匹配成功的关键字段
// 耗材使用 adm_device_definition 表 // 耗材使用 adm_device_definition 表
@@ -2427,10 +2436,12 @@ function handleSave(prescriptionId) {
}); });
return { return {
...parsedContent, ...filteredContent, // 🔧 BugFix#318: 使用过滤后的字段,排除手术特有字段
adviceType: saveAdviceType, // 使用转换后的类型 adviceType: saveAdviceType, // 使用转换后的类型
requestId: item.requestId, requestId: item.requestId,
dbOpType: '1', dbOpType: item.requestId ? '2' : '1', // 🔧 BugFix: 根据requestId判断是新增还是修改
encounterId: item.encounterId || props.patientInfo.encounterId, // 🔧 BugFix: 确保encounterId
patientId: item.patientId || props.patientInfo.patientId, // 🔧 BugFix: 确保patientId
groupId: item.groupId, groupId: item.groupId,
uniqueKey: undefined, uniqueKey: undefined,
// 使用转换后的数量和单位 // 使用转换后的数量和单位
@@ -2723,28 +2734,32 @@ function handleSaveSign(row, index, prescriptionId) {
formRef.validate((valid) => { formRef.validate((valid) => {
if (valid) { if (valid) {
if (row.adviceType != 2) { // 🔧 BugFix#318: 手术类型(adviceType=6)不需要检查绑定耗材/药品
if (row.adviceType != 2 && row.adviceType != 6) {
// 1:用法绑东西 2:诊疗绑东西 // 1:用法绑东西 2:诊疗绑东西
let typeCode = row.adviceType == 1 ? '1' : '2'; let typeCode = row.adviceType == 1 ? '1' : '2';
// 用法字典值/诊疗定义id // 用法字典值/诊疗定义id
let itemNo = row.adviceType == 1 ? row.methodCode : row.adviceDefinitionId; let itemNo = row.adviceType == 1 ? row.methodCode : row.adviceDefinitionId;
getBindDevice({ typeCode: typeCode, itemNo: itemNo }).then((res) => { // 🔧 确保 itemNo 有值才调用接口
if (res.data.length == 0) { if (itemNo) {
return; getBindDevice({ typeCode: typeCode, itemNo: itemNo }).then((res) => {
} if (res.data.length == 0) {
// 是否需要打开弹窗 return;
let openBindDialog = localStorage.getItem('doctor' + userStore.id);
if (!JSON.parse(openBindDialog)) {
proxy.$refs['orderBindInfoRef'].open(res.data);
} else {
// 如果弹窗不提示带出的项目,自动带出
// 如果有未签发的项目,并且当前的项目没有带出过绑定项目,则自动带出
if (!bindMethod.value[itemNo]) {
handleOrderBindInfo(res.data, row.methodCode);
bindMethod.value[itemNo] = true;
} }
} // 是否需要打开弹窗
}); let openBindDialog = localStorage.getItem('doctor' + userStore.id);
if (!JSON.parse(openBindDialog)) {
proxy.$refs['orderBindInfoRef'].open(res.data);
} else {
// 如果弹窗不提示带出的项目,自动带出
// 如果有未签发的项目,并且当前的项目没有带出过绑定项目,则自动带出
if (!bindMethod.value[itemNo]) {
handleOrderBindInfo(res.data, row.methodCode);
bindMethod.value[itemNo] = true;
}
}
});
}
} }
row.isEdit = false; row.isEdit = false;
isAdding.value = false; isAdding.value = false;
@@ -2766,15 +2781,20 @@ function handleSaveSign(row, index, prescriptionId) {
row.conditionId = conditionId.value; row.conditionId = conditionId.value;
// 处理总量为小单位情况,需要把单价也保存成小单位的 // 处理总量为小单位情况,需要把单价也保存成小单位的
if (row.unitCodeList.find((item) => item.value == row.unitCode).type == 'unit') { // 🔧 BugFix#318: 手术类型(adviceType=6)可能没有unitCodeList需要判断
if (row.adviceType != 3) { if (row.unitCodeList && row.unitCodeList.length > 0) {
row.unitPrice = row.unitTempPrice; const foundUnit = row.unitCodeList.find((item) => item.value == row.unitCode);
if (foundUnit && foundUnit.type == 'unit') {
if (row.adviceType != 3) {
row.unitPrice = row.unitTempPrice;
}
} else {
const minUnitItem = row.unitCodeList.find((item) => item.value == row.minUnitCode);
if (minUnitItem) {
row.unitCode_dictText = minUnitItem.label;
}
row.unitPrice = row.minUnitPrice;
} }
} else {
row.unitCode_dictText = row.unitCodeList.find(
(item) => item.value == row.minUnitCode
).label;
row.unitPrice = row.minUnitPrice;
} }
row.conditionDefinitionId = conditionDefinitionId.value; row.conditionDefinitionId = conditionDefinitionId.value;
row.encounterDiagnosisId = encounterDiagnosisId.value; row.encounterDiagnosisId = encounterDiagnosisId.value;
@@ -2956,8 +2976,27 @@ function handleSaveBatch(prescriptionId) {
saveAdviceType = 1; // 中成药前端2 -> 后端1 saveAdviceType = 1; // 中成药前端2 -> 后端1
} else if (item.adviceType == 5) { } else if (item.adviceType == 5) {
saveAdviceType = 3; // 会诊前端5 -> 后端3诊疗类 saveAdviceType = 3; // 会诊前端5 -> 后端3诊疗类
} else if (item.adviceType == 6) {
saveAdviceType = 6; // 🔧 BugFix#318: 手术类型保持为6
} }
// 🔧 BugFix#318: 过滤掉手术特有字段,只保留标准医嘱字段
const standardItemFields = [
'adviceDefinitionId', 'adviceName', 'adviceTableName', 'adviceType',
'basedOnId', 'chargeItemId', 'chargeStatus', 'conditionDefinitionId',
'conditionId', 'contentJson', 'dose', 'doseUnitCode', 'encounterDiagnosisId',
'encounterId', 'groupId', 'injectFlag', 'lotNumber', 'methodCode', 'partPercent',
'patientId', 'positionId', 'positionName', 'prescriptionNo', 'quantity', 'rateCode',
'requestId', 'skinTestFlag', 'sortNumber', 'statusEnum', 'totalPrice',
'unitCode', 'unitPrice', 'volume', 'ybClassEnum'
];
let filteredItem = {};
standardItemFields.forEach(field => {
if (item[field] !== undefined) {
filteredItem[field] = item[field];
}
});
// 构造 contentJson (保持前端UI原始数据) // 构造 contentJson (保持前端UI原始数据)
const itemToSave = { const itemToSave = {
...item, ...item,
@@ -3003,7 +3042,7 @@ function handleSaveBatch(prescriptionId) {
}); });
return { return {
...item, ...filteredItem, // 🔧 BugFix#318: 使用过滤后的字段
patientId: props.patientInfo.patientId, patientId: props.patientInfo.patientId,
encounterId: props.patientInfo.encounterId, encounterId: props.patientInfo.encounterId,
adviceType: saveAdviceType, adviceType: saveAdviceType,

View File

@@ -371,7 +371,7 @@
<div style="display: flex; align-items: center; margin-bottom: 16px; gap: 16px"> <div style="display: flex; align-items: center; margin-bottom: 16px; gap: 16px">
<span style="font-size: 16px; font-weight: 600"> <span style="font-size: 16px; font-weight: 600">
{{ row.adviceName }} {{ row.adviceName }}
{{ row.unitPrice ? Number(row.unitPrice).toFixed(2) + '/次' : '-' + '元' }} {{ row.unitPrice ? ' -' + Number(row.unitPrice).toFixed(2) + '' : ' -元' }}
</span> </span>
<div class="form-group"> <div class="form-group">
<el-form-item <el-form-item

View File

@@ -426,38 +426,35 @@ const inputRefs = ref({}); // 存储输入框实例
const requiredProps = ref([]); // 存储必填项 prop 顺序 const requiredProps = ref([]); // 存储必填项 prop 顺序
const totalAmount = ref(0); const totalAmount = ref(0);
const therapyEnum = ref(''); const therapyEnum = ref('');
const { method_code, unit_code, rate_code, distribution_category_code } = proxy.useDict( const { method_code, unit_code, rate_code, distribution_category_code, drord_doctor_type } = proxy.useDict(
'method_code', 'method_code',
'unit_code', 'unit_code',
'rate_code', 'rate_code',
'distribution_category_code' 'distribution_category_code',
'drord_doctor_type'
); );
const openDrawer = ref(false); const openDrawer = ref(false);
const orderClassCode = ref(''); const orderClassCode = ref('');
const orderStatus = ref(''); const orderStatus = ref('');
// 医嘱类型 // 医嘱类型 - 使用 drord_doctor_type 字典
const adviceTypeList = ref([ const adviceTypeList = computed(() => {
{ // 如果字典已加载,使用字典数据(过滤掉全部选项)
label: '西药中成药', if (drord_doctor_type.value && drord_doctor_type.value.length > 0) {
value: 1, const list = drord_doctor_type.value.map(item => ({
}, label: item.label,
// { value: parseInt(item.value) || item.value
// label: '耗材', }));
// value: 2, // 添加全部选项
// }, return [...list, { label: '全部', value: '' }];
{ }
label: '诊疗', // 默认返回值
value: 3, return [
}, { label: '西药中成药', value: 1 },
{ { label: '诊疗', value: 3 },
label: '手术', { label: '手术', value: 6 },
value: 4, { label: '全部', value: '' },
}, ];
{ });
label: '全部',
value: '',
},
]);
// 医嘱状态 // 医嘱状态
const statusOption = [ const statusOption = [
{ {

View File

@@ -250,12 +250,15 @@
</template> </template>
<script setup> <script setup>
import {computed, onMounted, reactive, ref, watch} from 'vue'; import {computed, getCurrentInstance, onMounted, reactive, ref, watch} from 'vue';
import {ElMessage} from 'element-plus'; import {ElMessage} from 'element-plus';
import {formatDateStr} from '@/utils/index'; import {formatDateStr} from '@/utils/index';
import {getAdviceBaseInfo, getDiseaseTreatmentInitLoc, getOrgList} from './api.js'; import {getAdviceBaseInfo, getDiseaseTreatmentInitLoc, getOrgList} from './api.js';
import useUserStore from '@/store/modules/user'; import useUserStore from '@/store/modules/user';
const { proxy } = getCurrentInstance();
const { drord_doctor_type } = proxy.useDict('drord_doctor_type');
// Props定义 // Props定义
const props = defineProps({ const props = defineProps({
visible: { visible: {
@@ -280,11 +283,26 @@ const dialogVisible = computed({
get: () => props.visible, get: () => props.visible,
set: (value) => emit('update:visible', value), set: (value) => emit('update:visible', value),
}); });
const adviceTypeList = ref([ // 使用 drord_doctor_type 字典
{ label: '耗材', value: 2 }, const adviceTypeList = computed(() => {
{ label: '诊疗', value: 3 }, if (drord_doctor_type.value && drord_doctor_type.value.length > 0) {
{ label: '全部', value: '' }, // 只保留耗材(4)和诊疗(3)类型,并添加全部选项
]); const filtered = drord_doctor_type.value.filter(item => {
const val = parseInt(item.value);
return val === 3 || val === 4;
}).map(item => ({
label: item.label,
value: parseInt(item.value)
}));
return [...filtered, { label: '全部', value: '' }];
}
// 默认值
return [
{ label: '耗材', value: 4 },
{ label: '诊疗', value: 3 },
{ label: '全部', value: '' },
];
});
const adviceType = ref(''); const adviceType = ref('');
const feeItemsList = ref([]); const feeItemsList = ref([]);
const executeTime = ref(''); const executeTime = ref('');