检查项目设置-套餐设置

This commit is contained in:
2025-11-26 16:15:11 +08:00
parent 69b7a4d865
commit ae7ca984f8
12 changed files with 1014 additions and 87 deletions

View File

@@ -68,4 +68,38 @@ export function listCheckPackage(query) {
method: 'get',
params: query
})
}
// 根据ID查询检查套餐详情
export function getCheckPackage(id) {
return request({
url: `/system/check-package/${id}`,
method: 'get'
})
}
// 新增检查套餐
export function addCheckPackage(data) {
return request({
url: '/system/check-package',
method: 'post',
data: data
})
}
// 修改检查套餐
export function updateCheckPackage(data) {
return request({
url: '/system/check-package',
method: 'put',
data: data
})
}
// 删除检查套餐
export function delCheckPackage(id) {
return request({
url: `/system/check-package/${id}`,
method: 'delete'
})
}

View File

@@ -3,12 +3,14 @@
<!-- 顶部操作按钮区 -->
<div class="header-actions">
<el-button type="primary" @click="handlePackageManagement">套餐管理</el-button>
<el-button @click="handleRefresh">刷新</el-button>
<el-button @click="handleRefresh" :loading="loading">
刷新 ({{ diagnosisTreatmentList.length }})
</el-button>
<el-button type="success" @click="handleSave">保存</el-button>
</div>
<!-- 基本信息表单区 -->
<div class="basic-info-section">
<div class="basic-info-section" v-loading="loading" element-loading-text="正在加载诊疗项目数据...">
<h3 class="section-title">基本信息</h3>
<el-form
ref="basicFormRef"
@@ -89,7 +91,11 @@
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-form-item label="折扣">
<el-input v-model="formData.discount" placeholder="请输入折扣">
<el-input
v-model="formData.discount"
placeholder="请输入折扣"
@input="validateNumberInput($event, 'discount')"
>
<template #append>%</template>
</el-input>
</el-form-item>
@@ -190,27 +196,61 @@
</el-table-column>
<el-table-column prop="itemName" label="项目名称/规格" min-width="200">
<template #default="{ row }">
<el-select
v-if="row.editing"
v-model="row.itemId"
placeholder="请选择项目"
filterable
style="width: 100%"
@change="handleItemSelect(row)"
>
<el-option
v-for="item in diagnosisTreatmentList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
<div v-if="row.editing">
<el-select
v-model="row.itemId"
placeholder="输入名称/首字母/编号搜索"
filterable
remote
:remote-method="(query) => handleProjectSearch(query, row)"
style="width: 100%"
@change="handleItemSelect(row)"
@focus="initializeSearchList(row)"
:loading="diagnosisTreatmentList.length === 0"
clearable
>
<el-option
v-for="item in (row.filteredList || diagnosisTreatmentList)"
:key="item.id"
:label="(item.name || item.itemName || '未命名') + (item.busNo ? ' [' + item.busNo + ']' : '')"
:value="item.id"
>
<span style="float: left">{{ item.name || item.itemName }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">
{{ item.busNo || item.code }}
</span>
</el-option>
<template #empty>
<div style="padding: 10px; text-align: center; color: #999;">
<div v-if="diagnosisTreatmentList.length === 0">
暂无项目数据<br/>
<small>请先在【系统管理-目录管理-诊疗项目】中添加项目</small>
</div>
<div v-else>
无匹配项目<br/>
<small>支持:名称模糊搜索、首字母搜索、编号搜索</small>
</div>
</div>
</template>
</el-select>
<div style="font-size: 12px; color: #999; margin-top: 4px;">
共 {{ diagnosisTreatmentList.length }} 个可选项目
<span v-if="row.filteredList && row.filteredList.length < diagnosisTreatmentList.length">
(搜索结果: {{ row.filteredList.length }} 个)
</span>
</div>
</div>
<span v-else>{{ row.itemName }}</span>
</template>
</el-table-column>
<el-table-column prop="dose" label="剂量" width="80" align="center">
<el-table-column prop="dose" label="剂量" width="100" align="center">
<template #default="{ row }">
<el-input v-if="row.editing" v-model="row.dose" placeholder="-" />
<el-input
v-if="row.editing"
v-model="row.dose"
placeholder="-"
@input="validateTableNumberInput($event, row, 'dose')"
/>
<span v-else>{{ row.dose || '-' }}</span>
</template>
</el-table-column>
@@ -226,9 +266,14 @@
<span v-else>{{ row.frequency || '-' }}</span>
</template>
</el-table-column>
<el-table-column prop="days" label="天数" width="80" align="center">
<el-table-column prop="days" label="天数" width="100" align="center">
<template #default="{ row }">
<el-input v-if="row.editing" v-model="row.days" placeholder="-" />
<el-input
v-if="row.editing"
v-model="row.days"
placeholder="-"
@input="validateTableNumberInput($event, row, 'days')"
/>
<span v-else>{{ row.days || '-' }}</span>
</template>
</el-table-column>
@@ -335,7 +380,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
import { getDicts } from '@/api/system/dict/data'
import { addCheckPackage, updateCheckPackage } from '@/api/system/checkType'
import { getDiagnosisTreatmentList } from '@/views/catalog/diagnosistreatment/components/diagnosistreatment'
import { useUserStore } from '@/store/modules/user'
import useUserStore from '@/store/modules/user'
const userStore = useUserStore()
@@ -372,13 +417,7 @@ const formRules = {
{ required: true, message: '请选择套餐级别', trigger: 'change' }
],
packageName: [
{ required: true, message: '请输入套餐名称', trigger: 'blur' }
],
department: [
{ required: true, message: '请选择科室', trigger: 'change' }
],
user: [
{ required: true, message: '请选择用户', trigger: 'change' }
{ required: true, message: '请输入套餐名称', trigger: 'blur', type: 'string' }
]
}
@@ -388,21 +427,28 @@ const packageLevelOptions = ref([])
const departments = ref([])
// 诊疗项目列表
const diagnosisTreatmentList = ref([])
// 过滤后的诊疗项目列表(用于搜索)
const filteredDiagnosisList = ref([])
// 加载状态
const loading = ref(false)
// 明细数据
const detailData = ref([])
// 初始化数据
onMounted(async () => {
console.log('=== PackageSettings 组件开始初始化 ===')
try {
// 获取套餐级别字典
try {
const levelResponse = await getDicts('examination_item_package_level')
if (levelResponse && levelResponse.data) {
packageLevelOptions.value = levelResponse.data
console.log('✓ 套餐级别数据加载成功:', packageLevelOptions.value.length)
}
} catch (error) {
console.error('获取套餐级别字典失败:', error)
console.error('获取套餐级别字典失败:', error)
}
// 获取科室字典
@@ -410,33 +456,97 @@ onMounted(async () => {
const deptResponse = await getDicts('dept')
if (deptResponse && deptResponse.data) {
departments.value = deptResponse.data
console.log('✓ 科室数据加载成功:', departments.value.length)
}
} catch (error) {
console.error('获取科室字典失败:', error)
console.error('获取科室字典失败:', error)
}
// 获取诊疗项目列表
// 获取诊疗项目列表 - 使用分批加载策略
loading.value = true
try {
const treatmentResponse = await getDiagnosisTreatmentList({
pageNo: 1,
pageSize: 1000
})
if (treatmentResponse && treatmentResponse.data && treatmentResponse.data.records) {
diagnosisTreatmentList.value = treatmentResponse.data.records
console.log('开始获取诊疗项目列表...')
// 分批加载数据,避免一次性加载过多导致超时
let allItems = []
const maxBatches = 3 // 最多加载3批
const batchSize = 50 // 每批50条
for (let page = 1; page <= maxBatches; page++) {
try {
const treatmentResponse = await getDiagnosisTreatmentList({
pageNo: page,
pageSize: batchSize
})
console.log(`${page}批API响应:`, treatmentResponse)
// 处理不同的响应格式
let batchData = []
if (treatmentResponse) {
if (treatmentResponse.data && treatmentResponse.data.records) {
batchData = treatmentResponse.data.records
} else if (treatmentResponse.data && Array.isArray(treatmentResponse.data)) {
batchData = treatmentResponse.data
} else if (treatmentResponse.records && Array.isArray(treatmentResponse.records)) {
batchData = treatmentResponse.records
}
}
if (batchData.length > 0) {
allItems = allItems.concat(batchData)
console.log(`✓ 第${page}批加载成功: ${batchData.length}条,累计: ${allItems.length}`)
// 如果这批数据少于pageSize说明已经是最后一批了
if (batchData.length < batchSize) {
break
}
} else {
break // 没有更多数据了
}
} catch (batchError) {
console.error(`${page}批加载失败:`, batchError)
break // 出错就停止继续加载
}
}
if (allItems.length > 0) {
diagnosisTreatmentList.value = allItems
console.log(`✓ 诊疗项目加载完成,共${allItems.length}`)
ElMessage.success(`成功加载${allItems.length}个诊疗项目`)
} else {
console.warn('未获取到任何诊疗项目数据')
ElMessage.warning({
message: '未获取到诊疗项目数据。请先在【系统管理-目录管理-诊疗项目】中添加数据',
duration: 6000,
showClose: true
})
}
} catch (error) {
console.error('获取诊疗项目列表失败:', error)
ElMessage.error({
message: '获取诊疗项目列表失败,请检查网络连接或联系管理员',
duration: 6000,
showClose: true
})
} finally {
loading.value = false
}
// 初始化一行空数据
handleAddRow()
console.log('=== PackageSettings 组件初始化完成 ===')
console.log('最终诊疗项目列表:', diagnosisTreatmentList.value)
} catch (error) {
console.error('初始化数据失败:', error)
console.error('初始化数据失败:', error)
}
})
// 套餐级别变更处理
function handlePackageLevelChange(value) {
console.log('套餐级别变更:', value)
// 重置关联字段
if (value !== '2') {
formData.department = ''
@@ -444,6 +554,21 @@ function handlePackageLevelChange(value) {
if (value !== '3') {
formData.user = ''
}
// 动态更新验证规则
if (value === '2') {
// 科室套餐,科室必填
formRules.department = [{ required: true, message: '请选择科室', trigger: 'change' }]
formRules.user = []
} else if (value === '3') {
// 个人套餐,用户必填
formRules.user = [{ required: true, message: '请选择用户', trigger: 'change' }]
formRules.department = []
} else {
// 全院套餐,都不必填
formRules.department = []
formRules.user = []
}
}
// 添加行
@@ -462,7 +587,8 @@ function handleAddRow() {
serviceCharge: 0,
total: 0,
origin: '',
editing: true
editing: true,
filteredList: diagnosisTreatmentList.value // 初始化过滤列表
})
}
@@ -499,13 +625,21 @@ function handleDeleteRow(index) {
// 项目选择处理
function handleItemSelect(row) {
console.log('选择项目ID:', row.itemId)
console.log('诊疗项目列表:', diagnosisTreatmentList.value)
const item = diagnosisTreatmentList.value.find(i => i.id === row.itemId)
console.log('找到的项目:', item)
if (item) {
row.itemName = item.name || ''
row.code = item.busNo || ''
// 获取单价,使用retailPrice
row.unitPrice = item.retailPrice || 0
row.itemName = item.name || item.itemName || ''
row.code = item.busNo || item.code || item.itemCode || ''
// 获取单价,尝试多个可能的字段名
row.unitPrice = item.retailPrice || item.unitPrice || item.price || 0
console.log('设置单价:', row.unitPrice)
calculateAmount(row)
} else {
ElMessage.warning('未找到该项目信息')
}
}
@@ -532,22 +666,100 @@ function handlePackageManagement() {
ElMessage.info('即将进入套餐管理界面')
}
// 刷新
function handleRefresh() {
ElMessageBox.confirm('确定要刷新页面吗?未保存的数据将丢失', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
location.reload()
}).catch(() => {})
// 刷新 - 重新加载诊疗项目数据
async function handleRefresh() {
try {
loading.value = true
console.log('开始刷新诊疗项目数据...')
// 分批加载数据,避免一次性加载过多导致超时
let allItems = []
const maxBatches = 3 // 最多加载3批
const batchSize = 50 // 每批50条
for (let page = 1; page <= maxBatches; page++) {
try {
const treatmentResponse = await getDiagnosisTreatmentList({
pageNo: page,
pageSize: batchSize
})
console.log(`${page}批API响应:`, treatmentResponse)
let batchData = []
if (treatmentResponse) {
if (treatmentResponse.data && treatmentResponse.data.records) {
batchData = treatmentResponse.data.records
} else if (treatmentResponse.data && Array.isArray(treatmentResponse.data)) {
batchData = treatmentResponse.data
} else if (treatmentResponse.records && Array.isArray(treatmentResponse.records)) {
batchData = treatmentResponse.records
}
}
if (batchData.length > 0) {
allItems = allItems.concat(batchData)
console.log(`✓ 第${page}批加载成功: ${batchData.length}条,累计: ${allItems.length}`)
// 如果这批数据少于pageSize说明已经是最后一批了
if (batchData.length < batchSize) {
break
}
} else {
break // 没有更多数据了
}
} catch (batchError) {
console.error(`${page}批加载失败:`, batchError)
break // 出错就停止继续加载
}
}
if (allItems.length > 0) {
diagnosisTreatmentList.value = allItems
ElMessage.success('刷新成功,共加载 ' + allItems.length + ' 个项目')
} else {
ElMessage.warning('未获取到项目数据,请先在【系统管理-目录管理-诊疗项目】中添加数据')
}
} catch (error) {
console.error('刷新失败:', error)
ElMessage.error('刷新失败,请检查网络连接或联系管理员')
} finally {
loading.value = false
}
}
// 数字输入验证 - 用于表单字段
function validateNumberInput(value, field) {
// 只允许数字和小数点
const regex = /^\d*\.?\d*$/
if (!regex.test(value)) {
formData[field] = value.replace(/[^\d.]/g, '')
}
}
// 数字输入验证 - 用于表格字段
function validateTableNumberInput(value, row, field) {
// 只允许数字和小数点
const regex = /^\d*\.?\d*$/
if (!regex.test(value)) {
row[field] = value.replace(/[^\d.]/g, '')
}
}
// 保存
async function handleSave() {
try {
console.log('开始保存,当前表单数据:', JSON.parse(JSON.stringify(formData)))
// 验证基本信息
await basicFormRef.value.validate()
try {
await basicFormRef.value.validate()
console.log('✓ 基本信息验证通过')
} catch (validationError) {
console.error('✗ 表单验证失败:', validationError)
ElMessage.error('请完善必填项:' + Object.keys(validationError).join(', '))
return
}
// 验证明细数据
if (detailData.value.length === 0) {
@@ -555,27 +767,38 @@ async function handleSave() {
return
}
console.log('明细数据条数:', detailData.value.length)
// 检查是否有未确认的编辑行
const hasEditingRow = detailData.value.some(row => row.editing)
if (hasEditingRow) {
ElMessage.warning('请先确认所有正在编辑的行')
return
}
console.log('✓ 所有行已确认')
// 检查明细数据完整性
const hasEmptyItem = detailData.value.some(row => !row.itemName || !row.quantity)
if (hasEmptyItem) {
ElMessage.warning('请完善所有明细项目信息')
console.error('✗ 存在空项目:', detailData.value.filter(row => !row.itemName || !row.quantity))
ElMessage.warning('请完善所有明细项目信息(项目名称和数量为必填项)')
return
}
console.log('✓ 明细数据完整性验证通过')
// 更新创建日期为当前系统时间
formData.createDate = new Date().toISOString().split('T')[0]
// 验证折扣范围
if (formData.discount && (parseFloat(formData.discount) < 0 || parseFloat(formData.discount) > 100)) {
ElMessage.warning('折扣必须在0-100之间')
return
}
// 构建保存数据
const saveData = {
id: formData.id,
packageName: formData.packageName,
packageName: String(formData.packageName || ''),
code: formData.code || '',
description: formData.description || '',
packageType: formData.packageType,
@@ -583,49 +806,69 @@ async function handleSave() {
department: formData.department || '',
user: formData.user || '',
organization: formData.organization,
packagePrice: formData.packagePrice,
packagePrice: parseFloat(formData.packagePrice) || 0,
discount: formData.discount ? parseFloat(formData.discount) : null,
creator: formData.creator,
isDisabled: formData.isDisabled,
showPackageName: formData.showPackageName,
generateServiceFee: formData.generateServiceFee,
packagePriceEnabled: formData.packagePriceEnabled,
serviceFee: formData.serviceFee || 0,
serviceFee: parseFloat(formData.serviceFee) || 0,
remark: formData.remark || '',
createDate: formData.createDate,
items: detailData.value.map(item => ({
items: detailData.value.map((item, index) => ({
itemCode: item.code || '',
itemName: item.itemName || '',
checkItemId: item.itemId || null, // 诊疗项目ID
checkItemId: item.itemId || null,
dose: item.dose || '',
method: item.method || '',
frequency: item.frequency || '',
days: item.days || '',
quantity: item.quantity || 1,
unitPrice: item.unitPrice || 0,
amount: item.amount || 0,
serviceCharge: item.serviceCharge || 0,
total: item.total || 0,
origin: item.origin || ''
quantity: parseInt(item.quantity) || 1,
unitPrice: parseFloat(item.unitPrice) || 0,
amount: parseFloat(item.amount) || 0,
serviceCharge: parseFloat(item.serviceCharge) || 0,
total: parseFloat(item.total) || 0,
origin: item.origin || '',
orderNum: index + 1
}))
}
// 调用API保存
const response = await addCheckPackage(saveData)
if (response && response.code === 200) {
ElMessage.success('套餐数据已保存')
// 如果有返回ID更新formData.id以便后续更新
if (response.data) {
formData.id = response.data
console.log('构建的保存数据:', JSON.parse(JSON.stringify(saveData)))
// 调用API保存 - 根据是否有ID判断新增还是更新
let response
try {
if (formData.id) {
console.log('执行更新操作...')
response = await updateCheckPackage(saveData)
} else {
console.log('执行新增操作...')
response = await addCheckPackage(saveData)
}
} else {
ElMessage.error(response?.msg || '保存失败,请检查表单数据')
console.log('API响应:', response)
if (response && (response.code === 200 || response.code === 0)) {
ElMessage.success('套餐数据已保存')
// 如果有返回ID更新formData.id以便后续更新
if (response.data && !formData.id) {
formData.id = response.data
console.log('新增成功套餐ID:', formData.id)
}
} else {
console.error('保存失败,响应:', response)
ElMessage.error(response?.msg || response?.message || '保存失败,请检查表单数据')
}
} catch (apiError) {
console.error('API调用失败:', apiError)
throw apiError
}
} catch (error) {
console.error('保存失败:', error)
console.error('保存过程出错:', error)
if (error !== 'cancel') {
ElMessage.error('保存失败,请检查表单数据')
const errorMsg = error.response?.data?.msg || error.message || '保存失败,请检查表单数据'
ElMessage.error('保存失败: ' + errorMsg)
}
}
}