Files
his/openhis-ui-vue3/src/views/outpatient/examination/ExamApply.vue
2026-05-26 23:55:02 +08:00

152 lines
5.9 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>
<div class="exam-apply-container">
<el-row :gutter="20">
<!-- 左侧检查项目分类 -->
<el-col :span="6">
<el-card shadow="never">
<template #header>检查项目分类</template>
<el-tree
:data="categories"
node-key="id"
highlight-current
@node-click="handleCategoryClick"
data-cy="category-tree"
/>
</el-card>
</el-col>
<!-- 中间项目列表 & 检查方法 -->
<el-col :span="10">
<el-card shadow="never" class="mb-20">
<template #header>检查项目</template>
<div class="item-list" data-cy="item-list">
<div v-for="item in currentItems" :key="item.id" class="item-row">
<el-checkbox v-model="item.checked" @change="handleItemCheck(item)" />
<el-tooltip :content="item.name" placement="top" :show-after="300">
<span class="item-name-text">{{ item.name }}</span>
</el-tooltip>
</div>
</div>
</el-card>
<el-card shadow="never">
<template #header>检查方法</template>
<div class="method-list" data-cy="method-list">
<div v-for="method in availableMethods" :key="method.id" class="method-row">
<el-checkbox v-model="method.checked" @change="handleMethodCheck(method)" />
<span>{{ method.name }}</span>
</div>
</div>
</el-card>
</el-col>
<!-- 右侧/下方已选择区域 -->
<el-col :span="8">
<el-card shadow="never">
<template #header>已选择项目</template>
<div class="selected-area" data-cy="selected-area">
<el-empty v-if="selectedItems.length === 0" description="暂无选择项目" />
<el-collapse v-else v-model="activeCollapseNames" accordion>
<el-collapse-item
v-for="sel in selectedItems"
:key="sel.id"
:name="sel.id"
data-cy="selected-card"
>
<template #title>
<div class="card-header">
<el-tooltip :content="cleanName(sel.name)" placement="top" :show-after="500">
<span class="item-name">{{ cleanName(sel.name) }}</span>
</el-tooltip>
<el-tag size="small" type="info" class="ml-2">{{ sel.type || '项目' }}</el-tag>
</div>
</template>
<!-- 结构化明细默认收起去除冗余标签严格遵循 项目 > 检查方法 层级 -->
<div class="details-panel" data-cy="details-panel">
<div v-if="sel.methods && sel.methods.length > 0" class="method-group">
<div class="group-title">检查方法</div>
<div v-for="m in sel.methods" :key="m.id" class="method-item">
<el-checkbox v-model="m.checked" @change="handleDetailMethodCheck(sel, m)" />
<span>{{ m.name }}</span>
</div>
</div>
<div v-else class="empty-detail">无关联检查方法</div>
</div>
</el-collapse-item>
</el-collapse>
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script setup>
import { ref } from 'vue'
// 状态定义
const categories = ref([])
const currentItems = ref([])
const availableMethods = ref([])
const selectedItems = ref([])
const activeCollapseNames = ref([]) // 默认空数组,确保所有卡片初始为收起状态
// 分类点击:加载对应项目与方法
const handleCategoryClick = (data) => {
// 实际项目中此处应调用 API 获取数据,此处为结构演示
currentItems.value = [
{ id: 101, name: '套餐128线排彩超', checked: false, type: '套餐', methods: [
{ id: 201, name: '常规扫查', checked: false },
{ id: 202, name: '血流多普勒', checked: false }
]}
]
availableMethods.value = [
{ id: 301, name: '独立检查方法A', checked: false },
{ id: 302, name: '独立检查方法B', checked: false }
]
}
// 修复1项目勾选与检查方法完全解耦不触发自动联动
const handleItemCheck = (item) => {
if (item.checked) {
const exists = selectedItems.value.find(s => s.id === item.id)
if (!exists) {
// 深拷贝避免引用污染,保留关联方法供明细展示
selectedItems.value.push({ ...item, methods: item.methods ? [...item.methods] : [] })
}
} else {
selectedItems.value = selectedItems.value.filter(s => s.id !== item.id)
}
}
// 修复1中间区域检查方法独立勾选不反向影响项目
const handleMethodCheck = (method) => {
// 仅维护中间列表状态,业务层按需处理
}
// 明细内方法独立勾选
const handleDetailMethodCheck = (parent, method) => {
// 仅更新当前套餐/项目下的方法状态
}
// 修复2清理名称去除“套餐”前缀及冗余符号
const cleanName = (name) => {
if (!name) return ''
return name.replace(/^套餐[:]/, '').trim()
}
</script>
<style scoped>
.exam-apply-container { padding: 20px; }
.mb-20 { margin-bottom: 20px; }
.item-row, .method-row { display: flex; align-items: center; padding: 8px 0; gap: 8px; }
.item-name-text { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.card-header { display: flex; align-items: center; width: 100%; }
.item-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ml-2 { margin-left: 8px; }
.details-panel { padding: 12px; background: #f5f7fa; border-radius: 4px; margin-top: 4px; }
.group-title { font-weight: 600; margin-bottom: 8px; color: #606266; font-size: 13px; }
.method-item { display: flex; align-items: center; padding: 4px 0; gap: 8px; }
.empty-detail { color: #909399; font-size: 12px; padding: 4px 0; }
</style>