Files
his/openhis-ui-vue3/src/views/doctorstation/components/inspection/inspectionApplication.vue

2101 lines
62 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-container class="inspection-application-container">
<!-- 顶部操作按钮区 -->
<el-header class="top-action-bar" height="50px">
<el-row class="action-buttons" type="flex" justify="end" :gutter="10">
<el-button type="success" size="large" @click="handleSave" class="save-btn">
<el-icon><Document /></el-icon>
保存
</el-button>
<el-button type="primary" size="large" @click="handleNewApplication" class="new-btn">
<el-icon><Plus /></el-icon>
新增
</el-button>
</el-row>
</el-header>
<!-- 检验信息表格区 -->
<el-main class="inspection-section" style="width: 100%; max-width: 100%">
<el-card class="table-card" style="width: 100%">
<template #header>
<el-row class="card-header" type="flex" align="middle">
<el-icon><DocumentChecked /></el-icon>
<span>检验信息</span>
</el-row>
</template>
<el-table
ref="inspectionTableRef"
:data="inspectionList"
border
stripe
size="small"
max-height="300px"
style="width: 100%; min-width: 100%"
class="inspection-table"
@selection-change="handleSelectionChange"
@cell-click="handleCellClick"
>
<el-table-column type="selection" width="55" align="center" header-align="center" />
<el-table-column label="序号" width="60" align="center" header-align="center">
<template #default="{ $index }">
<span>{{ $index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="申请单号" prop="applyNo" min-width="180" align="center" header-align="center" />
<el-table-column label="检验项目" prop="itemName" min-width="170px" align="center" header-align="center" />
<el-table-column label="申请医生" prop="applyDocName" width="120" align="center" header-align="center" />
<el-table-column label="急" width="60" align="center" header-align="center">
<template #default="scope">
<el-checkbox :model-value="scope.row.priorityCode" disabled />
</template>
</el-table-column>
<el-table-column label="收费" width="60" align="center" header-align="center">
<template #default="scope">
<el-checkbox :model-value="scope.row.applyStatus" disabled />
</template>
</el-table-column>
<el-table-column label="退费" width="60" align="center" header-align="center">
<template #default="scope">
<el-checkbox :model-value="scope.row.needRefund" disabled />
</template>
</el-table-column>
<el-table-column label="执行" width="60" align="center" header-align="center">
<template #default="scope">
<el-checkbox :model-value="scope.row.needExecute" disabled />
</template>
</el-table-column>
<el-table-column label="金额" prop="amount" width="90" align="center" header-align="center">
<template #default="scope">
¥{{ formatAmount(scope.row.itemAmount) }}
</template>
</el-table-column>
<el-table-column label="操作" width="120" align="center" header-align="center">
<template #default="scope">
<el-row type="flex" align="middle" justify="center" :gutter="8">
<el-button link size="default" @click="handlePrint(scope.row)" :icon="Printer" title="打印" style="font-size: 16px"></el-button>
<el-button link size="default" @click="handleDelete(scope.row)" :icon="Delete" style="color: #f56c6c; font-size: 16px" title="删除"></el-button>
</el-row>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-row class="pagination-container" justify="center" style="margin-top: 10px">
<el-pagination
v-model:current-page="queryParams.pageNo"
v-model:page-size="queryParams.pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="total"
layout="prev, pager, next, jumper, total"
:pager-count="5"
:hide-on-single-page="false"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</el-row>
</el-card>
</el-main>
<!-- 底部表单与项目选择区 -->
<el-main class="bottom-content-area">
<el-row :gutter="16">
<!-- 左侧申请单表单区65% -->
<el-col :span="15" class="form-area">
<el-card class="form-card" style="width: 100%">
<el-tabs v-model="leftActiveTab" class="form-tabs">
<el-tab-pane label="申请单" name="application">
<el-form class="application-form" :model="formData" label-width="auto">
<el-form-item label="申请单号" style="margin-bottom: 1px">
<el-input v-model="formData.applyNo" readonly size="small" />
</el-form-item>
<!-- 患者信息行 -->
<el-row :gutter="20" style="margin-bottom: 1px">
<el-col :span="8">
<el-form-item label="姓名" required>
<el-input v-model="formData.patientName" readonly size="small" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="就诊卡号" required>
<el-input v-model="formData.medicalrecordNumber" readonly size="small" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="费用性质" required>
<el-select v-model="formData.natureofCost" placeholder="请选择费用性质" size="small" style="width: 100%">
<el-option label="自费医疗" value="self" />
<el-option label="医保" value="medical" />
<el-option label="公费医疗" value="public" />
<el-option label="商业保险" value="commercial" />
<el-option label="其他" value="other" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- 申请信息行 -->
<el-row :gutter="20" style="margin-bottom: 1px">
<!--申请日期-->
<el-col :span="8">
<el-form-item label="申请日期" required>
<el-date-picker
v-model="formData.applyTime"
type="datetime"
placeholder="选择日期时间"
size="small"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
</el-col>
<!--申请科室-->
<el-col :span="8">
<el-form-item label="申请科室" required>
<el-input v-model="formData.applyDepartment" readonly size="small" />
</el-form-item>
</el-col>
<!--申请医生-->
<el-col :span="8">
<el-form-item label="申请医生" required>
<el-input v-model="formData.applyDocName" readonly size="small" />
</el-form-item>
</el-col>
</el-row>
<!-- 执行科室 -->
<el-form-item
label="执行科室"
required
style="margin-bottom: 1px"
:class="{ 'form-item-error': validationErrors.executeDepartment }"
:error="validationErrors.executeDepartment ? '请选择执行科室' : ''"
>
<el-select
v-model="formData.executeDepartment"
placeholder="请选择执行科室"
size="small"
style="width: 100%"
:class="{ 'is-error': validationErrors.executeDepartment }"
>
<el-option label="医学检验科" value="medical_lab" />
<el-option label="放射科" value="radiology" />
<el-option label="超声科" value="ultrasound" />
<el-option label="病理科" value="pathology" />
<el-option label="核医学科" value="nuclear_medicine" />
</el-select>
</el-form-item>
<!-- 诊断描述 -->
<el-row :gutter="20" style="margin-bottom: 1px">
<el-col :span="12">
<el-form-item
label="诊断描述"
required
:class="{ 'form-item-error': validationErrors.clinicDesc }"
:error="validationErrors.clinicDesc ? '请输入诊断描述' : ''"
>
<el-input
v-model="formData.clinicDesc"
type="textarea"
:rows="2"
size="small"
:class="{ 'is-error': validationErrors.clinicDesc }"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="临床诊断"
required
:class="{ 'form-item-error': validationErrors.clinicDiag }"
:error="validationErrors.clinicDiag ? '请输入临床诊断' : ''"
>
<el-input
v-model="formData.clinicDiag"
type="textarea"
:rows="2"
size="small"
:class="{ 'is-error': validationErrors.clinicDiag }"
/>
</el-form-item>
</el-col>
</el-row>
<!-- 禁忌症病史摘要检验目的体格检查 -->
<el-row :gutter="20" style="margin-bottom: 1px">
<el-col :span="12">
<el-form-item label="禁忌症">
<el-input v-model="formData.contraindication" type="textarea" :rows="2" size="small" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="病史摘要"
required
:class="{ 'form-item-error': validationErrors.medicalHistorySummary }"
:error="validationErrors.medicalHistorySummary ? '请输入病史摘要' : ''"
>
<el-input
v-model="formData.medicalHistorySummary"
type="textarea"
:rows="2"
size="small"
:class="{ 'is-error': validationErrors.medicalHistorySummary }"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="检验目的"
required
:class="{ 'form-item-error': validationErrors.purposeofInspection }"
:error="validationErrors.purposeofInspection ? '请输入检验目的' : ''"
>
<el-input
v-model="formData.purposeofInspection"
type="textarea"
:rows="2"
size="small"
:class="{ 'is-error': validationErrors.purposeofInspection }"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="体格检查">
<el-input v-model="formData.physicalExam" type="textarea" :rows="2" size="small" />
</el-form-item>
</el-col>
</el-row>
<!-- 检验项目和备注 -->
<el-row :gutter="20" style="margin-bottom: 1px">
<el-col :span="12">
<el-form-item label="检验项目">
<el-input v-model="formData.inspectionItemsText" type="textarea" :rows="2" size="small" readonly />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注">
<el-input v-model="formData.applyRemark" type="textarea" :rows="2" size="small" />
</el-form-item>
</el-col>
</el-row>
<!-- 状态复选框组 -->
<el-card style="margin-bottom: 16px; padding: 16px; background: #f8f9fa; border-radius: 4px; border: 1px solid #e9ecef" shadow="never">
<template #header>
<span style="font-weight: bold; color: #1a2b6d; font-size: 14px">
状态设置
</span>
</template>
<el-row type="flex" :gutter="16" wrap>
<el-col :xs="12" :sm="6" :md="6" :lg="6">
<el-checkbox v-model="formData.priorityCode" :true-value="1" :false-value="0"></el-checkbox>
</el-col>
<el-col :xs="12" :sm="6" :md="6" :lg="6">
<el-checkbox v-model="formData.applyStatus" :true-value="1" :false-value="0">收费</el-checkbox>
</el-col>
<el-col :xs="12" :sm="6" :md="6" :lg="6">
<el-checkbox v-model="formData.needRefund" :true-value="true" :false-value="false">退费</el-checkbox>
</el-col>
<el-col :xs="12" :sm="6" :md="6" :lg="6">
<el-checkbox v-model="formData.needExecute" :true-value="true" :false-value="false">执行</el-checkbox>
</el-col>
</el-row>
</el-card>
</el-form>
</el-tab-pane>
<el-tab-pane label="检验信息" name="inspectionInfo">
<el-card style="padding: 20px; height: 700px; overflow-y: auto; border: 1px solid #e4e7ed; border-radius: 4px; margin: 10px; width: 100%">
<el-form :model="formData" label-width="100px" style="margin-bottom: 20px">
<el-row :gutter="15">
<el-col :span="12">
<el-form-item label="检验医生">
<el-input v-model="formData.inspectionDoctor" size="small" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="检验时间">
<el-date-picker
v-model="formData.inspectionTime"
type="datetime"
placeholder="选择时间"
size="small"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="审核医生">
<el-input v-model="formData.auditDoctor" size="small" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="审核时间">
<el-date-picker
v-model="formData.auditTime"
type="datetime"
placeholder="选择时间"
size="small"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 检验信息详情表格 -->
<el-card style="margin-top: 20px; width: 100%" shadow="never">
<template #header>
<h4 style="margin: 0; font-weight: bold">检验信息详情</h4>
</template>
<el-table :data="selectedInspectionItems" border size="small" style="width: 100%; min-width: 100%" max-height="350">
<el-table-column label="项目名称" prop="itemName" width="200" />
<el-table-column label="样本类型" prop="sampleType" width="80" align="center" />
<el-table-column label="单位" prop="unit" width="60" align="center" />
<el-table-column label="总量" prop="itemQty" width="60" align="center">
<template #default="scope">
<span>{{ scope.row.itemQty || 1 }}</span>
</template>
</el-table-column>
<el-table-column label="单价" prop="itemPrice" width="70" align="right">
<template #default="scope">
¥{{ scope.row.itemPrice }}
</template>
</el-table-column>
<el-table-column label="金额" prop="itemAmount" width="70" align="right">
<template #default="scope">
¥{{ scope.row.itemAmount }}
</template>
</el-table-column>
<el-table-column label="服务费" width="70" align="right">
<template #default="scope">
¥{{ scope.row.serviceFee || 0 }}
</template>
</el-table-column>
<el-table-column label="类型" prop="type" width="60" align="center" />
<el-table-column label="自费" width="50" align="center">
<template #default="scope">
<el-checkbox :model-value="scope.row.isSelfPay" disabled />
</template>
</el-table-column>
</el-table>
</el-card>
</el-card>
</el-tab-pane>
</el-tabs>
</el-card>
</el-col>
<!-- 右侧项目选择区35% -->
<el-col :span="9" class="selection-area">
<!-- 检验项目选择区上部50% -->
<el-card class="inspection-selector">
<template #header>
<span class="card-title">检验项目选择</span>
</template>
<!-- 搜索框 -->
<el-input
v-model="searchKeyword"
placeholder="搜索检验项目..."
size="small"
clearable
prefix-icon="Search"
@input="handleSearch"
class="search-input"
/>
<!-- 分类树 -->
<el-scrollbar class="category-tree" style="max-height: 280px">
<div
v-for="category in inspectionCategories"
:key="category.key"
class="category-tree-item"
>
<div
:class="['category-tree-header', { active: activeCategory === category.key }]"
@click="switchCategory(category.key)"
>
<span class="category-tree-icon">{{ category.expanded ? '▼' : '▶' }}</span>
<span>{{ category.label }}</span>
<span class="category-count">({{ category.items.length }})</span>
</div>
<div v-if="category.expanded" class="category-tree-children">
<div
v-for="item in getFilteredItems(category.key)"
:key="item.itemId"
:class="['inspection-tree-item', { selected: isItemSelected(item) }]"
@click="handleItemClick(item)"
>
<el-checkbox
:model-value="isItemSelected(item)"
@change="toggleInspectionItem(item)"
@click.stop
/>
<span class="item-itemName">{{ item.itemName }}</span>
<span class="item-price">¥{{ item.itemPrice }}</span>
</div>
</div>
</div>
</el-scrollbar>
</el-card>
<!-- 下部已选项目区 -->
<el-card class="selected-items-area">
<template #header>
<el-row class="selected-header" type="flex" justify="space-between" align="middle">
<span class="card-title">已选择</span>
<el-button link @click="clearAllSelected" type="danger" size="small">清空</el-button>
</el-row>
</template>
<!-- 已选项目列表 -->
<el-scrollbar class="selected-tree" style="max-height: 300px">
<el-list v-if="selectedInspectionItems.length > 0" :data="selectedInspectionItems" class="selected-items-list">
<el-list-item
v-for="item in selectedInspectionItems"
:key="item.itemId"
class="selected-list-item"
>
<el-row class="selected-item-content" type="flex" align="middle" style="width: 100%">
<span class="item-itemName">{{ item.itemName }}</span>
<span class="item-price">¥{{ item.itemPrice }}</span>
<el-button
link
size="small"
style="color: #f56c6c; margin-left: auto"
@click="removeInspectionItem(item)"
>
删除
</el-button>
</el-row>
</el-list-item>
</el-list>
<el-empty v-if="selectedInspectionItems.length === 0" class="no-selection" description="暂无选择项目" />
</el-scrollbar>
</el-card>
</el-col>
</el-row>
</el-main>
</el-container>
</template>
<script setup>
import {onMounted, reactive, ref, watch} from 'vue'
import {ElMessage, ElMessageBox} from 'element-plus'
import { DocumentChecked, Plus, Document, Printer, Delete } from '@element-plus/icons-vue'
import {
checkInspectionApplicationNo,
deleteInspectionApplication, getApplyList,
saveInspectionApplication
} from '../api'
import useUserStore from '@/store/modules/user.js'
import {storeToRefs} from 'pinia'
// 在 onMounted 中调用初始化函数
onMounted(() => {
initData();
})
// Props
const props = defineProps({
patientInfo: {
type: Object,
required: true
},
activeTab: {
type: String
}
})
// Emits
const emit = defineEmits(['save'])
// 响应式数据
const showForm = ref(false)
const loading = ref(false)
const total = ref(0)
const leftActiveTab = ref('application')
const isGeneratingNewApplyNo = ref(false) // 标志:是否正在生成新申请单号
// 用户信息store
const userStore = useUserStore()
const { id: userId, name: userName, nickName: userNickName } = storeToRefs(userStore)
// 修改 initData 函数
function initData() {
// 然后执行原有的初始化逻辑
if (props.patientInfo) {
queryParams.encounterId = props.patientInfo.encounterId
formData.visitNo = props.patientInfo.busNo || ''
formData.patientId = props.patientInfo.patientId || ''
formData.patientName = props.patientInfo.patientName || ''
formData.medicalrecordNumber = props.patientInfo.identifierNo || ''
formData.applyDepartment = props.patientInfo.organizationName || ''
formData.applyDocName = userNickName.value || userName.value || ''
formData.applyDocCode = userId.value || ''
formData.specimenName = '血液'
formData.applyDeptCode = props.patientInfo.organizationName || ''
formData.applyOrganizationId = props.patientInfo.orgId || ''
formData.encounterId = props.patientInfo.encounterId
generateApplicationNo().then((newApplyNo) => {
formData.applyNo = newApplyNo;
});
}
// 只有在存在 encounterId 时才调用接口
if (queryParams.encounterId) {
getInspectionList()
}
}
// 查询参数
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
encounterId: props.patientInfo.encounterId
})
// 检验申请单列表
const inspectionList = ref([])
// 表单数据
const formData = reactive({
applyOrganizationId: props.patientInfo.orgId,
applicationId: null,
applyNo: '',
patientId:'',
patientName: '',
medicalrecordNumber: '',
natureofCost: 'self',
applyTime: new Date(),
applyDepartment: '',
applyDocName: '',
executeDepartment: 'medical_lab',
clinicDesc: '',
contraindication: '',
clinicDiag: '',
medicalHistorySummary: '',
purposeofInspection: '',
physicalExam: '',
labApplyItemList: [],
inspectionItemsText: '',
applyRemark: '',
priorityCode: 0,
applyStatus: 1,
needRefund: false,
needExecute: false,
inspectionDoctor: '',
inspectionTime: null,
auditDoctor: '',
auditTime: null,
visitNo: '',
applyDocCode:'',
applyDeptCode: props.patientInfo.organizationName,
specimenName: '血液',
encounterId: props.patientInfo.encounterId
})
// 表单验证规则
const formRules = {
natureofCost: [{ required: true, message: '请选择费用性质', trigger: 'change' }],
applyTime: [{ required: true, message: '请选择申请日期', trigger: 'change' }],
executeDepartment: [{ required: true, message: '请选择执行科室', trigger: 'change' }],
clinicDesc: [{ required: true, message: '请输入诊断描述', trigger: 'blur' }],
clinicDiag: [{ required: true, message: '请输入临床诊断', trigger: 'blur' }],
medicalHistorySummary: [{ required: true, message: '请输入病史摘要', trigger: 'blur' }],
purposeofInspection: [{ required: true, message: '请输入检验目的', trigger: 'blur' }],
labApplyItemList: [{ required: true, message: '请至少选择一个检验项目', trigger: 'change' }]
}
// 表单引用
const formRef = ref()
// 表格引用
const inspectionTableRef = ref()
// 验证错误状态
const validationErrors = reactive({
executeDepartment: false,
clinicDesc: false,
clinicDiag: false,
medicalHistorySummary: false,
purposeofInspection: false,
labApplyItemList: false
})
// 已选择的表格行
const selectedRows = ref([])
// 已选择的检验项目
const selectedInspectionItems = ref([])
// 搜索关键词
const searchKeyword = ref('')
// 活动分类
const activeCategory = ref('biochemical')
// 检验项目分类(树形结构)
let inspectionCategories = ref([
{
key: 'biochemical',
label: '生化',
expanded: true,
items: [
{ itemId: 1, itemName: '肝功能', itemPrice: 31, itemAmount: 31, sampleType: '血清', unit: 'U/L', itemQty: 1, serviceFee: 0, type: '生化', isSelfPay: false },
{ itemId: 2, itemName: '肾功能', itemPrice: 28, itemAmount: 28, sampleType: '血清', unit: 'U/L', itemQty: 1, serviceFee: 0, type: '生化', isSelfPay: false },
{ itemId: 3, itemName: '血糖', itemPrice: 15, itemAmount: 15, sampleType: '血清', unit: 'mmol/L', itemQty: 1, serviceFee: 0, type: '生化', isSelfPay: false }
]
},
{
key: 'blood',
label: '临检',
expanded: false,
items: [
{ itemId: 4, itemName: '血常规+crp', itemPrice: 50, itemAmount: 50, sampleType: '全血', unit: '×10^9/L', itemQty: 1, serviceFee: 0, type: '血液', isSelfPay: false },
{ itemId: 5, itemName: '血常规(五分类)', itemPrice: 15, itemAmount: 15, sampleType: '全血', unit: '×10^9/L', itemQty: 1, serviceFee: 0, type: '血液', isSelfPay: false }
]
},
{
key: 'urine',
label: '尿液',
expanded: false,
items: [
{ itemId: 6, itemName: '尿常规', itemPrice: 20, itemAmount: 20, sampleType: '尿液', unit: '细胞/μl', itemQty: 1, serviceFee: 0, type: '尿液', isSelfPay: false }
]
},
{
key: 'immunity',
label: '免疫',
expanded: false,
items: [
{ itemId: 7, itemName: '总IgE测定', itemPrice: 30, itemAmount: 30, sampleType: '血清', unit: 'IU/ml', itemQty: 1, serviceFee: 0, type: '免疫', isSelfPay: false },
{ itemId: 8, itemName: '风湿', itemPrice: 119, itemAmount: 119, sampleType: '血清', unit: 'U/ml', itemQty: 1, serviceFee: 0, type: '免疫', isSelfPay: false }
]
}
])
// 获取过滤后的项目
const getFilteredItems = (categoryKey) => {
const category = inspectionCategories.value.find(cat => cat.key === categoryKey)
if (!category) return []
if (!searchKeyword.value) {
return category.items
}
return category.items.filter(item =>
item.itemName.toLowerCase().includes(searchKeyword.value.toLowerCase())
)
}
// 获取检验申请单列表
function getInspectionList() {
// 如果没有encounterId,不调用接口
if (!queryParams.encounterId) {
// console.warn('【检验】encounterId为空,不调用接口')
return
}
loading.value = true
// 调用分页API传递分页参数和 encounterId
// console.log('【检验】调用API,encounterId:', queryParams.encounterId, 'pageNo:', queryParams.pageNo, 'pageSize:', queryParams.pageSize)
getApplyList({
encounterId: queryParams.encounterId,
pageNo: queryParams.pageNo,
pageSize: queryParams.pageSize
}).then((res) => {
if (res.code === 200) {
// 处理分页响应数据
if (res.data && typeof res.data === 'object') {
// 如果返回的是分页对象 {records: [...], total: 100}
if (Array.isArray(res.data.records)) {
// 处理数据:将同一个申请单的多个明细合并成一条记录
inspectionList.value = mergeInspectionApplyRecords(res.data.records)
total.value = res.data.total || 0
}
// 如果返回的是普通数组
else if (Array.isArray(res.data)) {
// 处理数据:将同一个申请单的多个明细合并成一条记录
inspectionList.value = mergeInspectionApplyRecords(res.data)
total.value = res.data.length
}
// 如果返回的是其他对象结构
else {
inspectionList.value = []
total.value = 0
}
} else {
inspectionList.value = []
total.value = 0
}
// console.log('【检验】获取数据成功,数量:', inspectionList.value.length, '总数:', total.value)
} else {
inspectionList.value = []
total.value = 0
ElMessage.error(res.message || '获取检验申请单列表失败')
}
}).catch((error) => {
// console.error('获取检验申请单列表异常:', error)
inspectionList.value = []
total.value = 0
ElMessage.error('获取检验申请单列表异常: ' + (error.message || ''))
}).finally(() => {
loading.value = false
})
}
// 合并检验申请单记录:将同一个申请单的多个明细合并成一条记录
function mergeInspectionApplyRecords(records) {
if (!records || records.length === 0) {
return []
}
// 使用Map按申请单号分组
const applyMap = new Map()
records.forEach(record => {
const applyNo = record.applyNo
if (applyMap.has(applyNo)) {
// 如果申请单已存在,合并检验项目
const existing = applyMap.get(applyNo)
existing.itemName = existing.itemName + '+' + record.itemName
// 累加金额,保留两位小数
const totalAmount = (parseFloat(existing.itemAmount) || 0) + (parseFloat(record.itemAmount) || 0)
existing.itemAmount = parseFloat(totalAmount.toFixed(2))
} else {
// 如果申请单不存在,直接添加
applyMap.set(applyNo, { ...record })
}
})
// 将Map转换为数组
return Array.from(applyMap.values())
}
// 格式化金额:确保显示两位小数
function formatAmount(amount) {
if (amount === null || amount === undefined || amount === '') {
return '0.00'
}
const num = parseFloat(amount)
if (isNaN(num)) {
return '0.00'
}
return num.toFixed(2)
}
// 新增申请单
async function handleNewApplication() {
// console.log('点击新增按钮')
resetForm()
// 生成新的申请单号
formData.applyNo = await generateApplicationNo()
// 确保申请医生是当前登录医生
formData.applyDocName = userNickName.value || userName.value || ''
leftActiveTab.value = 'application'
}
// 查询数据库中是否已存在指定申请单号
const checkApplicationNoExists = async (applyNo) => {
try {
// 这里调用API检查申请单号是否已存在
// 注意你需要根据实际API接口调整此调用
const response = await checkInspectionApplicationNo(applyNo);
// 后端返回格式:如果存在返回{applyNo: "..."}不存在返回null
return response.code === 200 && response.data && response.data.applyNo;
} catch (error) {
// 隐藏具体的错误信息,仅记录在控制台
console.debug('检查申请单号时发生错误:', error.message);
// 如果API调用失败假设单号不存在以避免阻塞
return false;
}
};
// 生成申请单号
let counter = 0;
const generateApplicationNo = async () => {
let applyNo;
let isUnique = false;
let attempts = 0;
const maxAttempts = 10; // 最大尝试次数
// 循环直到生成唯一的申请单号
while (!isUnique && attempts < maxAttempts) {
const now = new Date();
// 生成20位申请单号年(4位) + 月(2位) + 日(2位) + 时(2位) + 分(2位) + 秒(2位) + 毫秒(3位) + 随机数(3位)
const year = String(now.getFullYear()); // 取4位年份
const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始需要+1
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
const milliseconds = String(now.getMilliseconds()).padStart(3, '0'); // 毫秒取3位
// 生成3位随机数增加唯一性避免并发冲突
const randomNum = Math.floor(Math.random() * 1000).toString().padStart(3, '0'); // 3位随机数
// 年(4)+月(2)+日(2)+时(2)+分(2)+秒(2)+毫秒(3)+随机数(3) = 20位
applyNo = `${year}${month}${day}${hours}${minutes}${seconds}${milliseconds}${randomNum}`;
// 确保生成的申请单号不为空
if (!applyNo || applyNo.trim() === '') {
console.debug('生成的申请单号为空,重新生成');
attempts++;
continue;
}
// 检查生成的单号是否已存在于数据库中
const existsInDatabase = await checkApplicationNoExists(applyNo);
// 只有当单号不在数据库中时,才是唯一的
isUnique = !existsInDatabase;
attempts++;
}
if (!isUnique) {
console.warn(`经过${maxAttempts}次尝试仍未生成唯一申请单号,使用备用方案`);
// 如果多次尝试后仍无法生成唯一单号使用UUID的一部分作为备用方案
const timestamp = Date.now().toString();
const randomPart = Math.floor(Math.random() * 1000).toString().padStart(3, '0');
const fallbackNo = 'F' + timestamp.slice(-17) + randomPart; // 使用F开头表示备用方案
return fallbackNo;
}
return applyNo;
};
// 重置表单
async function resetForm() {
Object.assign(formData, {
applicationId: null,
applyOrganizationId: props.patientInfo.orgId || '',
patientName: props.patientInfo.patientName || '',
medicalrecordNumber: props.patientInfo.identifierNo || '',
natureofCost: 'self',
applyTime: new Date(),
applyDepartment: props.patientInfo.organizationName || '',
applyDeptCode: props.patientInfo.organizationName,
applyDocCode: userId.value || '',
applyDocName: userNickName.value || userName.value || '',
executeDepartment: 'medical_lab',
clinicDesc: '',
contraindication: '',
clinicDiag: '',
medicalHistorySummary: '',
purposeofInspection: '',
physicalExam: '',
labApplyItemList: [],
applyRemark: '',
priorityCode: 0,
applyStatus: 1,
needRefund: false,
needExecute: false,
patientId: props.patientInfo.patientId || '',
visitNo: '',
specimenName: '血液',
encounterId: props.patientInfo.encounterId || '',
})
selectedInspectionItems.value = []
// 重置验证错误状态
Object.keys(validationErrors).forEach(key => {
validationErrors[key] = false
})
formRef.value?.clearValidate()
}
// 返回列表
function handleBack() {
showForm.value = false
getInspectionList()
}
// 保存
function handleSave() {
// 重置验证错误状态
Object.keys(validationErrors).forEach(key => {
validationErrors[key] = false
})
let hasErrors = false
// 检查必填字段
// 检查必填字段,执行科室
if (!formData.executeDepartment) {
validationErrors.executeDepartment = true
hasErrors = true
}
// 检查必填字段,诊断描述
if (!formData.clinicDesc.trim()) {
validationErrors.clinicDesc = true
hasErrors = true
}
// 检查必填字段,临床诊断
if (!formData.clinicDiag.trim()) {
validationErrors.clinicDiag = true
hasErrors = true
}
// 检查必填字段,病史摘要
if (!formData.medicalHistorySummary.trim()) {
validationErrors.medicalHistorySummary = true
hasErrors = true
}
// 检查必填字段,检验目的
if (!formData.purposeofInspection.trim()) {
validationErrors.purposeofInspection = true
hasErrors = true
}
// 检查必填字段,检验项目
if (selectedInspectionItems.value.length === 0) {
validationErrors.labApplyItemList = true
hasErrors = true
ElMessage.error('请至少选择一项检验项目')
return
}
// 检查必填字段,申请日期
if(!formData.applyTime || (typeof formData.applyTime === 'string' && !formData.applyTime.trim())) {
validationErrors.applyTime = true
hasErrors = true
}
if (hasErrors) {
ElMessage.error('请填写所有必填字段')
return
}
// 准备保存数据
const prepareSaveData = () => {
return {
...formData,
labApplyItemList: selectedInspectionItems.value,
inspectionItemsText: selectedInspectionItems.value.map(item => item.itemName).join('+'),
amount: selectedInspectionItems.value.reduce((sum, item) => sum + item.itemAmount, 0),
serviceFee: selectedInspectionItems.value.reduce((sum, item) => sum + (item.serviceFee || 0), 0),
totalAmount: selectedInspectionItems.value.reduce((sum, item) => sum + item.itemAmount + (item.serviceFee || 0), 0)
}
}
// 先检查申请单号是否已存在
console.log('查询申请单号:', formData.applyNo)
// 如果正在生成新申请单号,则跳过重复检查,直接保存
if (isGeneratingNewApplyNo.value) {
// 正在使用新生成的单号,直接保存
isGeneratingNewApplyNo.value = false; // 重置标志
const saveData = prepareSaveData();
executeSave(saveData);
return;
}
checkInspectionApplicationNo(formData.applyNo).then((res) => {
if (res.code === 200 && res.data) {
// res.data有值表示申请单存在
// 注意res.data可能是{applyNo: "..."}或包含其他字段
const exists = res.data && (res.data.applyNo || res.data.exists);
if (exists) {
// 申请单号已存在,提示用户
ElMessageBox.confirm(
'当前申请单号已重复,将重新为您生成新的申请单号',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
// 设置标志,表示正在生成新申请单号
isGeneratingNewApplyNo.value = true;
// 重新生成申请单号
generateApplicationNo().then((newApplyNo) => {
if (newApplyNo && newApplyNo.trim() !== '') {
formData.applyNo = newApplyNo;
ElMessage.success('新申请单号已生成,请点击保存按钮继续,请核对数据');
// 不自动保存,等待用户再次点击保存
} else {
console.debug('生成的申请单号为空,不设置');
isGeneratingNewApplyNo.value = false;
}
});
}).catch((error) => {
// 用户点击取消或其他原因导致的拒绝
if (error !== 'cancel' && error !== 'close') {
console.error('MessageBox操作出错:', error);
}
console.debug('用户取消了重新生成申请单号');
});
} else {
// 申请单号不存在,继续保存操作
const saveData = prepareSaveData();
executeSave(saveData);
}
} else {
// 其他情况继续保存
const saveData = prepareSaveData();
executeSave(saveData);
}
}).catch((error) => {
console.error('检查申请单号时发生错误:', error);
// 如果检查过程出错,仍然继续保存操作,以免影响正常使用
const saveData = prepareSaveData();
executeSave(saveData);
})
}
// 执行保存操作
const executeSave = (saveData) => {
saveInspectionApplication(saveData).then((res) => {
console.log('保存检验申请单结果:', res.code)
if (res.code === 200) {
ElMessage.success('保存成功')
resetForm()
// 生成新的申请单号
generateApplicationNo().then((newApplyNo) => {
if (newApplyNo && newApplyNo.trim() !== '') {
formData.applyNo = newApplyNo;
} else {
console.debug('生成的申请单号为空,不设置');
}
});
leftActiveTab.value = 'application'
// 刷新列表
getInspectionList()
} else {
// 对于其他错误,也使用弹窗提示
ElMessageBox.alert(res.message || '保存失败', '错误', {
confirmButtonText: '确定',
type: 'error',
}).catch((error) => {
console.error('错误提示框操作出错:', error);
});
console.debug(res.message || '保存失败')
}
}).catch((error) => {
// 处理请求失败的其他错误
console.error('保存检验申请单时发生错误:', error);
ElMessage.error('保存失败,请稍后重试');
})
}
// 表单保存
function handleFormSave() {
formRef.value?.validate((valid) => {
if (valid) {
formData.labApplyItemList = selectedInspectionItems.value.map(item => item.itemId)
// console.log('保存检验申请单表单数据:', formData)
ElMessage.success('保存成功')
showForm.value = false
getInspectionList()
}
})
}
// 查看详情
function handleView(row) {
// console.log('点击查看按钮,数据:', row)
// 加载表单数据
Object.assign(formData, row)
// 根据检验项目名称找到对应的项目数据
selectedInspectionItems.value = []
const itemNames = row.inspectionItem.split('、')
inspectionCategories.value.forEach(category => {
category.items.forEach(item => {
if (itemNames.includes(item.name)) {
selectedInspectionItems.value.push(item)
}
})
})
leftActiveTab.value = 'application'
}
// 切换分类
function switchCategory(category) {
if (activeCategory.value === category) {
// 如果点击的是当前激活的分类,则收起
activeCategory.value = ''
inspectionCategories.value.forEach(cat => {
if (cat.key === category) {
cat.expanded = false
}
})
} else {
// 否则切换到新的分类并展开
activeCategory.value = category
inspectionCategories.value.forEach(cat => {
cat.expanded = cat.key === category
})
}
}
// 处理搜索
function handleSearch() {
// 搜索逻辑已在getFilteredItems中实现这里可以添加额外的搜索逻辑
// console.log('搜索关键词:', searchKeyword.value)
}
// 处理项目项点击(排除勾选框点击)
function handleItemClick(item) {
toggleInspectionItem(item)
}
// 判断项目是否已选择
function isItemSelected(item) {
return selectedInspectionItems.value.some(selected => selected.itemId === item.itemId)
}
// 切换检验项目选择
function toggleInspectionItem(item) {
const index = selectedInspectionItems.value.findIndex(selected => selected.itemId === item.itemId)
if (index > -1) {
selectedInspectionItems.value.splice(index, 1)
} else {
// 创建新对象,包含 itemName 属性(等于 name 属性)
const newItem = {
...item,
itemName: item.itemName
};
selectedInspectionItems.value.push(newItem);
}
}
// 移除检验项目
function removeInspectionItem(item) {
const index = selectedInspectionItems.value.findIndex(selected => selected.itemId === item.itemId)
if (index > -1) {
selectedInspectionItems.value.splice(index, 1)
}
}
// 清空所有选择
function clearAllSelected() {
selectedInspectionItems.value = []
}
// 分页大小改变
function handleSizeChange(size) {
queryParams.pageSize = size
getInspectionList()
}
// 分页页码改变
function handleCurrentChange(page) {
queryParams.pageNo = page
getInspectionList()
}
// 选择框变化
function handleSelectionChange(selection) {
selectedRows.value = selection
}
// 打印申请单
function handlePrint(row) {
// console.log('打印申请单:', row)
// 切换到申请单TAB
leftActiveTab.value = 'application'
// 加载要打印的数据
handleView(row)
// 等待DOM更新后执行打印
setTimeout(() => {
// 添加打印样式
const printStyle = document.createElement('style')
printStyle.innerHTML = `
@media print {
body * {
visibility: hidden;
}
.application-form,
.application-form * {
visibility: visible;
}
.application-form {
position: absolute;
left: 0;
top: 0;
width: 100%;
max-width: none;
box-shadow: none;
border: none;
margin: 0;
padding: 20px;
}
.el-tabs__header {
display: none;
}
.el-tabs__content {
padding: 0;
}
.section-header,
.pagination-container,
.inspection-selector,
.selected-items-area,
.actions {
display: none !important;
}
.application-form .el-input__inner,
.application-form .el-select .el-input__inner,
.application-form .el-textarea__inner {
border: 1px solid #ddd !important;
background: white !important;
}
.application-form .el-checkbox__input.is-checked .el-checkbox__inner {
background-color: #409eff;
border-color: #409eff;
}
}
`
document.head.appendChild(printStyle)
// 执行打印
window.print()
// 移除打印样式
setTimeout(() => {
document.head.removeChild(printStyle)
}, 1000)
ElMessage.success('正在准备打印...')
}, 100)
}
// 删除申请单
function handleDelete(row) {
ElMessageBox.confirm(
`确定要删除申请单 "${row.applyNo}" 吗?此操作将同时删除对应的医嘱。`,
'删除确认',
{
confirmButtonText: '确定删除',
cancelButtonText: '取消',
type: 'warning',
confirmButtonClass: 'el-button--danger'
}
).then(() => {
// 调用真实的 API 删除(传递 applyNo
// 调用真实的API删除
deleteInspectionApplication(row.applyNo).then((res) => {
if (res.code === 200) {
ElMessage.success('删除成功')
// 刷新列表
getInspectionList()
} else {
ElMessage.error(res.message || '删除失败')
}
}).catch((error) => {
console.error('删除检验申请单异常:', error)
ElMessage.error('删除异常')
})
}).catch(() => {
// 用户取消删除
})
}
// 单元格点击 - 点击表格行时加载申请单详情
function handleCellClick(row, column) {
// 点击表格行时,将该申请单的数据加载到表单中
if (row && row.applicationId) {
// 切换到申请单 TAB
leftActiveTab.value = 'application'
// 加载表单数据
Object.assign(formData, {
applicationId: row.applicationId,
applyNo: row.applyNo,
patientName: row.patientName,
medicalrecordNumber: row.medicalrecordNumber,
natureofCost: row.natureofCost || 'self',
applyTime: row.applyTime,
applyDepartment: row.applyDepartment,
applyDocName: row.applyDocName,
executeDepartment: row.executeDepartment || 'medical_lab',
clinicDesc: row.clinicDesc,
contraindication: row.contraindication,
clinicDiag: row.clinicDiag,
medicalHistorySummary: row.medicalHistorySummary,
purposeofInspection: row.purposeofInspection,
physicalExam: row.physicalExam,
applyRemark: row.applyRemark,
priorityCode: row.priorityCode || 0,
applyStatus: row.applyStatus || 1,
needRefund: row.needRefund || false,
needExecute: row.needExecute || false,
inspectionDoctor: row.inspectionDoctor,
inspectionTime: row.inspectionTime,
auditDoctor: row.auditDoctor,
auditTime: row.auditTime,
visitNo: row.visitNo,
applyDocCode: row.applyDocCode,
applyDeptCode: row.applyDeptCode,
specimenName: row.specimenName,
encounterId: row.encounterId,
patientId: row.patientId,
applyOrganizationId: row.applyOrganizationId
})
// 根据检验项目名称解析已选项目
selectedInspectionItems.value = []
if (row.inspectionItem) {
const itemNames = row.inspectionItem.split('、')
inspectionCategories.value.forEach(category => {
category.items.forEach(item => {
if (itemNames.includes(item.itemName)) {
selectedInspectionItems.value.push({ ...item })
}
})
})
}
// 重置验证错误状态
Object.keys(validationErrors).forEach(key => {
validationErrors[key] = false
})
}
}
// 监听activeTab变化
watch(() => props.activeTab, async (newVal) => {
if (newVal === 'inspection') {
await initData()
// 默认展开生化分类
activeCategory.value = 'biochemical'
inspectionCategories.value.forEach(cat => {
cat.expanded = cat.key === 'biochemical'
})
}
})
// 监听patientInfo变化,确保encounterId及时更新并重新加载数据
watch(() => props.patientInfo, async (newVal) => {
// console.log('【检验】patientInfo变化:', newVal)
console.log('【检验】接收到的完整patientInfo:', JSON.stringify(newVal, null, 2))
if (newVal && newVal.encounterId) {
const oldEncounterId = queryParams.encounterId
queryParams.encounterId = newVal.encounterId
// console.log('【检验】更新encounterId:', queryParams.encounterId)
// 如果encounterId发生变化重新加载检验申请单列表
if (oldEncounterId !== newVal.encounterId) {
getInspectionList()
}
// 更新科室编码
// const currentDeptCode = await getCurrentDeptCode();
// formData.applyDeptCode = currentDeptCode || '';
}
}, { deep: true, immediate: true })
// 监听已选择的检验项目,自动更新检验项目文本(用+号拼接)
watch(() => selectedInspectionItems.value, (newVal) => {
if (newVal && newVal.length > 0) {
formData.inspectionItemsText = newVal.map(item => item.itemName).join('+')
} else {
formData.inspectionItemsText = ''
}
}, { deep: true })
// 初始化
onMounted(async () => {
await initData();
getInspectionList();
})
// 暴露方法
defineExpose({
getList: getInspectionList
})
</script>
<style lang="scss" scoped>
/* 页面容器 */
.inspection-application-container {
max-height: 750px;
overflow-y: auto;
padding: 0;
}
/* 顶部操作按钮区 */
.top-action-bar {
display: flex;
align-items: center;
justify-content: flex-end;
border-bottom: 1px solid var(--el-border-color-light);
background: var(--el-bg-color);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.action-buttons {
display: flex;
gap: 10px;
}
/* 检验信息表格区 */
.inspection-section {
padding: 20px;
}
.table-card {
height: 300px;
display: flex;
flex-direction: column;
}
.card-header {
display: flex;
align-items: center;
gap: 8px;
font-weight: 600;
color: var(--el-text-color-primary);
}
/* 底部内容区域 */
.bottom-content-area {
padding: 20px;
}
/* 表单区域 */
.form-card {
height: 700px;
}
.form-tabs {
height: 100%;
}
.application-form {
height: 650px;
overflow-y: auto;
padding: 20px;
}
/* 选择区域 */
.selection-area {
display: flex;
flex-direction: column;
gap: 20px;
}
.inspection-selector,
.selected-items-area {
height: 350px;
}
.card-title {
font-weight: 600;
color: var(--el-text-color-primary);
}
.search-input {
margin-bottom: 15px;
}
.selected-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.pagination-container {
display: flex;
justify-content: center;
margin-top: 10px;
padding-top: 10px;
border-top: 1px solid var(--el-border-color-light);
}
:deep(.el-pagination) {
.el-pager li {
border-radius: 4px;
margin: 0 2px;
min-width: 32px;
height: 32px;
line-height: 30px;
border: 1px solid #dcdfe6;
background-color: #fff;
color: #606266;
transition: all 0.3s ease;
}
.el-pager li:hover {
border-color: #409eff;
color: #409eff;
}
.el-pager li.is-active {
border-color: #409eff;
background-color: #409eff;
color: #fff;
}
.el-pagination__jump {
margin-left: 10px;
}
}
.inspection-form {
background: white;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.form-header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #eee;
padding: 15px 20px;
margin-bottom: 15px;
}
.form-header .title {
display: flex;
align-items: center;
font-size: 16px;
font-weight: bold;
color: #1a2b6d;
}
.form-header .title i {
margin-right: 10px;
font-size: 24px;
}
.inspection-items-section {
border: 1px solid #ebeef5;
border-radius: 4px;
padding: 15px;
}
.selected-items {
margin-bottom: 20px;
}
.item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
font-weight: bold;
}
.selected-list {
min-height: 40px;
border: 1px solid #ebeef5;
border-radius: 4px;
padding: 10px;
}
.item-selector {
margin-top: 20px;
}
.category-tabs {
display: flex;
border-bottom: 1px solid #ebeef5;
margin-bottom: 15px;
}
.category-tab {
padding: 10px 20px;
cursor: pointer;
border-bottom: 2px solid transparent;
transition: all 0.3s ease;
}
.category-tab:hover {
color: #409eff;
}
.category-tab.active {
color: #409eff;
border-bottom-color: #409eff;
font-weight: bold;
}
.items-list {
max-height: 300px;
overflow-y: auto;
}
.inspection-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 15px;
margin-bottom: 5px;
border: 1px solid #ebeef5;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s ease;
}
.inspection-item:hover {
border-color: #409eff;
background-color: #ecf5ff;
}
.inspection-item.selected {
border-color: #409eff;
background-color: #ecf5ff;
}
.item-itemName {
font-weight: 500;
}
.item-price {
color: #e6a23c;
font-weight: bold;
}
.inspection-details {
margin-top: 30px;
padding: 20px;
border: 1px solid #ebeef5;
border-radius: 4px;
}
.details-header {
margin-bottom: 15px;
}
.details-header h3 {
margin: 0;
color: #1a2b6d;
font-size: 16px;
font-weight: bold;
}
.inspection-selector {
border: 1px solid #ddd;
border-radius: 4px;
padding: 15px;
background: white;
}
.category-list {
margin-bottom: 15px;
}
.category-item {
display: flex;
align-items: center;
padding: 8px 12px;
cursor: pointer;
border-radius: 4px;
transition: all 0.3s ease;
margin-bottom: 2px;
}
.category-item:hover {
background-color: #f5f5f5;
}
.category-item.active {
background-color: #e6f7ff;
color: #409eff;
font-weight: bold;
}
.category-icon {
margin-right: 8px;
font-weight: bold;
width: 12px;
text-align: center;
}
.selected-summary {
margin: 10px 0;
padding: 10px;
background: #f5f5f5;
border-radius: 4px;
}
.selected-items {
margin-top: 5px;
}
.inspection-selector .items-list {
max-height: 200px;
overflow-y: auto;
border: 1px solid #ebeef5;
border-radius: 4px;
padding: 10px;
}
.inspection-selector .inspection-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
margin-bottom: 5px;
border: 1px solid #f0f0f0;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s ease;
background: #fafafa;
}
.inspection-selector .inspection-item:hover {
border-color: #409eff;
background-color: #ecf5ff;
}
.inspection-selector .inspection-item.selected {
border-color: #409eff;
background-color: #ecf5ff;
font-weight: bold;
}
/* 检验信息表格样式 */
:deep(.inspection-table) {
border: 1px solid #e4e7ed;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
}
:deep(.inspection-table .el-table__header) {
th {
background: linear-gradient(to bottom, #f8fafc 0%, #f1f5f9 100%);
border-bottom: 2px solid #e2e8f0;
color: #1e293b;
font-weight: 600;
font-size: 13px;
padding: 12px 8px;
}
}
:deep(.inspection-table .el-table__body) {
td {
border-bottom: 1px solid #f1f5f9;
padding: 10px 8px;
font-size: 13px;
color: #475569;
}
}
:deep(.inspection-table .el-table__row:hover > td) {
background-color: #f8fafc !important;
}
:deep(.inspection-table .el-table__row--striped) {
background-color: #fafbfc;
}
:deep(.inspection-table .el-table__row--striped:hover > td) {
background-color: #f1f5f9 !important;
}
:deep(.inspection-table .el-checkbox) {
margin: 0;
}
:deep(.inspection-table .el-button--small) {
font-size: 12px;
padding: 4px 8px;
}
:deep(.inspection-table .el-button--link) {
color: #409eff;
transition: color 0.3s ease;
}
:deep(.inspection-table .el-button--link:hover) {
color: #66b1ff;
}
:deep(.inspection-table .el-button--link:last-child) {
color: #f56c6c;
}
:deep(.inspection-table .el-button--link:last-child:hover) {
color: #f78989;
}
:deep(.inspection-table .cell) {
line-height: 1.4;
}
/* 新的树形结构样式 */
.category-tree {
border: 1px solid #ebeef5;
border-radius: 4px;
background: #fafafa;
}
.category-tree-item {
border-bottom: 1px solid #ebeef5;
}
.category-tree-item:last-child {
border-bottom: none;
}
.category-tree-header {
display: flex;
align-items: center;
padding: 12px 15px;
cursor: pointer;
transition: all 0.3s ease;
background: #fff;
border-radius: 4px;
margin: 2px;
}
.category-tree-header:hover {
background-color: #f5f5f5;
}
.category-tree-header.active {
background-color: #e6f7ff;
color: #409eff;
font-weight: bold;
}
.category-tree-icon {
margin-right: 8px;
font-size: 12px;
width: 12px;
text-align: center;
color: #409eff;
}
.category-count {
margin-left: auto;
color: #999;
font-size: 12px;
}
.category-tree-children {
background: #fff;
border-top: 1px solid #ebeef5;
}
.inspection-tree-item {
display: flex;
align-items: center;
padding: 8px 15px 8px 35px;
cursor: pointer;
transition: all 0.3s ease;
border-bottom: 1px solid #f0f0f0;
}
.inspection-tree-item:last-child {
border-bottom: none;
}
.inspection-tree-item:hover {
background-color: #f5f5f5;
}
.inspection-tree-item.selected {
background-color: #ecf5ff;
border-left: 3px solid #409eff;
}
.inspection-tree-item .item-itemName {
flex: 1;
margin-left: 10px;
font-weight: 500;
}
.inspection-tree-item .item-price {
color: #e6a23c;
font-weight: bold;
margin-left: 10px;
}
/* 已选项目区样式 */
.selected-items-area {
display: flex;
flex-direction: column;
}
.selected-header {
flex-shrink: 0;
}
.selected-tree {
flex: 1;
}
.selected-tree-item {
padding: 8px 0;
border-bottom: 1px solid #f0f0f0;
}
.selected-tree-item:last-child {
border-bottom: none;
}
.selected-item-content {
display: flex;
align-items: center;
padding: 8px 12px;
background: #f8f9fa;
border-radius: 4px;
margin: 2px 0;
}
.selected-item-content .item-itemName {
flex: 1;
font-weight: 500;
}
.selected-item-content .item-price {
color: #e6a23c;
font-weight: bold;
margin-right: 10px;
}
.no-selection {
text-align: center;
padding: 40px 20px;
color: #999;
}
/* 表单验证错误样式 */
.form-item-error .el-input__inner,
.form-item-error .el-textarea__inner {
border-color: #f56c6c !important;
}
.form-item-error .el-select .el-input__inner {
border-color: #f56c6c !important;
}
.is-error.el-input .el-input__inner,
.is-error.el-textarea .el-textarea__inner {
border-color: #f56c6c !important;
}
.error-message {
color: #f56c6c;
font-size: 12px;
margin-top: 4px;
line-height: 1;
}
/* 自定义消息框样式,确保其显示在最顶层 */
.custom-message-box {
z-index: 9999 !important;
}
/* 确保模态框相关元素具有高z-index */
.el-popup-parent--hidden {
overflow: hidden;
padding-right: 0 !important;
}
.v-modal {
z-index: 2000 !important;
}
/* 响应式布局 */
@media (max-width: 992px) {
.bottom-content-area {
flex-direction: column;
}
.form-area,
.selection-area {
width: 100%;
}
.el-col {
width: 100% !important;
max-width: 100% !important;
flex: 0 0 100% !important;
}
}
@media (max-width: 768px) {
.inspection-section {
padding: 10px;
}
.bottom-content-area {
padding: 0 10px 10px 10px;
gap: 15px;
}
/* 表单字段纵向排列 */
.application-form .el-form-item {
margin-bottom: 15px;
}
/* 隐藏表格非关键列 */
.inspection-table .el-table__cell:nth-child(n+4):nth-child(-n+7) {
display: none;
}
.top-action-bar {
padding: 0 10px;
}
.action-buttons {
flex-direction: column;
gap: 5px;
}
.el-button--large {
width: 100%;
}
}
/* 优化表单样式 */
.application-form {
padding: 20px;
height: 700px;
overflow-y: auto;
border: 1px solid #e4e7ed;
border-radius: 4px;
margin: 10px;
}
/* 优化已选项目区样式 */
.selected-items-area .selected-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
.selected-items-area .selected-tree {
max-height: 270px;
overflow-y: auto;
}
/* 优化搜索框样式 */
.inspection-selector .el-input {
margin-bottom: 15px;
}
/* 优化分类树样式 */
.category-tree {
max-height: 280px;
overflow-y: auto;
}
</style>