Files
his/openhis-ui-vue3/src/views/outpatient/doctor/components/ExamItemSelector.vue
2026-05-27 01:42:02 +08:00

184 lines
5.2 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-item-selector">
<div class="selector-layout">
<!-- 左侧检查项目分类 -->
<div class="panel category-panel">
<h4 class="panel-title">检查项目分类</h4>
<el-tree
:data="categoryTree"
node-key="id"
highlight-current
default-expand-all
@node-click="handleCategorySelect"
/>
</div>
<!-- 中间检查项目列表 -->
<div class="panel item-panel">
<h4 class="panel-title">检查项目</h4>
<el-checkbox-group v-model="selectedItemIds" @change="onItemChange" class="item-list">
<el-checkbox v-for="item in currentItems" :key="item.id" :label="item.id" class="item-checkbox">
{{ item.name }}
</el-checkbox>
</el-checkbox-group>
</div>
<!-- 右侧/下方已选择区域 -->
<div class="panel selected-panel">
<h4 class="panel-title">已选择</h4>
<!-- 修复3结构化展示 & 默认收起 -->
<el-collapse v-model="activeCollapseNames" accordion class="selected-collapse">
<el-collapse-item
v-for="group in selectedGroups"
:key="group.itemId"
:name="group.itemId"
>
<template #title>
<!-- 修复2宽度自适应/提示完整名称去除套餐前缀 -->
<el-tooltip :content="group.itemName" placement="top" :show-after="300">
<span class="group-title">{{ group.itemName }}</span>
</el-tooltip>
</template>
<div class="method-section">
<el-checkbox-group v-model="group.selectedMethodIds" @change="onMethodChange(group)">
<el-checkbox v-for="method in group.methods" :key="method.id" :label="method.id">
{{ method.name }}
</el-checkbox>
</el-checkbox-group>
</div>
</el-collapse-item>
</el-collapse>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
// 模拟数据结构 (实际应从API获取)
interface CategoryNode { id: string; name: string; children?: ExamItem[] }
interface ExamItem { id: string; name: string; methods?: ExamMethod[] }
interface ExamMethod { id: string; name: string }
const categoryTree = ref<CategoryNode[]>([
{
id: 'cat_1', name: '彩超', children: [
{ id: 'item_1', name: '128线排套餐', methods: [{ id: 'm1', name: '常规' }, { id: 'm2', name: '三维' }] },
{ id: 'item_2', name: '腹部彩超', methods: [{ id: 'm3', name: '常规' }] }
]
}
])
const currentItems = ref<ExamItem[]>([])
const selectedItemIds = ref<string[]>([])
// 修复3默认空数组实现面板默认收起状态
const activeCollapseNames = ref<string[]>([])
// 已选数据映射:独立维护项目与方法状态
const selectedDataMap = ref<Map<string, { id: string; name: string; methods: ExamMethod[]; selectedMethodIds: string[] }>>(new Map())
// 计算属性:渲染已选择分组
const selectedGroups = computed(() => {
return Array.from(selectedDataMap.value.values()).map(item => ({
itemId: item.id,
// 修复2清理冗余“套餐”字样
itemName: item.name.replace(/套餐/g, ''),
methods: item.methods || [],
selectedMethodIds: item.selectedMethodIds || []
}))
})
// 分类点击
const handleCategorySelect = (node: CategoryNode) => {
currentItems.value = node.children || []
}
// 修复1项目勾选与检查方法解耦
const onItemChange = (ids: string[]) => {
const added = ids.filter(id => !selectedItemIds.value.includes(id))
const removed = selectedItemIds.value.filter(id => !ids.includes(id))
// 处理新增项目
added.forEach(id => {
const item = currentItems.value.find(i => i.id === id)
if (item) {
selectedDataMap.value.set(id, {
id: item.id,
name: item.name,
methods: item.methods || [],
// 关键修复:不自动勾选关联方法,保持独立手动选择
selectedMethodIds: []
})
}
})
// 处理移除项目
removed.forEach(id => {
selectedDataMap.value.delete(id)
})
selectedItemIds.value = ids
}
// 方法独立勾选变更
const onMethodChange = (group: { itemId: string; selectedMethodIds: string[] }) => {
const item = selectedDataMap.value.get(group.itemId)
if (item) {
item.selectedMethodIds = group.selectedMethodIds
}
}
</script>
<style scoped>
.exam-item-selector {
padding: 12px;
background: #fff;
border-radius: 4px;
}
.selector-layout {
display: flex;
gap: 12px;
height: 480px;
}
.panel {
flex: 1;
border: 1px solid #ebeef5;
border-radius: 4px;
padding: 10px;
overflow-y: auto;
background: #fafafa;
}
.panel-title {
margin: 0 0 10px 0;
font-size: 14px;
font-weight: 600;
color: #303133;
}
.item-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.item-checkbox {
margin-right: 0;
}
.selected-collapse {
border: none;
}
.group-title {
max-width: 140px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
font-weight: 500;
color: #409eff;
}
.method-section {
padding: 8px 0 8px 16px;
border-left: 2px solid #e4e7ed;
margin-left: 4px;
}
</style>