Files
his/openhis-ui-vue3/src/views/outpatient/doctor/examination/index.vue
2026-05-27 00:45:59 +08:00

274 lines
6.6 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="examination-application-container">
<el-row :gutter="16">
<!-- 左侧检查项目分类 -->
<el-col :span="6">
<el-card shadow="never" class="category-panel">
<template #header>检查项目分类</template>
<el-tree
:data="categoryTree"
:props="{ label: 'name', children: 'children' }"
node-key="id"
highlight-current
@node-click="handleCategorySelect"
data-cy="category-tree"
/>
</el-card>
</el-col>
<!-- 中间检查项目列表 -->
<el-col :span="9">
<el-card shadow="never" class="item-panel">
<template #header>检查项目</template>
<div class="item-scroll-area">
<div v-for="item in currentItems" :key="item.id" class="item-row">
<el-checkbox
v-model="item.checked"
@change="handleItemToggle(item)"
data-cy="item-checkbox"
>
{{ cleanDisplayName(item.name) }}
</el-checkbox>
</div>
</div>
</el-card>
</el-col>
<!-- 右侧已选择区域 -->
<el-col :span="9">
<el-card shadow="never" class="selected-panel">
<template #header>已选择</template>
<div class="selected-scroll-area">
<div v-if="selectedItems.length === 0" class="empty-tip">暂无选择项目</div>
<div
v-for="sel in selectedItems"
:key="sel.id"
class="selected-card"
data-cy="selected-card"
>
<div class="card-header" @click="toggleDetail(sel)">
<el-icon class="arrow-icon" :class="{ expanded: sel.expanded }">
<ArrowRight />
</el-icon>
<el-tooltip
:content="cleanDisplayName(sel.name)"
placement="top"
:show-after="300"
:hide-after="0"
>
<span class="card-name" data-cy="selected-card-name">
{{ cleanDisplayName(sel.name) }}
</span>
</el-tooltip>
<el-icon class="expand-toggle" data-cy="expand-toggle">
<ArrowDown />
</el-icon>
</div>
<transition name="detail-slide">
<div v-show="sel.expanded" class="card-details">
<div v-for="method in sel.methods" :key="method.id" class="method-row">
<el-checkbox
v-model="method.checked"
@change="handleMethodToggle(sel, method)"
data-cy="method-checkbox"
>
{{ method.name }}
</el-checkbox>
</div>
</div>
</transition>
</div>
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { ArrowRight, ArrowDown } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
// 类型定义
interface ExamMethod {
id: string
name: string
checked: boolean
}
interface ExamItem {
id: string
name: string
checked: boolean
methods: ExamMethod[]
}
interface CategoryNode {
id: string
name: string
children?: CategoryNode[]
items?: ExamItem[]
}
// 状态管理
const categoryTree = ref<CategoryNode[]>([])
const currentItems = ref<ExamItem[]>([])
const selectedItems = ref<ExamItem[]>([])
// 核心修复1名称清洗去除冗余“套餐”字样
const cleanDisplayName = (name: string) => {
if (!name) return ''
return name.replace(/套餐/g, '').trim()
}
// 分类切换
const handleCategorySelect = (data: CategoryNode) => {
currentItems.value = data.items || []
}
// 核心修复2项目与方法解耦禁止自动联动勾选
const handleItemToggle = (item: ExamItem) => {
if (item.checked) {
const exists = selectedItems.value.find(s => s.id === item.id)
if (!exists) {
selectedItems.value.push({
...item,
expanded: false, // 核心修复3默认收起状态
methods: item.methods?.map(m => ({ ...m, checked: false })) || [] // 方法默认不勾选
})
}
} else {
selectedItems.value = selectedItems.value.filter(s => s.id !== item.id)
}
}
// 方法独立勾选(不反向影响父级项目)
const handleMethodToggle = (parent: ExamItem, method: ExamMethod) => {
// 仅记录方法状态,不触发父级联动逻辑
if (!method.checked) {
ElMessage.info(`已取消方法:${method.name}`)
}
}
// 核心修复3展开/收起明细交互
const toggleDetail = (sel: ExamItem) => {
sel.expanded = !sel.expanded
}
</script>
<style scoped>
.examination-application-container {
padding: 16px;
background: #f5f7fa;
min-height: 100vh;
}
.category-panel, .item-panel, .selected-panel {
height: 600px;
display: flex;
flex-direction: column;
}
.category-panel :deep(.el-card__body),
.item-panel :deep(.el-card__body),
.selected-panel :deep(.el-card__body) {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
.item-scroll-area, .selected-scroll-area {
flex: 1;
overflow-y: auto;
padding-right: 8px;
}
.item-row {
padding: 10px 0;
border-bottom: 1px dashed #ebeef5;
}
/* 核心修复2卡片宽度自适应去除固定宽度导致的截断 */
.selected-card {
border: 1px solid #dcdfe6;
border-radius: 6px;
margin-bottom: 12px;
background: #fff;
width: 100%;
box-sizing: border-box;
overflow: hidden;
}
.card-header {
display: flex;
align-items: center;
padding: 12px;
cursor: pointer;
background: #fafafa;
transition: background 0.2s;
}
.card-header:hover {
background: #f0f2f5;
}
.arrow-icon {
transition: transform 0.25s ease;
margin-right: 6px;
}
.arrow-icon.expanded {
transform: rotate(90deg);
}
.card-name {
flex: 1;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-right: 8px;
}
.card-details {
padding: 8px 12px 12px 32px;
background: #fcfcfc;
border-top: 1px solid #ebeef5;
}
.method-row {
padding: 6px 0;
display: flex;
align-items: center;
}
.expand-toggle {
color: #909399;
font-size: 14px;
}
.empty-tip {
text-align: center;
color: #909399;
padding: 40px 0;
}
.detail-slide-enter-active,
.detail-slide-leave-active {
transition: all 0.3s ease;
max-height: 200px;
opacity: 1;
}
.detail-slide-enter-from,
.detail-slide-leave-to {
max-height: 0;
opacity: 0;
padding-top: 0;
padding-bottom: 0;
}
</style>