From bcc2f490a0264144417beff881e4114e730a8d46 Mon Sep 17 00:00:00 2001 From: yangkexiang <1677036288@qq.com> Date: Thu, 21 May 2026 17:40:26 +0800 Subject: [PATCH] bug550\556569 --- .../web/doctorstation/dto/AdviceBaseDto.java | 2 + .../impl/MedicineSummaryAppServiceImpl.java | 25 +- .../examination/examinationApplication.vue | 735 +++++++++++++----- .../inspection/inspectionApplication.vue | 41 +- .../prescription/prescriptionHistory.vue | 33 +- .../prescription/prescriptionInfo.vue | 18 +- .../prescription/prescriptionlist.vue | 50 +- .../components/MedicationSummary.vue | 34 +- .../inpatientDoctor/home/components/api.js | 3 +- .../applicationForm/bloodTransfusion.vue | 410 ++++++++-- .../components/prescriptionList.vue | 45 ++ .../components/summaryMedicineList.vue | 37 +- .../components/prescriptionList.vue | 79 ++ .../medicalOrderExecution/index.vue | 2 +- .../components/prescriptionList.vue | 39 +- .../medicalOrderProofread/index.vue | 8 +- 16 files changed, 1230 insertions(+), 331 deletions(-) diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/dto/AdviceBaseDto.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/dto/AdviceBaseDto.java index 47a075ea..ea553b79 100755 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/dto/AdviceBaseDto.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/dto/AdviceBaseDto.java @@ -198,8 +198,10 @@ public class AdviceBaseDto { /** * 所属科室 */ + @Dict(dictTable = "adm_organization", dictCode = "id", dictText = "name") @JsonSerialize(using = ToStringSerializer.class) private Long orgId; + private String orgId_dictText; /** * 所在位置 diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inhospitalnursestation/appservice/impl/MedicineSummaryAppServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inhospitalnursestation/appservice/impl/MedicineSummaryAppServiceImpl.java index 5240add0..7776ec6b 100755 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inhospitalnursestation/appservice/impl/MedicineSummaryAppServiceImpl.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inhospitalnursestation/appservice/impl/MedicineSummaryAppServiceImpl.java @@ -78,12 +78,10 @@ public class MedicineSummaryAppServiceImpl implements IMedicineSummaryAppService .map(notPerformedReason -> new DispenseInitDto.NotPerformedReasonOption(notPerformedReason.getValue(), notPerformedReason.getInfo())) .collect(Collectors.toList()); - // 发药状态 + // 发药状态(汇总单:待配药→已提交,已发放→已发药) List dispenseStatusOptions = new ArrayList<>(); - dispenseStatusOptions.add(new DispenseStatusOption(DispenseStatus.PREPARATION.getValue(), - DispenseStatus.PREPARATION.getInfo())); - dispenseStatusOptions.add(new DispenseStatusOption(DispenseStatus.COMPLETED.getValue(), - DispenseStatus.COMPLETED.getInfo())); + dispenseStatusOptions.add(new DispenseStatusOption(DispenseStatus.PREPARATION.getValue(), "已提交")); + dispenseStatusOptions.add(new DispenseStatusOption(DispenseStatus.COMPLETED.getValue(), "已发药")); initDto.setNotPerformedReasonOptions(notPerformedReasonOptions).setDispenseStatusOptions(dispenseStatusOptions); return R.ok(initDto); @@ -161,8 +159,8 @@ public class MedicineSummaryAppServiceImpl implements IMedicineSummaryAppService new Page<>(pageNo, pageSize), queryWrapper, DispenseStatus.COMPLETED.getValue(), DispenseStatus.PREPARATION.getValue(), SupplyType.SUMMARY_DISPENSE.getValue()); medicineSummaryFormPage.getRecords().forEach(e -> { - // 发药状态 - e.setStatusEnum_enumText(EnumUtils.getInfoByValue(DispenseStatus.class, e.getStatusEnum())); + // 发药状态(汇总单展示文案) + e.setStatusEnum_enumText(getSummaryFormStatusText(e.getStatusEnum())); }); return R.ok(medicineSummaryFormPage); } @@ -292,4 +290,17 @@ public class MedicineSummaryAppServiceImpl implements IMedicineSummaryAppService } return R.ok(MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[]{"取消"})); } + + /** + * 汇总发药单状态展示文案(药品医嘱状态映射表:汇总申请→已提交,发药→已发药) + */ + private String getSummaryFormStatusText(Integer statusEnum) { + if (DispenseStatus.PREPARATION.getValue().equals(statusEnum)) { + return "已提交"; + } + if (DispenseStatus.COMPLETED.getValue().equals(statusEnum)) { + return "已发药"; + } + return EnumUtils.getInfoByValue(DispenseStatus.class, statusEnum); + } } diff --git a/openhis-ui-vue3/src/views/doctorstation/components/examination/examinationApplication.vue b/openhis-ui-vue3/src/views/doctorstation/components/examination/examinationApplication.vue index 4b30f229..17e7ede7 100755 --- a/openhis-ui-vue3/src/views/doctorstation/components/examination/examinationApplication.vue +++ b/openhis-ui-vue3/src/views/doctorstation/components/examination/examinationApplication.vue @@ -397,117 +397,165 @@ - +
已选择:
-
+ +
@@ -539,6 +587,8 @@ const dictLoading = ref(false); const activeDetailTab = ref('applyForm'); const applicationList = ref([]); const selectedItems = ref([]); +const selectedMethods = ref([]); +const methodPickerExpanded = ref(true); // Bug #499: 查询过滤状态 const searchForm = reactive({ @@ -705,13 +755,25 @@ function getDisplayItemName(item) { return String(item?.name || '').replace(/^套餐[::\-\s]*/, ''); } -function getSelectedItemAmount(item) { - const itemPrice = Number(item?.price || 0); - const methodPrice = Number(item?.selectedMethod?.packagePrice || 0); - if (!hasMethodPackage(item) || isSamePackage(item)) { - return itemPrice; +/** 检查方法展示:避免与后端文案重复出现「(方法)(方法)」 */ +function formatExamMethodCaption(name) { + const raw = String(name || '').trim(); + if (!raw) return ''; + if (/^\(方法\)/.test(raw) || /^(方法)/.test(raw)) { + return raw; } - return itemPrice + methodPrice; + return `(方法) ${raw}`; +} + +/** 已选方法纯文本(用于标题下级展示,不包含「勾选」前缀,去掉后端自带的 (方法) 前缀) */ +function getDisplaySelectedMethodName(item) { + const raw = String(item?.selectedMethod?.name || '').trim(); + if (!raw) return ''; + return raw.replace(/^\(方法\)\s*/, '').replace(/^(方法)\s*/, '').trim(); +} + +function getSelectedItemAmount(item) { + return Number(item?.price || 0); } function parsePackageDetailsPayload(res) { @@ -843,6 +905,19 @@ const currentActiveCategory = ref(null); // Bug #500: 记录当前激活的分 const allMethods = ref([]); +const activeCategory = computed(() => { + const id = activeNames.value; + if (id === '' || id === null || id === undefined) return null; + return categoryList.value.find((cat) => String(cat.typeId) === String(id)) || null; +}); + +const activeCategoryName = computed(() => activeCategory.value?.typeName || activeCategory.value?.categoryName || ''); + +const methodsForActiveCategory = computed(() => { + const arr = activeCategory.value?.methods; + return Array.isArray(arr) ? arr : []; +}); + // ====== 科室下拉(来源:科室管理)====== const orgLoading = ref(false); const orgOptions = ref([]); // { label, value } @@ -953,6 +1028,44 @@ const availableMethods = computed(() => { return allMethods.value; }); +function isStandaloneMethodSelected(method) { + return selectedMethods.value.some((m) => String(m.id) === String(method?.id)); +} + +function getDisplayMethodName(method) { + const raw = String(method?.name || '').trim(); + if (!raw) return ''; + return raw.replace(/^\(方法\)\s*/, '').replace(/^(方法)\s*/, '').trim(); +} + +function hasStandaloneMethodPackage(method) { + return !!(method?.packageId || method?.packageName); +} + +function getStandaloneMethodPackageDetailsList(method) { + return Array.isArray(method?.packageDetails) ? method.packageDetails : []; +} + +async function onStandaloneMethodChange(checked, method) { + if (!method) return; + if (checked) { + if (!isStandaloneMethodSelected(method)) { + selectedMethods.value.push({ + ...method, + expanded: false, + packageLoading: false, + packageDetails: [] + }); + } + } else { + const idx = selectedMethods.value.findIndex((m) => String(m.id) === String(method.id)); + if (idx > -1) selectedMethods.value.splice(idx, 1); + } + updateMethodDisplay(); + await nextTick(); + form.totalAmount = totalAmountCalc.value; +} + // 当可选方法列表改变时,如果当前选中的方法不在新列表中,则清空 // #428: 分类展开时联动加载检查方法 // Bug #500: 使用 categoryLoadingSet 替代 dictLoading,避免切换分类时整个区域闪烁 @@ -996,6 +1109,8 @@ async function handleCategoryExpand(cat) { function handleCollapseChange(activeName) { // 始终记录当前激活的分类,确保 handleCategoryExpand 能正确忽略过期请求 currentActiveCategory.value = activeName || null; + // 底部「检查方法」勾选区默认展开,不因切换左侧分类而收起 + methodPickerExpanded.value = true; if (activeName) { // Bug #428修复: 直接从 categoryList(原始响应式数组)查找分类, @@ -1005,6 +1120,7 @@ function handleCollapseChange(activeName) { handleCategoryExpand(cat); // 异步加载,不 await } } + updateMethodDisplay(); } watch(availableMethods, (newMethods) => { @@ -1130,17 +1246,26 @@ const filteredCategoryList = computed(() => { // ====== 合计 ====== const totalAmountCalc = computed(() => { - const total = selectedItems.value.reduce((sum, item) => { + const itemTotal = selectedItems.value.reduce((sum, item) => { const effectivePrice = getSelectedItemAmount(item); return sum + (effectivePrice * (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); }); // 监听已选项:自动更新申检部位 watch(selectedItems, () => { form.inspectionArea = selectedItems.value.map(i => i.name).join('+'); - form.isCharged = selectedItems.value.length > 0 ? 1 : 0; + form.isCharged = selectedItems.value.length > 0 || selectedMethods.value.length > 0 ? 1 : 0; +}, { deep: true }); + +watch(selectedMethods, () => { + form.isCharged = selectedItems.value.length > 0 || selectedMethods.value.length > 0 ? 1 : 0; + updateMethodDisplay(); }, { deep: true }); // 监听患者变化 @@ -1231,6 +1356,7 @@ function handleAdd() { selectedMethodDisplay: '' // Bug #384修复: 重置检查方法显示 }); selectedItems.value = []; + selectedMethods.value = []; resetCategoryChecked(); activeDetailTab.value = 'applyForm'; // 自动加载临床诊断 @@ -1244,22 +1370,27 @@ function handleSave() { ElMessage.warning('请至少选择一个检查明细项目'); return; } - // 检查每个项目是否已选择检查方法 - const itemsWithoutMethod = selectedItems.value.filter(item => !item.selectedMethod); - if (itemsWithoutMethod.length > 0) { - const names = itemsWithoutMethod.map(item => item.name).join('、'); - ElMessage.warning(`以下项目未选择检查方法:${names},请在右侧勾选后再保存`); + if (selectedMethods.value.length === 0) { + ElMessage.warning('请选择检查方法'); return; } // 从已选项目推导检查类型编码(取第一个项目的 checkType,如 CT / ECG / GI) const firstCheckType = selectedItems.value[0]?.checkType || 'unknown'; form.examTypeCode = firstCheckType; + form.totalAmount = totalAmountCalc.value; + const primaryMethod = selectedMethods.value[0] || null; const payload = { ...form, encounterId: props.patientInfo?.encounterId || null, patientIdNum: props.patientInfo?.patientId || null, + checkMethods: selectedMethods.value.map((method) => ({ + checkMethodId: method.id || null, + checkMethodName: method.name || null, + checkMethodCode: method.code || null, + checkMethodPackageName: method.packageName || null + })), items: selectedItems.value.map((item, index) => ({ itemCode: String(item.id), itemName: item.name, @@ -1269,10 +1400,10 @@ function handleSave() { itemStatus: 0, itemSeq: index + 1, // 检查方法信息 - checkMethodId: item.selectedMethod?.id || null, - checkMethodName: item.selectedMethod?.name || null, - checkMethodCode: item.selectedMethod?.code || null, - checkMethodPackageName: item.selectedMethod?.packageName || null // Bug #384修复: 保存套餐名称 + checkMethodId: primaryMethod?.id || null, + checkMethodName: primaryMethod?.name || null, + checkMethodCode: primaryMethod?.code || null, + checkMethodPackageName: primaryMethod?.packageName || null // Bug #384修复: 保存套餐名称 })) }; request({ @@ -1293,6 +1424,7 @@ function handleRowClick(row) { Object.assign(form, row); form.selectedMethodDisplay = ''; // Bug #384修复: 先清空,后面根据回充数据更新 selectedItems.value = []; + selectedMethods.value = []; activeDetailTab.value = 'applyForm'; request({ url: `/exam/apply/${row.applyNo}`, method: 'get' }).then(async res => { // 响应结构: Axios拦截器对code===200返回res.data(AjaxResult体) @@ -1317,8 +1449,9 @@ function handleRowClick(row) { methods: [], selectedMethod: null, expanded: false, - itemPackageExpanded: true, - methodPackageExpanded: true, + projectFoldExpanded: false, + methodFoldExpanded: false, + methodPackageExpanded: false, packageDetailsLoading: false, isPackage: false, packageId: null, @@ -1362,7 +1495,21 @@ function handleRowClick(row) { return item; })); // Bug #408修复: 确保明细数据正确加载到selectedItems + const methodMap = new Map(); + for (const item of itemsWithMethods) { + if (item.selectedMethod && !methodMap.has(String(item.selectedMethod.id))) { + methodMap.set(String(item.selectedMethod.id), { + ...item.selectedMethod, + expanded: false, + packageLoading: false, + packageDetails: [] + }); + } + item.selectedMethod = null; + item.methodPackageDetails = []; + } selectedItems.value = itemsWithMethods; + selectedMethods.value = Array.from(methodMap.values()); // 加载套餐明细(单个失败不影响其他项目和明细显示) for (const it of selectedItems.value) { if (hasItemPackage(it)) { @@ -1372,14 +1519,17 @@ function handleRowClick(row) { console.error('加载套餐明细失败:', it.name, e); } } - if (hasMethodPackage(it) && !isSamePackage(it)) { + it.methodFoldExpanded = false; + syncItemExpandedFlag(it); + } + for (const method of selectedMethods.value) { + if (hasStandaloneMethodPackage(method)) { try { - await loadMethodPackageDetails(it, it.selectedMethod); + await loadStandaloneMethodPackageDetails(method); } catch (e) { - console.error('加载检查方法套餐明细失败:', it.name, e); + console.error('加载检查方法套餐明细失败:', method.name, e); } } - it.expanded = shouldShowPackageBody(it); } syncCategoryChecked(); // Bug #384修复: 回充后更新检查方法显示 @@ -1465,8 +1615,9 @@ async function handleItemSelect(checked, item, cat) { methods: methods, selectedMethod: null, expanded: false, - itemPackageExpanded: true, - methodPackageExpanded: true, + projectFoldExpanded: false, + methodFoldExpanded: false, + methodPackageExpanded: false, isPackage: !!(item.packageId || item.packageName), packageName: item.packageName || null, packageDetailsLoading: false, @@ -1475,19 +1626,13 @@ async function handleItemSelect(checked, item, cat) { }; selectedItems.value.push(newRow); // 必须用数组里的响应式行,不能继续改局部 newRow:push 后列表内是 proxy,改 raw 对象不会触发右侧卡片更新(会一直卡在「加载中」) - const row = selectedItems.value[selectedItems.value.length - 1]; - // 勾选项目只加入项目列表,检查方法由用户在“检查方法”区域手动选择 - row.selectedMethod = null; + const rowJustAdded = selectedItems.value[selectedItems.value.length - 1]; + syncItemExpandedFlag(rowJustAdded); + updateMethodDisplay(); - - // 新勾选项目后默认展开,直接展示检查方法状态和套餐明细 - row.expanded = true; - row.itemPackageExpanded = true; - row.methodPackageExpanded = true; - if (hasItemPackage(row)) { - await loadPackageDetailsForItem(row); - } + await nextTick(); + form.totalAmount = totalAmountCalc.value; // 自动回填执行科室:按检查项目类型 → 检查类型管理里配置的执行科室 if (selectedItems.value.length === 1 && cat?.performDeptName) { @@ -1508,25 +1653,16 @@ async function handleItemSelect(checked, item, cat) { // Bug #382 修复:移除自动切换页签逻辑,保持当前页签状态 } -// Bug #384修复 + #426修复: 展开/收起项目卡片 -async function toggleItemExpand(item) { - item.expanded = !item.expanded; - if (item.expanded && hasItemPackage(item) && getPackageDetailsList(item).length === 0 && !item.packageDetailsLoading) { - await loadPackageDetailsForItem(item); - } - if ( - item.expanded && - shouldShowMethodPackageBody(item) && - getMethodPackageDetailsList(item).length === 0 && - !item.methodPackageLoading - ) { - await loadMethodPackageDetails(item, item.selectedMethod); - } +/** expanded 与各折叠条保持一致(明细表等仍可依赖 expanded) */ +function syncItemExpandedFlag(row) { + if (!row) return; + row.expanded = !!(row.projectFoldExpanded || row.methodFoldExpanded); } -async function toggleItemPackageExpand(item) { - item.itemPackageExpanded = !item.itemPackageExpanded; - if (item.itemPackageExpanded && getPackageDetailsList(item).length === 0 && !item.packageDetailsLoading) { +async function toggleProjectFold(item) { + item.projectFoldExpanded = !item.projectFoldExpanded; + syncItemExpandedFlag(item); + if (item.projectFoldExpanded && hasItemPackage(item) && getPackageDetailsList(item).length === 0 && !item.packageDetailsLoading) { await loadPackageDetailsForItem(item); } } @@ -1543,25 +1679,64 @@ async function toggleMethodPackageExpand(item) { } } -// Bug #384修复: 勾选框选择检查方法(单选逻辑) -async function selectMethodCheckbox(checked, item, method) { - if (checked) { - item.selectedMethod = method; - item.expanded = true; - item.methodPackageExpanded = true; - // 动态加载该方法对应的套餐明细 - await loadMethodPackageDetails(item, method); - } else { - item.selectedMethod = null; - item.methodPackageDetails = []; +async function toggleSelectedMethodFold(method) { + method.expanded = !method.expanded; + if ( + method.expanded && + hasStandaloneMethodPackage(method) && + getStandaloneMethodPackageDetailsList(method).length === 0 && + !method.packageLoading + ) { + await loadStandaloneMethodPackageDetails(method); } - // 联动更新表单检查方法显示字段 - updateMethodDisplay(); +} - // #430: 套餐金额实时同步到申请单 - nextTick(() => { - form.totalAmount = totalAmountCalc.value; - }); +function handleRemoveMethod(idx) { + selectedMethods.value.splice(idx, 1); + updateMethodDisplay(); +} + +async function loadStandaloneMethodPackageDetails(method) { + method.packageLoading = true; + method.packageDetails = []; + try { + let packageId = method.packageId; + if (!packageId && !method.packageName) { + method.packageLoading = false; + return; + } + if (!packageId && method.packageName) { + const pkgRes = await listCheckPackage({ packageName: method.packageName }); + let packages = pkgRes?.data || []; + if (!Array.isArray(packages)) { + packages = packages.records || packages.data || []; + } + if (packages.length === 0) { + method.packageLoading = false; + return; + } + packageId = packages[0].id; + method.packageId = packageId; + } + const detailRes = await request({ + url: `/system/check-type/package/${packageId}/details`, + method: 'get' + }); + method.packageDetails = parsePackageDetailsPayload(detailRes).map(d => ({ + id: d.id, + name: d.name || d.itemName, + quantity: d.quantity || 1, + unit: d.unit || '次', + price: d.price ?? d.unitPrice ?? d.itemPrice ?? 0, + amount: d.amount || d.total || 0, + checked: true + })); + } catch (err) { + console.error('加载检查方法套餐明细失败:', err); + method.packageDetails = []; + } finally { + method.packageLoading = false; + } } // 根据检查方法的packageName加载对应的套餐明细 @@ -1623,9 +1798,12 @@ async function onDetailMethodChange(row, val) { } row.methodPackageDetails = []; updateMethodDisplay(); - row.expanded = shouldShowPackageBody(row); - row.itemPackageExpanded = true; - row.methodPackageExpanded = true; + const open = shouldShowPackageBody(row); + row.expanded = open; + row.projectFoldExpanded = shouldShowItemPackageBody(row) && open; + row.methodFoldExpanded = shouldShowMethodPackageBody(row) && open; + row.methodPackageExpanded = false; + syncItemExpandedFlag(row); if (hasItemPackage(row)) { await loadPackageDetailsForItem(row); } @@ -1637,26 +1815,13 @@ async function onDetailMethodChange(row, val) { }); } -// Bug #384修复: 更新检查方法显示字段(联动) +// Bug #384修复: 更新检查方法显示字段(取自独立已选检查方法) function updateMethodDisplay() { - // 找到第一个有选中检查方法的项目 - const itemWithMethod = selectedItems.value.find(item => item.selectedMethod); - if (itemWithMethod?.selectedMethod) { - form.selectedMethodDisplay = itemWithMethod.selectedMethod.name; // 显示检查方法名称,不显示套餐名称 - } else { - form.selectedMethodDisplay = ''; + if (selectedMethods.value.length > 0) { + form.selectedMethodDisplay = selectedMethods.value.map((method) => method.name).join('、'); + return; } -} - -// 选择检查方法 -function selectMethod(item, method) { - if (item.selectedMethod?.id === method.id) { - item.selectedMethod = null; - } else { - item.selectedMethod = method; - } - // Bug #384修复: 联动更新表单检查方法显示字段 - updateMethodDisplay(); + form.selectedMethodDisplay = ''; } function handleRemoveItem(idx, item) { @@ -1670,7 +1835,7 @@ function handleRemoveItem(idx, item) { if (selectedItems.value.length === 0) { form.performDeptCode = ''; form.examTypeCode = ''; - form.selectedMethodDisplay = ''; // Bug #384修复: 清空检查方法显示 + updateMethodDisplay(); } else { // Bug #384修复: 移除后重新计算检查方法显示 updateMethodDisplay(); @@ -1976,39 +2141,167 @@ defineExpose({ getList }); overflow: hidden; } -.selected-item-card .card-header { - display: flex; - align-items: center; - padding: 10px 10px; - cursor: pointer; - gap: 8px; - background: linear-gradient(180deg, #f8fafc 0%, #f0f4f8 100%); - border-bottom: 1px solid transparent; +/* 项目上 / 方法下:各自独立下拉条 */ +.fold-strip { + border-bottom: 1px solid var(--el-border-color-lighter); } -.selected-item-card .card-header:hover { +.fold-strip:last-child { + border-bottom: none; +} + +.fold-strip-header { + display: flex; + align-items: flex-start; + gap: 8px; + padding: 10px 10px; + cursor: pointer; + background: linear-gradient(180deg, #f8fafc 0%, #f0f4f8 100%); +} + +.fold-strip-header:hover { background: linear-gradient(180deg, #ecf5ff 0%, #e3eef8 100%); } -.selected-item-card.is-expanded .card-header { - border-bottom-color: #ebeef5; +.fold-strip-method.is-method-target .fold-strip-header { + background: linear-gradient(180deg, #e8f3ff 0%, #dceaff 100%); } -.card-name { +.fold-chevron { + font-size: 14px; + color: #909399; + transition: transform 0.2s ease; + flex-shrink: 0; + margin-top: 2px; + transform: rotate(-90deg); +} + +.fold-chevron.open { + transform: rotate(0deg); +} + +.fold-header-main { flex: 1; min-width: 0; + display: flex; + flex-direction: column; + gap: 4px; +} + +.fold-kicker { + font-size: 11px; + font-weight: 600; + color: #909399; + letter-spacing: 0.03em; +} + +.fold-title { font-size: 13px; - font-weight: 500; + font-weight: 600; color: #303133; - line-height: 1.4; + line-height: 1.35; word-break: break-word; } -.card-price { +.fold-title-plain { + font-weight: 500; + color: #606266; +} + +.line-clamp-2 { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.fold-price-strong { font-size: 13px; color: #409eff; font-weight: 600; flex-shrink: 0; + margin-top: 2px; +} + +.fold-price-strong.warn { + color: #e6a23c; +} + +.fold-strip-body { + background: #fafbfc; + padding: 0 10px 10px 36px; + border-top: 1px dashed var(--el-border-color-lighter); +} + +.fold-package-wrap { + padding-top: 6px; +} + +.fold-strip-muted { + font-size: 12px; + color: #909399; + padding: 10px 0 4px; +} + +.selected-global-method-picker { + flex-shrink: 0; + margin-top: 8px; + border-radius: 6px; + border: 1px solid #e4e7ed; + background: #fff; + overflow: hidden; +} + +.method-picker-collapse-title { + display: flex; + align-items: center; + gap: 10px; + padding: 10px 10px; + cursor: pointer; + background: #fff; +} + +.method-picker-collapse-title:hover { + background: #f5f7fa; +} + +.method-picker-title-main { + flex: 1; + min-width: 0; + font-size: 13px; + font-weight: 600; + color: #303133; +} + +.global-method-picker-scope { + font-size: 12px; + color: #909399; + flex-shrink: 0; +} + +.method-picker-arrow { + font-size: 14px; + color: #909399; + transition: transform 0.2s ease; + flex-shrink: 0; + transform: rotate(-90deg); +} + +.method-picker-arrow.expanded { + transform: rotate(0deg); +} + +.global-method-picker-list { + display: flex; + flex-direction: column; + gap: 0; + padding: 6px 8px 8px; + border-top: 1px solid #ebeef5; +} + +.method-picker-row { + padding: 6px 4px; + border-radius: 3px; } .expand-icon { @@ -2058,11 +2351,6 @@ defineExpose({ getList }); white-space: nowrap; } -/* 展开区域 */ -.selected-card-body { - background: #fafbfc; -} - .selected-card-section { padding: 10px; border-bottom: 1px solid #ebeef5; @@ -2112,6 +2400,49 @@ defineExpose({ getList }); color: #409eff; } +/* 收起态:仅展示折叠箭头,不显示「套餐明细」等冗余标题 */ +.package-toggle-minimal { + display: flex; + align-items: center; + justify-content: flex-start; + padding: 8px 10px; + font-size: 12px; + color: var(--el-text-color-secondary); + cursor: pointer; + border-bottom: 1px dashed #e4e7ed; + background: #fafafa; +} + +.package-toggle-minimal:hover { + color: #409eff; + background: #f5f9ff; +} + + + +.nested-empty-text { + font-size: 12px; + color: var(--el-text-color-placeholder); + padding-left: 2px; +} + +.nested-label-row { + margin-bottom: 6px; +} + +.nested-label { + font-size: 11px; + font-weight: 600; + color: var(--el-text-color-secondary); + letter-spacing: 0.03em; +} + + + +.method-label-inner { + font-size: 13px; +} + .package-details-loading, .package-details-empty { padding: 12px 10px; diff --git a/openhis-ui-vue3/src/views/doctorstation/components/inspection/inspectionApplication.vue b/openhis-ui-vue3/src/views/doctorstation/components/inspection/inspectionApplication.vue index 90bad516..f1afc46f 100755 --- a/openhis-ui-vue3/src/views/doctorstation/components/inspection/inspectionApplication.vue +++ b/openhis-ui-vue3/src/views/doctorstation/components/inspection/inspectionApplication.vue @@ -179,8 +179,8 @@ type="datetime" placeholder="选择执行时间" size="small" - format="YYYY-MM-DD HH:mm:ss" - value-format="YYYY-MM-DD HH:mm:ss" + format="YYYY-MM-DD HH:mm" + value-format="YYYY-MM-DD HH:mm" style="width: 100%" /> @@ -445,7 +445,6 @@ > - {{ scope.row.dose ? scope.row.dose + ' ' + scope.row.doseUnitCode_dictText : '' }} + {{ + scope.row.dose + ? scope.row.dose + + (scope.row.doseUnitCode_dictText && + String(scope.row.doseUnitCode_dictText).toLowerCase() !== 'null' + ? ' ' + scope.row.doseUnitCode_dictText + : '') + : '' + }} @@ -703,10 +711,10 @@ @change="calculateTotalPrice(scope.row, scope.$index)" @input="calculateTotalPrice(scope.row, scope.$index)" /> - {{ scope.row.unitCode_dictText }} + {{ resolveTotalQuantityUnit(scope.row) }} - {{ scope.row.quantity ? scope.row.quantity + ' ' + scope.row.unitCode_dictText : '' }} + {{ formatTotalQuantityWithUnit(scope.row) }} @@ -917,6 +925,39 @@ const unitMap = ref({ minUnit: 'minUnit', unit: 'unit', }); + +/** 解析总量单位文案(无字典时:诊疗/手术/检查默认「次」,耗材默认「个」) */ +const resolveTotalQuantityUnit = (row) => { + if (row == null) return ''; + const fromDict = + row.unitCode_dictText ?? row.minUnitCode_dictText ?? row.unitCodeName; + let unitStr = + fromDict != null && String(fromDict).trim() !== '' + && String(fromDict).toLowerCase() !== 'null' + ? String(fromDict).trim() + : ''; + if (!unitStr) { + const t = Number(row.adviceType); + // drord_doctor_type: 3=诊疗 4=耗材 5=会诊 6=手术;23=检查(特殊) + // 注意:2=中成药(药品),不可用「次」作为默认单位 + if (t === 3 || t === 6 || t === 23 || t === 5) { + unitStr = '次'; + } else if (t === 4) { + unitStr = '个'; + } + } + return unitStr; +}; + +/** 总量列展示:避免 unitCode_dictText 为空时显示「1 null」 */ +const formatTotalQuantityWithUnit = (row) => { + if (row == null) return ''; + const q = row.quantity; + if (q === undefined || q === null || q === '') return ''; + const unitStr = resolveTotalQuantityUnit(row); + return unitStr ? `${q} ${unitStr}` : String(q); +}; + const buttonDisabled = computed(() => { return !props.patientInfo; }); @@ -2714,7 +2755,8 @@ function handleEmrTreatment() { treatment += '诊疗[' + (index + 1) + ']' + ' '; treatment += item.adviceName + ' '; if (item.quantity) { - treatment += '数量:' + item.quantity + item.unitCode_dictText + ' '; + const u = resolveTotalQuantityUnit(item); + treatment += '数量:' + item.quantity + (u ? ' ' + u : '') + ' '; } treatment += '频次:' + item.rateCode_dictText + ' '; if (item.methodCode_dictText) { diff --git a/openhis-ui-vue3/src/views/drug/inpatientMedicationDispensing/components/MedicationSummary.vue b/openhis-ui-vue3/src/views/drug/inpatientMedicationDispensing/components/MedicationSummary.vue index 9c6fec5a..4cf8b944 100755 --- a/openhis-ui-vue3/src/views/drug/inpatientMedicationDispensing/components/MedicationSummary.vue +++ b/openhis-ui-vue3/src/views/drug/inpatientMedicationDispensing/components/MedicationSummary.vue @@ -58,7 +58,11 @@ - + + +