({
+ ...child,
+ id: `${row.id}-${child.id || child.itemCode}`,
+ name: child.name || child.itemName,
+ unit: child.unit || '次',
+ price: child.price ?? child.unitPrice ?? child.itemPrice ?? 0,
+ quantity: row.quantity || 1,
+ isPackageDetail: true,
+ hasChildren: false
+ }));
+ resolve(children);
+ } catch (err) {
+ console.error('加载套餐明细失败:', err);
+ resolve([]);
+ }
+ return;
+ }
+
+ // 2. 如果当前行有选择的检查方法,则展开为“项目费”和“方法费”两行
+ if (row.selectedMethod) {
+ const projectPrice = Number(row.price || 0);
+ const methodPrice = Number(row.selectedMethod.packagePrice ?? row.selectedMethod.price ?? 0);
+ const children = [
+ {
+ id: `${row.id}-project-fee`,
+ name: `项目费: ${row.name}`,
+ applyPart: '-',
+ selectedMethod: null,
+ unit: row.unit || '次',
+ quantity: row.quantity || 1,
+ price: projectPrice,
+ checkType: row.checkType || '',
+ isPackageDetail: true,
+ isProjectFeeChild: true,
+ packageId: row.packageId,
+ packageName: row.packageName,
+ hasChildren: !!(row.packageId || row.packageName)
+ },
+ {
+ id: `${row.id}-method-fee`,
+ name: `方法费: ${row.selectedMethod.name}`,
+ applyPart: '-',
+ selectedMethod: null,
+ unit: '次',
+ quantity: row.quantity || 1,
+ price: methodPrice,
+ checkType: row.checkType || '',
+ isPackageDetail: true,
+ hasChildren: false
+ }
+ ];
+ resolve(children);
+ return;
+ }
+
+ // 3. 回退逻辑:无方法但有套餐,则直接加载套餐明细作为子节点
let packageId = row.packageId;
if (!packageId && row.packageName) {
try {
@@ -1122,7 +1187,10 @@ function getDisplaySelectedMethodName(item) {
}
function getSelectedItemAmount(item) {
- return Number(item?.price || 0);
+ const itemPrice = Number(item?.price || 0);
+ const method = item?.selectedMethod || (item?.isPackageDetail ? null : selectedMethods.value[0]) || null;
+ const methodPrice = method ? Number(method.packagePrice ?? method.price ?? 0) : 0;
+ return itemPrice + methodPrice;
}
function parsePackageDetailsPayload(res) {
@@ -1601,14 +1669,12 @@ const filteredCategoryList = computed(() => {
// ====== 合计 ======
const totalAmountCalc = computed(() => {
- const itemTotal = selectedItems.value.reduce((sum, item) => {
- const effectivePrice = getSelectedItemAmount(item);
- return sum + (effectivePrice * (item.quantity || 1));
+ const total = selectedItems.value.reduce((sum, item) => {
+ const basePrice = Number(item.price || 0);
+ const method = item.selectedMethod || selectedMethods.value[0] || null;
+ const methodPrice = method ? Number(method.packagePrice ?? method.price ?? 0) : 0;
+ return sum + ((basePrice + methodPrice) * (item.quantity || 1));
}, 0);
- const methodTotal = selectedMethods.value.reduce((sum, method) => {
- return sum + Number(method?.packagePrice ?? method?.price ?? 0);
- }, 0);
- const total = itemTotal + methodTotal;
return total.toFixed(2);
});
@@ -1621,6 +1687,19 @@ watch(selectedItems, () => {
watch(selectedMethods, () => {
form.isCharged = selectedItems.value.length > 0 || selectedMethods.value.length > 0 ? 1 : 0;
updateMethodDisplay();
+
+ // 同步更新已选项目的选中检查方法及 hasChildren
+ const primary = selectedMethods.value[0] || null;
+ selectedItems.value.forEach(item => {
+ if (primary) {
+ const matched = item.methods.find(m => String(m.id) === String(primary.id));
+ item.selectedMethod = matched || primary;
+ item.hasChildren = true;
+ } else {
+ item.selectedMethod = null;
+ item.hasChildren = !!(item.packageId || item.packageName);
+ }
+ });
}, { deep: true });
// 监听患者变化
@@ -1746,20 +1825,25 @@ function handleSave() {
checkMethodCode: method.code || null,
checkMethodPackageName: method.packageName || null
})),
- items: selectedItems.value.map((item, index) => ({
- itemCode: String(item.id),
- itemName: item.name,
- bodyPartCode: item.checkType || 'unknown',
- itemFee: getSelectedItemAmount(item),
- performDeptCode: form.performDeptCode || '',
- itemStatus: 0,
- itemSeq: index + 1,
- // 检查方法信息
- checkMethodId: primaryMethod?.id || null,
- checkMethodName: primaryMethod?.name || null,
- checkMethodCode: primaryMethod?.code || null,
- checkMethodPackageName: primaryMethod?.packageName || null // Bug #384修复: 保存套餐名称
- }))
+ items: selectedItems.value.map((item, index) => {
+ const itemMethod = item.selectedMethod || primaryMethod || null;
+ return {
+ itemCode: String(item.id),
+ itemName: item.name,
+ bodyPartCode: item.checkType || 'unknown',
+ itemFee: Number(item.price || 0), // 仅发送项目基础价格给后端,防止后端重复累加
+ performDeptCode: form.performDeptCode || '',
+ itemStatus: 0,
+ itemSeq: index + 1,
+ // 检查方法代码 (与后端 DTO ExamApplyItemDto.examMethodCode 一致,用于后端计费和数据库存储)
+ examMethodCode: itemMethod?.code || null,
+ // 优先使用当前明细行的“检查方法”,无则使用主选择的方法
+ checkMethodId: itemMethod?.id || null,
+ checkMethodName: itemMethod?.name || null,
+ checkMethodCode: itemMethod?.code || null,
+ checkMethodPackageName: itemMethod?.packageName || null
+ };
+ })
};
request({
url: '/exam/apply',
@@ -1833,14 +1917,30 @@ function handleRowClick(row) {
serviceFee: md.serviceFee || null
}));
// 回充已保存的检查方法
- if (m.checkMethodId) {
- item.selectedMethod = item.methods.find(md => String(md.id) === String(m.checkMethodId)) || null;
- if (item.selectedMethod?.packageId) {
- item.hasChildren = true; // #426修复
+ const methodCode = m.examMethodCode || m.checkMethodCode;
+ const methodId = m.checkMethodId;
+ if (methodCode || methodId) {
+ const found = item.methods.find(md =>
+ (methodCode && String(md.code) === String(methodCode)) ||
+ (methodId && String(md.id) === String(methodId))
+ );
+ if (found) {
+ item.selectedMethod = found;
+ } else {
+ item.selectedMethod = {
+ id: methodId || null,
+ name: m.checkMethodName || '',
+ code: methodCode || '',
+ price: 0,
+ packageName: m.checkMethodPackageName || '',
+ packageId: null,
+ packagePrice: null,
+ serviceFee: null
+ };
}
}
- if (item.selectedMethod?.packageId) {
- item.hasChildren = true; // #426修复
+ if (item.selectedMethod || item.packageId || item.packageName) {
+ item.hasChildren = true;
}
}
} catch (err) {
@@ -1860,7 +1960,6 @@ function handleRowClick(row) {
packageDetails: []
});
}
- item.selectedMethod = null;
item.methodPackageDetails = [];
}
selectedItems.value = itemsWithMethods;
@@ -1963,6 +2062,8 @@ async function handleItemSelect(checked, item, cat) {
}
}
+ const primaryMethod = selectedMethods.value[0] || null;
+ const matchedMethod = primaryMethod ? (methods.find(m => String(m.id) === String(primaryMethod.id)) || primaryMethod) : null;
const newRow = {
id: item.id, name: item.name,
price: item.price, quantity: 1,
@@ -1973,7 +2074,7 @@ async function handleItemSelect(checked, item, cat) {
nationalCode: item.nationalCode || '',
checked: true,
methods: methods,
- selectedMethod: null,
+ selectedMethod: matchedMethod,
expanded: false,
projectFoldExpanded: false,
methodFoldExpanded: false,
@@ -1982,7 +2083,7 @@ async function handleItemSelect(checked, item, cat) {
packageName: item.packageName || null,
packageDetailsLoading: false,
packageId: item.packageId || null,
- hasChildren: !!(item.packageId || item.packageName) // #426修复: 树形表格懒加载展开标记,支持 packageName 解析
+ hasChildren: !!(item.packageId || item.packageName || matchedMethod)
};
selectedItems.value.push(newRow);
// 必须用数组里的响应式行,不能继续改局部 newRow:push 后列表内是 proxy,改 raw 对象不会触发右侧卡片更新(会一直卡在「加载中」)
@@ -2150,14 +2251,37 @@ async function loadMethodPackageDetails(item, method) {
}
}
-/** 检查明细表格中切换检查方法 */
async function onDetailMethodChange(row, val) {
row.selectedMethod = val || null;
- if (val?.packageId || val?.packageName) {
- row.hasChildren = true; // #426修复
+ row.hasChildren = !!(val || hasItemPackage(row));
+
+ // 同步全局已选的检查方法列表
+ if (val) {
+ const exists = selectedMethods.value.some(m => String(m.id) === String(val.id));
+ if (!exists) {
+ selectedMethods.value = [{
+ ...val,
+ expanded: false,
+ packageLoading: false,
+ packageDetails: []
+ }];
+ }
+ } else {
+ selectedMethods.value = [];
}
+
row.methodPackageDetails = [];
updateMethodDisplay();
+
+ // 若明细表已被展开,切换方法时刷新对应的子树节点
+ if (detailTableRef.value && typeof detailTableRef.value.reloadRowChilds === 'function') {
+ try {
+ detailTableRef.value.reloadRowChilds(row);
+ } catch (e) {
+ console.error('reloadRowChilds failed:', e);
+ }
+ }
+
const open = shouldShowPackageBody(row);
row.expanded = open;
row.projectFoldExpanded = shouldShowItemPackageBody(row) && open;
diff --git a/healthlink-his-ui/src/views/doctorstation/components/inspection/inspectionApplication.vue b/healthlink-his-ui/src/views/doctorstation/components/inspection/inspectionApplication.vue
index 751709daf..b43aea9d0 100755
--- a/healthlink-his-ui/src/views/doctorstation/components/inspection/inspectionApplication.vue
+++ b/healthlink-his-ui/src/views/doctorstation/components/inspection/inspectionApplication.vue
@@ -1,4 +1,4 @@
-
+
急
@@ -726,7 +726,7 @@
@@ -742,8 +742,6 @@
退费
@@ -758,8 +756,6 @@
执行
diff --git a/healthlink-his-ui/src/views/doctorstation/components/prescription/prescriptionlist.vue b/healthlink-his-ui/src/views/doctorstation/components/prescription/prescriptionlist.vue
index ba79d6f4d..4ced52886 100755
--- a/healthlink-his-ui/src/views/doctorstation/components/prescription/prescriptionlist.vue
+++ b/healthlink-his-ui/src/views/doctorstation/components/prescription/prescriptionlist.vue
@@ -1,4 +1,4 @@
-
+
皮试:
@@ -837,7 +837,7 @@
>
皮试:
@@ -1332,7 +1332,7 @@
@@ -1575,6 +1575,23 @@ const orderGroupLoaded = ref({
// 更新展开行的函数
const updateExpandOrder = (keys) => {
expandOrder.value = keys;
+ nextTick(() => {
+ if (prescriptionRef.value?.setRowExpand) {
+ // 折叠不需要展开的行
+ prescriptionList.value.forEach(row => {
+ if (!keys.includes(row.uniqueKey)) {
+ prescriptionRef.value.setRowExpand([row], false);
+ }
+ });
+ // 展开目标行
+ keys.forEach(key => {
+ const targetRow = prescriptionList.value.find(item => item.uniqueKey === key);
+ if (targetRow) {
+ prescriptionRef.value.setRowExpand([targetRow], true);
+ }
+ });
+ }
+ });
};
const stockList = ref([]);
const contractList = ref([]);
@@ -1760,14 +1777,19 @@ onBeforeUnmount(() => {
watch(
() => expandOrder.value,
(newValue) => {
- if (newValue.length > 0) {
+ if (newValue && newValue.length > 0) {
nextTick(() => {
const index = prescriptionList.value.findIndex((row) => row.uniqueKey === newValue[0]);
- const items = proxy.$refs['formRef' + index]?.$el?.querySelectorAll('[data-prop]');
- requiredProps.value = Array.from(items).map((item) => item.dataset.prop);
+ if (index !== -1) {
+ const formRef = proxy.$refs['formRef' + index];
+ const items = formRef?.$el?.querySelectorAll('[data-prop]') || formRef?.querySelectorAll?.('[data-prop]');
+ requiredProps.value = items ? Array.from(items).map((item) => item.dataset.prop) : [];
+ } else {
+ requiredProps.value = [];
+ }
});
} else {
- requiredProps.value = {};
+ requiredProps.value = [];
}
}
);
@@ -2567,6 +2589,16 @@ const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
* 选择药品回调
*/
function selectAdviceBase(key, row) {
+ console.log('[selectAdviceBase] Triggered with key:', key, 'row:', JSON.parse(JSON.stringify(row)));
+ // 确保 rowIndex 指向正确的行索引,避免 out of sync 或者未定义导致的报错
+ const targetIndex = prescriptionList.value.findIndex(item => item.uniqueKey === key);
+ console.log('[selectAdviceBase] Target index resolved:', targetIndex, 'Current rowIndex.value:', rowIndex.value);
+ if (targetIndex !== -1) {
+ rowIndex.value = targetIndex;
+ } else {
+ console.error('[selectAdviceBase] Target row not found in prescriptionList by uniqueKey!');
+ }
+
// 🔧 Bug Fix: 检查药品是否需要皮试,如果需要则弹出确认框
if (row.skinTestFlag == 1) {
ElMessageBox.confirm(`药品:${row.adviceName}需要做皮试,是否做皮试?`, '提示', {
@@ -2643,7 +2675,7 @@ function selectAdviceBase(key, row) {
// 确保在setValue之后再次设置showPopover为false,防止被覆盖
prescriptionList.value[rowIndex.value].showPopover = false;
- expandOrder.value = [key];
+ updateExpandOrder([key]);
// 自动聚焦到单次用量字段 - 使用 async/await 多次尝试
await nextTick();
@@ -4108,7 +4140,7 @@ async function setValue(row) {
if (row.adviceType != 3 && row.adviceType != 4 && row.adviceType != 5) {
// 🔧 Bug #144 补充修复:检查 inventoryList 是否存在,避免 undefined 错误
if (!row.inventoryList || row.inventoryList.length == 0) {
- expandOrder.value = [];
+ updateExpandOrder([]);
proxy.$modal.msgWarning(row.adviceName + '无库存');
return;
}
@@ -4229,6 +4261,9 @@ async function setValue(row) {
}
// 🔧 Bug #218 修复:最后统一同步组套字段(适用于所有类型)
syncGroupFields(row);
+
+ // 强制触发 Vue 数组响应式更新,并通知 vxe-table 重新加载数据
+ prescriptionList.value = [...prescriptionList.value];
}
// 选择组套 - 适配新版 OrderGroupDrawer 组件
diff --git a/healthlink-his-ui/src/views/doctorstation/components/tcm/tcmAdvice.vue b/healthlink-his-ui/src/views/doctorstation/components/tcm/tcmAdvice.vue
index f4e1ab69f..8cd916b4b 100755
--- a/healthlink-his-ui/src/views/doctorstation/components/tcm/tcmAdvice.vue
+++ b/healthlink-his-ui/src/views/doctorstation/components/tcm/tcmAdvice.vue
@@ -1,4 +1,4 @@
-
+
是否代煎:
{
};
// 当前行变化时更新索引
-const handleCurrentChange = (currentRow) => {
- currentIndex.value = filteredAdviceBaseList.value.findIndex((item) => item === currentRow);
- currentSelectRow.value = currentRow;
+const handleCurrentChange = ({ row }) => {
+ currentIndex.value = filteredAdviceBaseList.value.findIndex((item) => item === row);
+ currentSelectRow.value = row;
};
-function clickRow(row) {
- emit('selectAdviceBase', row);
+function clickRow({ row }) {
+ if (row) {
+ emit('selectAdviceBase', row);
+ }
}
defineExpose({
diff --git a/healthlink-his-ui/src/views/hospitalRecord/components/medicalRecordFirst.vue b/healthlink-his-ui/src/views/hospitalRecord/components/medicalRecordFirst.vue
index cb521d9e8..0ab31f8cb 100755
--- a/healthlink-his-ui/src/views/hospitalRecord/components/medicalRecordFirst.vue
+++ b/healthlink-his-ui/src/views/hospitalRecord/components/medicalRecordFirst.vue
@@ -1,4 +1,4 @@
-
+