diff --git a/openhis-ui-vue3/src/views/maintainSystem/Inspection/index.vue b/openhis-ui-vue3/src/views/maintainSystem/Inspection/index.vue index b9946031..1819c81f 100644 --- a/openhis-ui-vue3/src/views/maintainSystem/Inspection/index.vue +++ b/openhis-ui-vue3/src/views/maintainSystem/Inspection/index.vue @@ -268,14 +268,14 @@ @@ -1160,18 +1160,33 @@ const handleEditRow = (row) => { // 初始化行内属性 if (!row.subItemOptions) row.subItemOptions = []; - row.loadingSubItems = false; - // 回显名称 + // 预加载费用套餐列表(确保下拉框能显示名称而不是ID) + if (feePackages.value.length === 0) { + getFeePackages(); + } + + // 如果已有子项ID但选项列表为空,且有大类ID,则主动加载子类列表 + if (row.inspectionTypeId && row.subItemOptions.length === 0) { + row.loadingSubItems = true; + fetchInspectionTypesRequest({ parentId: row.inspectionTypeId }).then(res => { + let subData = []; + if (res.code === 200) { + if (res.data && Array.isArray(res.data)) subData = res.data; + else if (res.data && res.data.rows) subData = res.data.rows; + else if (res.data && res.data.data && Array.isArray(res.data.data)) subData = res.data.data; + } + row.subItemOptions = subData; + }).finally(() => { + row.loadingSubItems = false; + }); + } + + // 回显检验大类名称 if (row.inspectionTypeId && !row.inspectionTypeName) { const p = parentTypeOptions.value.find(i => i.id === row.inspectionTypeId); if (p) row.inspectionTypeName = p.name; } - - if (row.subItemId && row.subItemOptions.length > 0) { - const s = row.subItemOptions.find(i => i.id === row.subItemId); - if (s) row.subItemName = s.name; - } }; onMounted(() => { @@ -1292,15 +1307,15 @@ const loadObservationItems = async (resetPage = false) => { code: item.busNo || '', name: item.name || '', testType: item.inspectionTypeId_dictText || item.testType || '', - inspectionTypeId: item.inspectionTypeId || null, + inspectionTypeId: item.inspectionTypeId ? Number(item.inspectionTypeId) : null, package: item.packageName || '', - feePackageId: item.feePackageId || null, + feePackageId: item.feePackageId ? String(item.feePackageId) : null, sampleType: item.specimenCode || '', amount: parseFloat(item.retailPrice || 0), sortOrder: item.sortOrder || null, serviceRange: item.serviceRange || '全部', subItemName: item.subItemName || '', - subItemId: item.subItemId || null, + subItemId: item.subItemId ? Number(item.subItemId) : null, remark: item.descriptionText || '', status: true })); @@ -1466,7 +1481,7 @@ let addingItem = false; const addPackageItem = () => { if (addingItem) return; // 防止重复调用 addingItem = true; - + const newItem = { name: '', dosage: '', @@ -1482,7 +1497,7 @@ const addPackageItem = () => { origin: '' }; packageItems.value.push(newItem); - + // 延迟重置标志位,确保不会影响其他操作 setTimeout(() => { addingItem = false; @@ -1509,23 +1524,23 @@ const deletePackageItem = (index) => { const updateItemAmount = (item) => { // 计算项目原价金额 const originalAmount = (item.quantity || 1) * (item.unitPrice || 0.00); - + // 应用折扣到项目金额 let discountedAmount = originalAmount; if (discount.value && !isNaN(parseFloat(discount.value))) { const discountRate = parseFloat(discount.value) / 100; discountedAmount = originalAmount * (1 - discountRate); } - + // 更新项目金额 item.amount = parseFloat(discountedAmount.toFixed(2)); - + // 基于折扣后的金额计算服务费 item.serviceFee = calculateItemServiceFee(item); - + // 更新项目总金额 updateItemTotalAmount(item); - + // 重新计算套餐金额和服务费 calculateAmounts(); }; @@ -1581,7 +1596,7 @@ const cancelEditItem = (index) => { // 计算单个项目的服务费(基于折扣后的金额) const calculateItemServiceFee = (item) => { if (!generateServiceFee.value) return 0; - + // 服务费是项目折扣后金额的10% return parseFloat((item.amount * 0.1).toFixed(2)); }; @@ -1596,7 +1611,7 @@ const redistributeServiceFee = () => { }); return; } - + // 重新计算每个项目的服务费 packageItems.value.forEach(item => { item.serviceFee = calculateItemServiceFee(item); @@ -1610,27 +1625,27 @@ const calculateAmounts = () => { packageItems.value.forEach(item => { // 计算项目原价金额 const originalAmount = (item.quantity || 1) * (item.unitPrice || 0.00); - + // 应用折扣到项目金额 let discountedAmount = originalAmount; if (discount.value && !isNaN(parseFloat(discount.value))) { const discountRate = parseFloat(discount.value) / 100; discountedAmount = originalAmount * (1 - discountRate); } - + // 更新项目金额 item.amount = parseFloat(discountedAmount.toFixed(2)); }); - + // 重新分配所有项目的服务费 redistributeServiceFee(); - + // 计算套餐总金额(基于项目的折扣后金额) const totalAmount = packageItems.value.reduce((sum, item) => sum + (item.amount || 0), 0); - + // 更新套餐金额 packageAmount.value = parseFloat(totalAmount.toFixed(2)); - + // 计算套餐总服务费 if (generateServiceFee.value) { serviceFee.value = parseFloat(packageItems.value.reduce((sum, item) => sum + (item.serviceFee || 0), 0).toFixed(2)); @@ -1724,12 +1739,12 @@ const handleConfirm = (row) => { ElMessage.warning('请选择执行科室'); return; } - + // 注意:编码唯一性由后端统一校验;这里不做硬编码拦截(避免误判) - + // 去除code字段的前后空格,确保唯一性验证准确 submitData.code = submitData.code.trim(); - + // 区分新增和更新操作:使用 temp_ 前缀的临时ID判断,避免时间戳阈值在不同年份失效 if (isTempId(row.id)) { // 新增的临时ID // 处理 parentId:如果是子类且 parentId 是临时ID,需要先找到父类的真实 id @@ -1740,7 +1755,7 @@ const handleConfirm = (row) => { const parts = parseCodeParts(submitData.code); if (parts.subRaw) { const parentCode = parts.mainRaw; - const parent = tableData.value.find(r => + const parent = tableData.value.find(r => !isTempId(r.id) && (r?.code ?? '').toString().trim() === parentCode ); if (parent) { @@ -1751,11 +1766,11 @@ const handleConfirm = (row) => { } } } - + // 新增数据时移除临时ID,让后端自动生成主键 const { id, ...newData } = submitData; newData.parentId = finalParentId || null; // 确保 parentId 正确设置(大类为 null,子类为父类 id) - + addInspectionType(newData).then(response => { ElMessage.success('新增成功'); getInspectionTypeList(); @@ -1778,7 +1793,7 @@ const handleConfirm = (row) => { } }); } - + editingRowId.value = null; }; @@ -1826,7 +1841,7 @@ const handleAdd = (row, index) => { tableData.value.splice(index + 1, 0, newRow); editingRowId.value = newRow.id; }; - + const handleDelete = (id) => { ElMessageBox.confirm('确定要删除该检验类型吗?', '提示', { confirmButtonText: '确定', @@ -1881,19 +1896,47 @@ const addNewItem = () => { editingRowId.value = newItem.id; }; -const editItem = (item) => { +const editItem = async (item) => { if (editingRowId.value === item.id) { - // 如果当前行已经在编辑模式,点击编辑按钮则保存 saveItem(item); - } else { - // 否则进入编辑模式 - editingRowId.value = item.id; + return; } + + // 初始化行内属性 + if (!item.subItemOptions) item.subItemOptions = []; + + // 并行预加载:费用套餐列表 + 当前行的子类列表 + const tasks = []; + + if (feePackages.value.length === 0) { + tasks.push(getFeePackages()); + } + + if (item.inspectionTypeId && item.subItemOptions.length === 0) { + item.loadingSubItems = true; + tasks.push( + fetchInspectionTypesRequest({ parentId: item.inspectionTypeId }).then(res => { + let subData = []; + if (res.code === 200) { + if (res.data && Array.isArray(res.data)) subData = res.data; + else if (res.data && res.data.rows) subData = res.data.rows; + else if (res.data && res.data.data && Array.isArray(res.data.data)) subData = res.data.data; + } + item.subItemOptions = subData; + }).finally(() => { + item.loadingSubItems = false; + }) + ); + } + + // 等所有数据加载完再切换编辑态,确保 el-select 能回显正确文字 + await Promise.all(tasks); + editingRowId.value = item.id; }; const updateAmountFromPackage = (item) => { if (item.feePackageId) { - const selectedPackage = feePackages.value.find(pkg => pkg.id === item.feePackageId); + const selectedPackage = feePackages.value.find(pkg => String(pkg.id) === String(item.feePackageId)); if (selectedPackage) { // 套餐总金额 = 套餐金额 + 服务费 const packageAmount = parseFloat(selectedPackage.packageAmount || 0); @@ -1911,42 +1954,42 @@ const saveItem = async (item) => { ElMessage.error('小类编码不能为空'); return; } - + // 验证小类编码格式:4位数字 const codeRegex = /^\d{4}$/; if (!codeRegex.test(item.code.trim())) { ElMessage.error('小类编码必须为4位数字'); return; } - + if (!item.name || item.name.trim() === '') { ElMessage.error('小类项目名称不能为空'); return; } - + if (!item.inspectionTypeId) { ElMessage.error('检验类型不能为空'); return; } - + if (!item.sampleType) { ElMessage.error('样本类型不能为空'); return; } - + // 验证小类编码唯一性 - const isDuplicate = inspectionItems.value.some(i => + const isDuplicate = inspectionItems.value.some(i => i.id !== item.id && i.code.trim() === item.code.trim() ); - + if (isDuplicate) { ElMessage.error('小类编码已存在'); return; } - + // 从费用套餐获取金额 updateAmountFromPackage(item); - + try { // 准备提交给后端的数据 const submitData = { @@ -1964,7 +2007,7 @@ const saveItem = async (item) => { sortOrder: item.sortOrder ? parseInt(item.sortOrder) : null, serviceRange: item.serviceRange || '全部' }; - + // 判断是新增还是更新 if (typeof item.id === 'number') { // 临时ID(数字类型),新增 const response = await addDiagnosisTreatment(submitData); @@ -1984,7 +2027,7 @@ const saveItem = async (item) => { ElMessage.error(response.msg || '更新失败'); } } - + editingRowId.value = null; } catch (error) { console.error('保存检验项目失败:', error); @@ -2048,19 +2091,19 @@ const exportTable = () => { // 创建Blob对象 const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); - + // 创建下载链接 const link = document.createElement('a'); const url = URL.createObjectURL(blob); link.setAttribute('href', url); link.setAttribute('download', `检验项目导出_${new Date().toISOString().split('T')[0]}.csv`); link.style.visibility = 'hidden'; - + // 添加到DOM并触发下载 document.body.appendChild(link); link.click(); document.body.removeChild(link); - + ElMessage.success('导出成功'); };