fix(consultation): 解决会诊流程中的多个功能问题

- 在 deptappthoursManage.js 中添加 status 参数以仅获取已启动的机构
- 为 consultationapplication 组件添加已确认和已签名状态选项
- 扩展操作列宽度并添加打印功能按钮
- 优化 handlePrint 方法以支持行参数和性别枚举转换
- 为 consultationconfirmation 组件添加必填验证和编辑权限控制
- 修复会诊确认医师信息回显逻辑
- 在 inspectionApplication 组件中修复表格行点击事件和检验项目加载
- 禁用非紧急标记的编辑权限以解决Bug #268
- 为 surgeryApplication 组件添加响应码验证和错误处理
- 在 consultation 组件中添加表单验证清除功能
- 为 PackageManagement 组件实现动态机构选项加载
- 重构 PackageSettings 组件的套餐金额显示和只读模式
- 为检查项目设置组件添加套餐筛选和下级类型选择功能
- 实现检验套餐的编辑和查看模式切换功能
This commit is contained in:
2026-03-26 18:22:21 +08:00
parent c509a804ec
commit 91a0b48662
20 changed files with 631 additions and 266 deletions

View File

@@ -192,7 +192,7 @@ import {computed, onMounted, ref} from 'vue';
import {useRouter} from 'vue-router';
import {ElMessage} from 'element-plus';
import {getLocationTree} from '@/views/charge/outpatientregistration/components/outpatientregistration';
import {listInspectionPackage} from '@/api/system/inspectionPackage';
import {listInspectionPackage, delInspectionPackage} from '@/api/system/inspectionPackage';
import { getTenantPage } from '@/api/system/tenant';
@@ -583,7 +583,13 @@ const pageButtons = computed(() => {
// 处理新增
function handleAdd() {
router.push('/maintainSystem/Inspection?tab=2');
router.push({
path: '/maintainSystem/Inspection',
query: {
tab: '2',
mode: 'add'
}
});
}
// 处理编辑
@@ -625,12 +631,39 @@ function handleView(item) {
}
// 处理删除
function handleDelete(item) {
if (confirm(`确定要删除套餐 "${item.name}" 吗?`)) {
const index = tableData.value.findIndex(i => i.id === item.id);
if (index !== -1) {
tableData.value.splice(index, 1);
alert(`套餐 "${item.name}" 已删除`);
async function handleDelete(item) {
try {
await ElMessageBox.confirm(
`确定要删除套餐 "${item.name}" 吗?删除后将无法恢复。`,
'确认删除',
{
confirmButtonText: '确定删除',
cancelButtonText: '取消',
type: 'warning'
}
)
// 获取套餐ID优先使用 basicInformationId
const packageId = item.basicInformationId || item.id
if (!packageId) {
ElMessage.error('无法获取套餐ID删除失败')
return
}
// 调用后端API删除
const response = await delInspectionPackage(packageId)
if (response && (response.code === 200 || response.code === 0)) {
ElMessage.success('删除成功')
// 删除成功后,重新加载列表数据
loadData()
} else {
ElMessage.error(response?.msg || response?.message || '删除失败')
}
} catch (error) {
if (error !== 'cancel' && error !== 'close') {
console.error('删除失败:', error)
ElMessage.error('删除失败: ' + (error?.message || error?.msg || '未知错误'))
}
}
}

View File

@@ -424,7 +424,8 @@
<el-button :icon="RefreshRight" @click="resetForm">重置</el-button>
<el-button type="success" @click="handlePackageManagement">套餐管理</el-button>
</div>
<el-button type="success" size="large" @click="handleSave">保存</el-button>
<el-button v-if="!isViewMode" type="success" size="large" @click="handleSave">{{ packageMode === 'edit' ? '更新' : '保存' }}</el-button>
<el-button v-else type="primary" size="large" @click="handleBackToManagement">返回管理</el-button>
</div>
<!-- 表单区域 -->
@@ -448,6 +449,7 @@
default-first-option
placeholder="请选择或输入套餐级别"
style="width: 100%;"
:disabled="isViewMode"
@change="handlePackageLevelChange"
>
<el-option
@@ -473,6 +475,7 @@
check-strictly
:expand-on-click-node="false"
clearable
:disabled="isViewMode"
style="width: 100%;"
@change="handlePackageDepartmentChange"
/>
@@ -483,7 +486,7 @@
</div>
<div class="form-item">
<span class="form-label"><span style="color:red"></span>套餐名称</span>
<el-input v-model="packageName" placeholder="请输入套餐名称" />
<el-input v-model="packageName" placeholder="请输入套餐名称" :disabled="isViewMode" />
<div class="error-message" id="packageNameError" style="color: #ff4d4f; font-size: 12px; margin-top: 4px; display: none;">套餐名称不能为空</div>
</div>
<div class="form-item">
@@ -495,6 +498,7 @@
@change="handleTenantChange"
clearable
filterable
:disabled="isViewMode"
:loading="loadingTenant"
no-data-text="暂无数据请稍后重试"
@visible-change="handleTenantVisibleChange"
@@ -513,7 +517,7 @@
</div>
<div class="form-item">
<span class="form-label">折扣 %</span>
<el-input v-model="discount" @input="calculateAmounts" />
<el-input v-model="discount" @input="calculateAmounts" :disabled="isViewMode" />
</div>
<div class="form-item">
<span class="form-label">制单人</span>
@@ -521,32 +525,32 @@
</div>
<div class="form-item">
<span class="form-label">备注</span>
<el-input v-model="remarks" placeholder="请输入备注" />
<el-input v-model="remarks" placeholder="请输入备注" :disabled="isViewMode" />
</div>
<div class="form-item">
<span class="form-label">是否停用</span>
<el-radio-group v-model="isDisabled">
<el-radio-group v-model="isDisabled" :disabled="isViewMode">
<el-radio :label="false">启用</el-radio>
<el-radio :label="true">停用</el-radio>
</el-radio-group>
</div>
<div class="form-item">
<span class="form-label">显示套餐名</span>
<el-radio-group v-model="showPackageName">
<el-radio-group v-model="showPackageName" :disabled="isViewMode">
<el-radio :label="true">是</el-radio>
<el-radio :label="false">否</el-radio>
</el-radio-group>
</div>
<div class="form-item">
<span class="form-label">生成服务费</span>
<el-radio-group v-model="generateServiceFee">
<el-radio-group v-model="generateServiceFee" :disabled="isViewMode">
<el-radio :label="true">是</el-radio>
<el-radio :label="false">否</el-radio>
</el-radio-group>
</div>
<div class="form-item">
<span class="form-label">套餐价格</span>
<el-radio-group v-model="enablePackagePrice">
<el-radio-group v-model="enablePackagePrice" :disabled="isViewMode">
<el-radio :label="true">启用</el-radio>
<el-radio :label="false">不启用</el-radio>
</el-radio-group>
@@ -558,7 +562,7 @@
</div>
<div class="form-item">
<span class="form-label">lis分组</span>
<el-select v-model="selectedLisGroup" placeholder="请选择lis分组" style="width: 100%;">
<el-select v-model="selectedLisGroup" placeholder="请选择lis分组" style="width: 100%;" :disabled="isViewMode">
<el-option
v-for="group in lisGroupList"
:key="group.id"
@@ -569,7 +573,7 @@
</div>
<div class="form-item">
<span class="form-label">血量</span>
<el-input v-model="bloodVolume" />
<el-input v-model="bloodVolume" :disabled="isViewMode" />
</div>
</div>
</div>
@@ -578,7 +582,7 @@
<div class="table-container" style="width: 100%; margin-top: 20px;">
<div class="table-header" style="display: flex; justify-content: space-between; align-items: center; padding: 10px;">
<div class="table-title" style="font-size: 16px; font-weight: bold;">检验套餐明细</div>
<el-button type="primary" size="small" circle @click="addPackageItem" title="添加项目">
<el-button v-if="!isViewMode" type="primary" size="small" circle @click="addPackageItem" title="添加项目">
<el-icon><Plus /></el-icon>
</el-button>
</div>
@@ -890,6 +894,7 @@ import {
import {listLisGroup} from '@/api/system/checkType';
import {
addInspectionPackage,
updateInspectionPackage,
getInspectionPackage,
listInspectionPackageDetails,
saveInspectionPackageDetails
@@ -1545,6 +1550,12 @@ const bloodVolume = ref('');
const remarks = ref('');
// 检验套餐明细项目 - 从后端API获取
const packageItems = ref([]);
// 套餐当前模式: add-新增, edit-编辑, view-查看
const packageMode = ref('add');
// 当前编辑的套餐ID用于编辑和查看模式
const currentPackageId = ref(null);
// 是否为查看模式(只读)
const isViewMode = computed(() => packageMode.value === 'view');
let addingItem = false;
const addPackageItem = () => {
@@ -2651,34 +2662,50 @@ const savePackageData = async (basicInfo, detailData) => {
});
try {
// 1. 先保存基本信息
const basicResponse = await addInspectionPackage(basicInfo);
// 检查响应码
if (basicResponse.code !== 200) {
loading.close();
throw new Error(basicResponse.msg || '保存基本信息失败');
// 判断是新增还是编辑模式
const isEditMode = packageMode.value === 'edit' && currentPackageId.value;
// 如果是编辑模式设置packageId到basicInfo中
if (isEditMode) {
basicInfo.packageId = currentPackageId.value;
}
// 检查响应数据结构 - 兼容多种可能的响应格式
// 1. 先保存或更新基本信息
let packageId = null;
let basicResponse;
if (isEditMode) {
// 编辑模式调用更新API
basicResponse = await updateInspectionPackage(basicInfo);
packageId = currentPackageId.value;
} else {
// 新增模式调用新增API
basicResponse = await addInspectionPackage(basicInfo);
// 检查响应码
if (basicResponse.code !== 200) {
loading.close();
throw new Error(basicResponse.msg || '保存基本信息失败');
}
if (basicResponse.data) {
// 标准格式:{code: 200, data: {packageId: xxx}}
packageId = basicResponse.data.packageId || basicResponse.data.id;
} else if (basicResponse.packageId) {
// 如果data不存在尝试直接从响应根级别获取
packageId = basicResponse.packageId;
} else if (basicResponse.id) {
// 如果data不存在尝试直接从响应根级别获取id
packageId = basicResponse.id;
}
// 检查响应数据结构 - 兼容多种可能的响应格式
if (basicResponse.data) {
// 标准格式:{code: 200, data: {packageId: xxx}}
packageId = basicResponse.data.packageId || basicResponse.data.id;
} else if (basicResponse.packageId) {
// 如果data不存在尝试直接从响应根级别获取
packageId = basicResponse.packageId;
} else if (basicResponse.id) {
// 如果data不存在尝试直接从响应根级别获取id
packageId = basicResponse.id;
}
// 验证套餐ID是否存在
if (!packageId) {
loading.close();
console.error('无法从响应中获取套餐ID完整响应:', basicResponse);
throw new Error('保存成功但未返回套餐ID。请检查后端接口是否正确返回了packageId或id字段');
// 验证套餐ID是否存在
if (!packageId) {
loading.close();
console.error('无法从响应中获取套餐ID完整响应:', basicResponse);
throw new Error('保存成功但未返回套餐ID。请检查后端接口是否正确返回了packageId或id字段');
}
}
// 2. 分别保存每个明细数据到明细表,并将后端返回的 id 回填到 packageItems
@@ -2780,6 +2807,10 @@ const doResetForm = () => {
// 清空明细数据
packageItems.value = [];
// 重置模式为新增
packageMode.value = 'add';
currentPackageId.value = null;
// 重新计算金额
calculateAmounts();
@@ -2857,6 +2888,13 @@ const handlePackageManagement = () => {
});
};
const handleBackToManagement = () => {
// 返回套餐管理页面
router.push({
path: '/maintainSystem/Inspection/PackageManagement'
});
};
const refreshPage = () => {
getInspectionTypeList();
};
@@ -2889,7 +2927,19 @@ watch(
const applyRouteForPackage = async (query) => {
const packageId = query?.packageId;
if (!packageId) return;
const mode = query?.mode || 'add';
// 设置当前模式和套餐ID
packageMode.value = mode;
currentPackageId.value = packageId ? String(packageId) : null;
// 如果是新增模式,重置表单
if (mode === 'add' || !packageId) {
activeNav.value = 2;
doResetForm();
return;
}
activeNav.value = 2;
await nextTick();
loadInspectionPackage(String(packageId));

View File

@@ -17,8 +17,13 @@
</el-form-item>
<el-form-item label="卫生机构">
<el-select v-model="queryParams.organization" placeholder="请选择机构" style="width: 150px" clearable>
<el-option label="演示医院" value="演示医院" />
<el-select v-model="queryParams.organization" placeholder="请选择机构" style="width: 150px" clearable filterable>
<el-option
v-for="org in organizationOptions"
:key="org.value"
:label="org.label"
:value="org.value"
/>
</el-select>
</el-form-item>
@@ -199,6 +204,7 @@ import {ElMessage, ElMessageBox} from 'element-plus'
import {getDicts} from '@/api/system/dict/data'
import {listDept} from '@/api/system/dept'
import {delCheckPackage, getCheckPackage, listCheckPackage} from '@/api/system/checkType'
import {getTenantPage} from '@/api/system/tenant'
import request from '@/utils/request'
import useUserStore from '@/store/modules/user'
@@ -275,6 +281,8 @@ const loading = ref(false)
const packageLevelOptions = ref([])
// 科室选项
const departments = ref([])
// 卫生机构选项
const organizationOptions = ref([])
// 初始化数据
onMounted(async () => {
@@ -394,6 +402,33 @@ onMounted(async () => {
}
}
// 获取卫生机构列表
try {
const tenantResponse = await getTenantPage({ pageNum: 1, pageSize: 100 })
if (tenantResponse && tenantResponse.code === 200) {
const tenantData = tenantResponse.data || {}
let tenantList = []
if (Array.isArray(tenantData)) {
tenantList = tenantData
} else if (tenantData.records) {
tenantList = tenantData.records
} else if (tenantData.rows) {
tenantList = tenantData.rows
} else if (tenantData.list) {
tenantList = tenantData.list
}
// 过滤启用的机构
organizationOptions.value = tenantList
.filter(item => item && item.status === '0')
.map(item => ({
value: item.tenantName || item.name || item.orgName || String(item.id),
label: item.tenantName || item.name || item.orgName || String(item.id)
}))
}
} catch (error) {
console.error('获取卫生机构列表失败:', error)
}
// 加载列表数据
handleQuery()
})

View File

@@ -87,7 +87,7 @@
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-form-item label="套餐金额">
<el-input v-model="formData.packagePrice" :disabled="true" placeholder="自动计算">
<el-input v-model="packagePriceDisplay" :disabled="true" placeholder="自动计算">
<template #append></template>
</el-input>
</el-form-item>
@@ -112,73 +112,60 @@
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-form-item label="是否停用">
<el-radio-group v-model="formData.isDisabled">
<el-radio :value="0">启用</el-radio>
<el-radio :value="1">停用</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-form-item label="是否停用">
<el-radio-group v-model="formData.isDisabled" :disabled="isReadOnly">
<el-radio :value="0">启用</el-radio>
<el-radio :value="1">停用</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-form-item label="显示套餐名">
<el-radio-group v-model="formData.showPackageName">
<el-radio :value="1"></el-radio>
<el-radio :value="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-form-item label="显示套餐名">
<el-radio-group v-model="formData.showPackageName" :disabled="isReadOnly">
<el-radio :value="1"></el-radio>
<el-radio :value="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-form-item label="生成服务费">
<el-radio-group v-model="formData.generateServiceFee">
<el-radio :value="1"></el-radio>
<el-radio :value="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-form-item label="生成服务费">
<el-radio-group v-model="formData.generateServiceFee" :disabled="isReadOnly">
<el-radio :value="1"></el-radio>
<el-radio :value="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-form-item label="套餐价格">
<el-radio-group v-model="formData.packagePriceEnabled">
<el-radio :value="1">启用</el-radio>
<el-radio :value="0">不启用</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-form-item label="套餐价格">
<el-radio-group v-model="formData.packagePriceEnabled" :disabled="isReadOnly">
<el-radio :value="1">启用</el-radio>
<el-radio :value="0">不启用</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-form-item label="服务费">
<el-input-number
v-model="formData.serviceFee"
:precision="2"
:min="0"
placeholder="请输入服务费"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-form-item label="服务费">
<el-input-number
v-model="formData.serviceFee"
:precision="2"
:min="0"
placeholder="请输入服务费"
style="width: 100%"
:disabled="isReadOnly"
/>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-form-item label="日期">
<el-date-picker
v-model="formData.createDate"
type="date"
placeholder="选择日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
:disabled="true"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12">
<el-form-item label="备注">
<el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12">
<el-form-item label="备注">
<el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" :disabled="isReadOnly" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
@@ -338,7 +325,7 @@
<span v-else>{{ row.origin || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="150" align="center" fixed="right">
<el-table-column label="操作" v-if="!isReadOnly" width="150" align="center" fixed="right">
<template #default="{ row, $index }">
<div class="actions">
<el-button
@@ -446,7 +433,7 @@ const formData = reactive({
user: '',
packageName: '',
organization: '',
packagePrice: '0.00',
packagePrice: 0,
discount: '',
creator: userStore.name || '当前用户',
isDisabled: 0,
@@ -458,6 +445,14 @@ const formData = reactive({
createDate: new Date().toISOString().split('T')[0] // 自动生成当前系统日期
})
// 套餐金额显示值(格式化后的字符串)
const packagePriceDisplay = computed({
get: () => formData.packagePrice?.toFixed(2) || '0.00',
set: (value) => {
// 只读,不允许直接修改
}
})
// 表单验证规则
const formRules = {
packageType: [
@@ -499,6 +494,9 @@ watch(() => props.packageData, (newData) => {
function loadPackageData(data) {
if (!data) return
console.log('=== 加载套餐数据 ===')
console.log('套餐数据:', data)
// 填充基本信息
Object.keys(formData).forEach(key => {
if (data[key] !== undefined) {
@@ -511,7 +509,7 @@ function loadPackageData(data) {
// 旧编码格式:在下拉框中添加临时选项
const tempDept = {
deptCode: deptValue,
dictLabel: `旧编码: ${deptValue} (请重新选择)`,
dictLabel: `旧编码${deptValue} (请重新选择)`,
dictValue: deptValue,
isOldFormat: true
}
@@ -548,13 +546,45 @@ function loadPackageData(data) {
editing: false,
filteredList: diagnosisTreatmentList.value
}))
console.log('明细数据加载成功,条数:', detailData.value.length)
} else {
console.log('没有明细数据')
}
console.log('formData 加载后:', formData)
console.log('detailData 加载后:', detailData.value)
}
onMounted(async () => {
console.log('=== PackageSettings 组件开始初始化 ===')
console.log('当前模式:', props.mode)
try {
// 新增模式初始化 formData
if (props.mode === 'add') {
console.log('新增模式:初始化 formData')
// 确保表单字段正确初始化
formData.id = null
formData.packageType = '检查套餐'
formData.packageLevel = ''
formData.department = ''
formData.user = ''
formData.packageName = ''
formData.organization = ''
formData.packagePrice = 0
formData.discount = ''
formData.isDisabled = 0
formData.showPackageName = 1
formData.generateServiceFee = 0
formData.packagePriceEnabled = 1
formData.serviceFee = 0
formData.remark = ''
formData.createDate = new Date().toISOString().split('T')[0]
// 清空明细数据并初始化一行
detailData.value = []
handleAddRow()
}
// 获取套餐级别字典
try {
const levelResponse = await getDicts('examination_item_package_level')
@@ -698,11 +728,6 @@ onMounted(async () => {
// 加载卫生机构列表(只获取启用的租户)
await loadOrganizationList()
// 初始化一行空数据
if(props.mode === 'add'){
handleAddRow()
}
} catch (error) {
console.error('✗ 初始化数据失败:', error)
}
@@ -1033,12 +1058,12 @@ function calculatePackagePrice() {
// 如果有折扣,应用折扣计算
let finalPrice = total
if (formData.discount && parseFloat(formData.discount) > 0 && parseFloat(formData.discount) <= 100) {
const discountRate = parseFloat(formData.discount) / 100 // 将百分比转换为小数如10% -> 0.1
const discountRate = parseFloat(formData.discount) / 100 // 将百分比转换为小数(如 10% -> 0.1
const discountAmount = total * discountRate // 折扣金额
finalPrice = total - discountAmount // 折扣后金额
}
formData.packagePrice = finalPrice.toFixed(2)
formData.packagePrice = finalPrice
}
// 折扣变更处理

View File

@@ -233,7 +233,7 @@
</div>
<div class="search-item">
<label>费用套餐</label>
<el-select v-model="searchParamsMethod.packageName" placeholder="选择使用套餐" style="width: 150px">
<el-select v-model="searchParamsMethod.packageName" placeholder="选择使用套餐" style="width: 150px" filterable clearable>
<el-option
v-for="pkg in checkPackages"
:key="pkg.id"
@@ -551,10 +551,17 @@
</td>
<td>
<template v-if="item.editing">
<input type="text" placeholder="请输入下级医技类型" v-model="item.subType">
<el-select v-model="item.subType" placeholder="选择下级医技类型" style="width: 100%" clearable filterable>
<el-option
v-for="opt in checkTypeOptionsForMethodPart"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</el-select>
</template>
<template v-else>
{{ item.subType || '' }}
{{ getCheckTypeLabelForMethodPart(item.subType) || '' }}
</template>
</td>
<td>