diff --git a/openhis-ui-vue3/src/views/basicmanage/medicalOrderSet/components/MedicalOrderSetDialog.vue b/openhis-ui-vue3/src/views/basicmanage/medicalOrderSet/components/MedicalOrderSetDialog.vue index 1b48cada..1779b5e7 100644 --- a/openhis-ui-vue3/src/views/basicmanage/medicalOrderSet/components/MedicalOrderSetDialog.vue +++ b/openhis-ui-vue3/src/views/basicmanage/medicalOrderSet/components/MedicalOrderSetDialog.vue @@ -146,7 +146,7 @@ v-model="scope.row.doseQuantity" @input=" (value) => { - scope.row.dose = value / scope.row.unitConversionRatio; + scope.row.dose = value * scope.row.unitConversionRatio; } " /> @@ -164,7 +164,7 @@ v-model="scope.row.dose" @input=" (value) => { - scope.row.doseQuantity = value * scope.row.unitConversionRatio; + scope.row.doseQuantity = value / scope.row.unitConversionRatio; } " /> diff --git a/openhis-ui-vue3/src/views/basicmanage/medicalOrderSet/index.vue b/openhis-ui-vue3/src/views/basicmanage/medicalOrderSet/index.vue index bbcaffd7..99251607 100644 --- a/openhis-ui-vue3/src/views/basicmanage/medicalOrderSet/index.vue +++ b/openhis-ui-vue3/src/views/basicmanage/medicalOrderSet/index.vue @@ -227,7 +227,7 @@ v-model="scope.row.doseQuantity" @input=" (value) => { - scope.row.dose = value / scope.row.unitConversionRatio; + scope.row.dose = value * scope.row.unitConversionRatio; } " /> @@ -238,7 +238,7 @@ v-model="scope.row.dose" @input=" (value) => { - scope.row.doseQuantity = value * scope.row.unitConversionRatio; + scope.row.doseQuantity = value / scope.row.unitConversionRatio; } " /> diff --git a/openhis-ui-vue3/src/views/maintainSystem/Inspection/index.vue b/openhis-ui-vue3/src/views/maintainSystem/Inspection/index.vue index b9946031..21b02482 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 @@ @@ -488,7 +488,24 @@
卫生机构 - + + +
套餐金额 @@ -1006,7 +1023,83 @@ const handleFocus = () => { } */ }; +// 获取当前登录用户信息 +// --- 新增:存储租户/机构列表和当前选中的值 --- +const tenantOptions = ref([]); // 存储从后端获取的租户列表 +const selectedTenantId = ref(null); // 存储当前选中的租户ID +// --- 新增:控制租户列表加载状态 --- +const loadingTenant = ref(false); // 控制下拉框的加载状态 +const fetchTenantList = async () => { + + if (loadingTenant.value) return; // 防止重复请求 + loadingTenant.value = true; + + try { + + const response = await request({ + url: '/system/tenant/page', + method: 'get', + params: { + pageNum: 1, + pageSize: 100 + } + }); + + + + if (response.code === 200) { + let tenantData = []; + + // --- 关键修改:优先检查 records 字段 --- + if (response.data && response.data.records && Array.isArray(response.data.records)) { + tenantData = response.data.records; + + } else if (response.data && response.data.rows && Array.isArray(response.data.rows)) { + // 兼容旧的 rows 格式 + tenantData = response.data.rows; + + } else if (response.data && Array.isArray(response.data)) { + // 兼容最简单的数组格式 + tenantData = response.data; + + } else { + + tenantData = []; + } + + // 格式化数据以适应 el-select + tenantOptions.value = tenantData.map(item => ({ + value: item.id, + label: item.tenantName || item.name || item.orgName || String(item.id) || '未知机构' + })); + + // 如果仍未设置默认值且列表不为空,选择第一个 + if (!selectedTenantId.value && tenantOptions.value.length > 0) { + selectedTenantId.value = tenantOptions.value[0].value; + + } + } else { + + ElMessage.error(response.msg || '获取机构列表失败,请联系管理员'); + tenantOptions.value = []; + } + } catch (error) { + + ElMessage.error('网络异常或数据解析错误,请检查控制台日志'); + tenantOptions.value = []; + } finally { + // 确保无论成功还是失败都停止加载状态 + loadingTenant.value = false; + } + +}; +// 展开时若列表为空则加载数据 +const handleTenantVisibleChange = async (visible) => { + if (visible && tenantOptions.value.length === 0) { // 仅在展开且列表为空时加载 + await fetchTenantList(); + } +}; /** * 获取数据方法 * 这里不再接收搜索关键词,而是直接拉取所有启用的套餐 @@ -1061,10 +1154,6 @@ const handlePackageVisibleChange = (visible) => { // 可选:如果希望页面一打开就预加载一次,保留 onMounted // 如果希望完全由用户点击触发,可以注释掉 onMounted -onMounted(() => { - // getFeePackages(); -}); - // ============================== // 【修复】级联下拉框逻辑 (包含直接请求代码) @@ -1160,24 +1249,37 @@ 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(() => { - // ... 其他初始化代码 - loadParentTypes(); // <--- 确保这一行存在 - // ... + loadParentTypes(); }); @@ -1292,15 +1394,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 })); @@ -1319,8 +1421,8 @@ const packageFilter = ref(''); // 过滤后的检验项目数据(仅保留费用套餐的前端过滤,其他过滤已由后端处理) const filteredInspectionItems = computed(() => { return inspectionItems.value.filter(item => { - // 按费用套餐过滤(费用套餐是前端自定义字段,需要前端过滤) - if (packageFilter.value && item.package !== packageFilter.value) { + // 按费用套餐过滤(用 feePackageId 与选中的套餐 id 比对) + if (packageFilter.value && String(item.feePackageId) !== String(packageFilter.value)) { return false; } return true; @@ -1466,7 +1568,7 @@ let addingItem = false; const addPackageItem = () => { if (addingItem) return; // 防止重复调用 addingItem = true; - + const newItem = { name: '', dosage: '', @@ -1482,7 +1584,7 @@ const addPackageItem = () => { origin: '' }; packageItems.value.push(newItem); - + // 延迟重置标志位,确保不会影响其他操作 setTimeout(() => { addingItem = false; @@ -1509,23 +1611,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 +1683,7 @@ const cancelEditItem = (index) => { // 计算单个项目的服务费(基于折扣后的金额) const calculateItemServiceFee = (item) => { if (!generateServiceFee.value) return 0; - + // 服务费是项目折扣后金额的10% return parseFloat((item.amount * 0.1).toFixed(2)); }; @@ -1596,7 +1698,7 @@ const redistributeServiceFee = () => { }); return; } - + // 重新计算每个项目的服务费 packageItems.value.forEach(item => { item.serviceFee = calculateItemServiceFee(item); @@ -1610,27 +1712,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 +1826,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 +1842,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 +1853,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 +1880,7 @@ const handleConfirm = (row) => { } }); } - + editingRowId.value = null; }; @@ -1826,7 +1928,7 @@ const handleAdd = (row, index) => { tableData.value.splice(index + 1, 0, newRow); editingRowId.value = newRow.id; }; - + const handleDelete = (id) => { ElMessageBox.confirm('确定要删除该检验类型吗?', '提示', { confirmButtonText: '确定', @@ -1873,7 +1975,7 @@ const addNewItem = () => { amount: 0.00, sortOrder: inspectionItems.value.length + 1, serviceRange: '全部', - sub医技Type: '', + subItemName: '', remark: '', status: true }; @@ -1881,19 +1983,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 +2041,51 @@ 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; } - + // 【新增】验证小类项目名称唯一性 +// 逻辑:遍历列表,排除当前正在编辑的行(id不同),且名称(trim后)相同 + const isDuplicateName = inspectionItems.value.some(i => + i.id !== item.id && i.name.trim() === item.name.trim() + ); + if (isDuplicateName) { + ElMessage.error('小类项目名称已存在'); + return; + } + // 从费用套餐获取金额 updateAmountFromPackage(item); - + try { // 准备提交给后端的数据 const submitData = { @@ -1964,7 +2103,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 +2123,7 @@ const saveItem = async (item) => { ElMessage.error(response.msg || '更新失败'); } } - + editingRowId.value = null; } catch (error) { console.error('保存检验项目失败:', error); @@ -2015,8 +2154,8 @@ const deleteItem = async (id) => { }; const cancelEdit = (item) => { - // 如果是新添加的行,则直接删除 - if (item.id.toString().length > 10) { // 临时ID,使用Date.now()生成 + // 如果是新添加的行,则直接删除(临时ID为数字类型) + if (typeof item.id === 'number') { const index = inspectionItems.value.findIndex(i => i.id === item.id); if (index !== -1) { inspectionItems.value.splice(index, 1); @@ -2048,19 +2187,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('导出成功'); }; @@ -2370,19 +2509,21 @@ const handlePackageManagement = () => { const refreshPage = () => { getInspectionTypeList(); // 刷新时也重新加载套餐项目 - loadPackageItemsFromAPI(); + // loadPackageItemsFromAPI(); }; // 页面加载时获取数据 onMounted(() => { getInspectionTypeList(); getLisGroupList(); - // 加载检验套餐明细项目 - loadPackageItemsFromAPI(); - // 初始化计算套餐金额和服务费 - calculateAmounts(); + // // 加载检验套餐明细项目 + // loadPackageItemsFromAPI(); + // // 初始化计算套餐金额和服务费 + // calculateAmounts(); + fetchTenantList(); // 页面加载时获取租户列表 }); + // 监听检验分类代码,当字典数据加载完成后加载检验项目数据 watch(activity_category_code, (newVal) => { if (newVal && newVal.length > 0 && inspectionItems.value.length === 0) {