Bug #384: 检查方法联动功能完善,增加套餐价格查询和项目卡片展开选择

Bug #386: 检验申请删除时同步删除关联收费项目
  Bug #382: 选择项目后保持当前页签状态
  Bug #380,381: 临床诊断获取主诊断字段名修正
  Bug #387: 套餐项目回充默认展开并自动加载明细
This commit is contained in:
wangjian963
2026-04-21 10:18:26 +08:00
parent 5ab4650c4e
commit 994ffcb8b8
6 changed files with 513 additions and 184 deletions

View File

@@ -45,35 +45,10 @@
class="inspection-table"
highlight-current-row
row-key="applicationId"
:expand-row-keys="expandedRowKeys"
@expand-change="handleExpandChange"
@selection-change="handleSelectionChange"
@current-change="handleRowClick"
@cell-click="handleCellClick"
>
<el-table-column type="expand" width="50" align="center" header-align="center">
<template #default="scope">
<div v-if="scope.row.children && scope.row.children.length > 0" class="expand-content">
<el-table :data="scope.row.children" border size="small" style="width: 100%">
<el-table-column label="明细项目" prop="itemName" min-width="150" />
<el-table-column label="样本类型" prop="sampleType" width="100" />
<el-table-column label="单位" prop="unit" width="80" />
<el-table-column label="单价" prop="itemPrice" width="80" align="right">
<template #default="itemScope">
¥{{ formatAmount(itemScope.row.itemPrice) }}
</template>
</el-table-column>
<el-table-column label="数量" prop="itemQty" width="80" align="center" />
<el-table-column label="金额" prop="itemAmount" width="80" align="right">
<template #default="itemScope">
¥{{ formatAmount(itemScope.row.itemAmount) }}
</template>
</el-table-column>
</el-table>
</div>
<div v-else class="expand-empty">无明细项目</div>
</template>
</el-table-column>
<el-table-column type="selection" width="55" align="center" header-align="center" />
<el-table-column label="申请 ID" prop="applicationId" width="80" align="center" header-align="center">
<template #default="scope">
@@ -83,14 +58,7 @@
<el-table-column label="申请单号" prop="applyNo" min-width="160" align="center" header-align="center" />
<el-table-column label="检验项目" prop="itemName" min-width="170px" align="center" header-align="center">
<template #default="scope">
<span v-if="scope.row.hasChildren" style="color: #409EFF; cursor: pointer" @click.stop="toggleExpand(scope.row)">
<el-icon style="vertical-align: middle; margin-right: 4px">
<Right v-if="!isExpanded(scope.row.applicationId)" />
<Bottom v-else />
</el-icon>
{{ scope.row.itemName }}
</span>
<span v-else>{{ scope.row.itemName }}</span>
<span>{{ scope.row.itemName }}</span>
</template>
</el-table-column>
<el-table-column label="申请医生" prop="applyDocName" width="120" align="center" header-align="center" />
@@ -645,7 +613,7 @@
<script setup>
import {onMounted, onUnmounted, reactive, ref, watch, computed, getCurrentInstance} from 'vue'
import {ElMessage, ElMessageBox} from 'element-plus'
import { DocumentChecked, Plus, Document, Printer, Delete, Check, Loading, Right, Bottom } from '@element-plus/icons-vue'
import { DocumentChecked, Plus, Document, Printer, Delete, Check, Loading } from '@element-plus/icons-vue'
import {
deleteInspectionApplication, getApplyList,
saveInspectionApplication,
@@ -792,53 +760,39 @@ const loading = ref(false)
const saving = ref(false) // 保存状态
const total = ref(0)
const leftActiveTab = ref('application')
const expandedRowKeys = ref([])
const isExpanded = (applicationId) => {
return expandedRowKeys.value.includes(applicationId)
}
const toggleExpand = async (row) => {
const applicationId = row.applicationId
const isCurrentlyExpanded = isExpanded(applicationId)
if (isCurrentlyExpanded) {
// 收起
expandedRowKeys.value = expandedRowKeys.value.filter(id => id !== applicationId)
} else {
// 展开 - 先检查是否需要加载明细数据
if (row.hasChildren && (!row.children || row.children.length === 0)) {
// 加载套餐明细
await loadPackageDetails(row)
}
expandedRowKeys.value = [...expandedRowKeys.value, applicationId]
}
}
const handleExpandChange = (row, expandedRows) => {
expandedRowKeys.value = expandedRows.map(r => r.applicationId)
}
const loadPackageDetails = async (row) => {
/**
* 加载套餐明细(公共函数)
* @param {string|number} packageId 套餐ID
* @returns {Promise<Array>} 明细数组
*/
const fetchPackageDetails = async (packageId) => {
if (!packageId) return []
try {
const packageId = row.feePackageId || row.packageId
if (!packageId) return
const res = await getInspectionPackageDetails(packageId)
if (res.code === 200 && res.data) {
row.children = res.data.map(detail => ({
itemId: detail.detailId || detail.id || detail.itemId,
itemName: detail.itemName || detail.name,
sampleType: detail.sampleType || '',
unit: detail.unit || '',
itemPrice: detail.unitPrice || detail.itemPrice || detail.price || 0,
itemQty: detail.quantity || detail.itemQty || detail.qty || 1,
itemAmount: (detail.unitPrice || detail.itemPrice || 0) * (detail.quantity || detail.itemQty || 1)
}))
return res.data.map(detail => {
const detailId = detail.detailId || detail.id || detail.itemId
const qty = detail.quantity || detail.itemQty || detail.qty || 1
const price = detail.unitPrice || detail.itemPrice || detail.price || 0
return {
detailId: detailId,
itemId: detailId, // 兼容表格 row-key
itemName: detail.itemName || detail.name,
sampleType: detail.sampleType || '',
unit: detail.unit || '',
quantity: qty,
itemQty: qty, // 兼容表格"总量"列
unitPrice: price,
itemPrice: price, // 兼容表格"单价"列
itemAmount: price * qty
}
})
}
return []
} catch (error) {
console.error('加载套餐明细失败:', error)
row.children = []
return []
}
}
@@ -847,35 +801,9 @@ const loadPackageDetailsForTable = async (row, treeNode, resolve) => {
resolve([])
return
}
try {
const packageId = row.feePackageId || row.packageId
if (!packageId) {
resolve([])
return
}
const res = await getInspectionPackageDetails(packageId)
if (res.code === 200 && res.data) {
// 构建明细数据结构
// BugFix: 后端返回字段为 unitPrice 和 quantity需正确映射
const children = res.data.map(detail => ({
itemId: detail.detailId || detail.id || detail.itemId,
itemName: detail.itemName || detail.name,
sampleType: detail.sampleType || '',
unit: detail.unit || '',
itemPrice: detail.unitPrice || detail.itemPrice || detail.price || 0,
itemQty: detail.quantity || detail.itemQty || detail.qty || 1,
itemAmount: (detail.unitPrice || detail.itemPrice || 0) * (detail.quantity || detail.itemQty || 1)
}))
resolve(children)
} else {
resolve([])
}
} catch (error) {
console.error('加载套餐明细失败:', error)
resolve([])
}
const packageId = row.feePackageId || row.packageId
const children = await fetchPackageDetails(packageId)
resolve(children)
}
const togglePackageExpand = async (item) => {
@@ -885,27 +813,9 @@ const togglePackageExpand = async (item) => {
if (item.expanded && (!item.children || item.children.length === 0)) {
item.loading = true
try {
const packageId = item.feePackageId || item.packageId
if (packageId) {
const res = await getInspectionPackageDetails(packageId)
if (res.code === 200 && res.data) {
item.children = res.data.map(detail => ({
detailId: detail.detailId || detail.id || detail.itemId,
itemName: detail.itemName || detail.name,
unit: detail.unit || '',
quantity: detail.quantity || detail.itemQty || detail.qty || 1,
unitPrice: detail.unitPrice || detail.itemPrice || detail.price || 0,
itemPrice: detail.unitPrice || detail.itemPrice || detail.price || 0
}))
}
}
} catch (error) {
console.error('加载套餐明细失败:', error)
item.children = []
} finally {
item.loading = false
}
const packageId = item.feePackageId || item.packageId
item.children = await fetchPackageDetails(packageId)
item.loading = false
}
}
@@ -1822,6 +1732,26 @@ const clearAllSelected = () => {
selectedInspectionItems.value = []
}
// Bug #387修复: 同步分类勾选状态
const syncCategoryChecked = () => {
// 重置所有分类项目的勾选状态
inspectionCategories.value.forEach(category => {
category.items.forEach(item => {
item.checked = false
})
})
// 获取已选项目的ID集合
const ids = new Set(selectedInspectionItems.value.map(s => s.itemId))
// 同步勾选状态
for (const cat of inspectionCategories.value) {
for (const item of cat.items) {
if (ids.has(item.itemId)) {
item.checked = true
}
}
}
}
// 分页大小改变
const handleSizeChange = (size) => {
queryParams.pageSize = size
@@ -1977,6 +1907,7 @@ const loadApplicationToForm = async (row) => {
if (detail.labApplyItemList && detail.labApplyItemList.length > 0) {
// Bug #326修复: 直接使用后端返回的数据,不再从本地缓存查找匹配项
// 后端已返回完整关联信息activityId、feePackageId、inspectionTypeId、sampleType、unit
// Bug #387修复: 套餐项目默认展开,并自动加载明细
selectedInspectionItems.value = detail.labApplyItemList.map(item => {
const itemId = item.activityId || item.itemId || item.id || Math.random().toString(36).substring(2, 11)
const isPackage = item.feePackageId != null || item.itemName?.includes('套餐')
@@ -1995,12 +1926,25 @@ const loadApplicationToForm = async (row) => {
feePackageId: item.feePackageId || null,
activityId: item.activityId || itemId,
inspectionTypeId: item.inspectionTypeId || null,
expanded: false,
expanded: isPackage, // Bug #387: 套餐默认展开
children: [],
childrenLoaded: false,
childrenLoaded: !isPackage, // Bug #387: 套餐需加载明细
loading: false
}
})
// Bug #387修复: 自动加载套餐明细
for (const pkgItem of selectedInspectionItems.value) {
if (pkgItem.isPackage && pkgItem.feePackageId) {
pkgItem.loading = true
pkgItem.children = await fetchPackageDetails(pkgItem.feePackageId)
pkgItem.childrenLoaded = true
pkgItem.loading = false
}
}
// Bug #387修复: 同步分类勾选状态
syncCategoryChecked()
} else if (detail.inspectionItem || detail.itemName) {
// 如果只有项目名称,尝试从本地分类中查找匹配项
const itemNames = (detail.inspectionItem || detail.itemName).split(/[+,]/)