Fix Bug #550: AI修复
This commit is contained in:
@@ -1,124 +1,272 @@
|
||||
<template>
|
||||
<div class="check-request">
|
||||
<el-table
|
||||
ref="table"
|
||||
:data="requestList"
|
||||
style="width: 100%"
|
||||
@selection-change="handleSelectionChange"
|
||||
:row-key="row => row.id"
|
||||
:default-expand-all="true"
|
||||
>
|
||||
<!-- 解决名称遮挡:使用 tooltip 并限制宽度 -->
|
||||
<el-table-column
|
||||
prop="itemName"
|
||||
label="检查项目"
|
||||
width="200"
|
||||
:show-overflow-tooltip="true"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-tooltip
|
||||
class="item"
|
||||
effect="dark"
|
||||
:content="row.itemName"
|
||||
placement="top-start"
|
||||
>
|
||||
<span class="ellipsis">{{ row.itemName }}</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<div class="check-request-container">
|
||||
<div class="layout-wrapper">
|
||||
<!-- 左侧:检查项目分类 -->
|
||||
<div class="panel left-panel">
|
||||
<h3 class="panel-title">检查项目分类</h3>
|
||||
<el-tree
|
||||
:data="categoryTree"
|
||||
:props="{ label: 'name', children: 'children' }"
|
||||
@node-click="handleCategoryClick"
|
||||
highlight-current
|
||||
default-expand-all
|
||||
class="category-tree"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 解决自动勾选冲突:改为手动控制勾选状态 -->
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55"
|
||||
:selectable="selectableRow"
|
||||
/>
|
||||
<!-- 中间:检查项目列表 -->
|
||||
<div class="panel middle-panel">
|
||||
<h3 class="panel-title">检查项目</h3>
|
||||
<el-table
|
||||
:data="currentItems"
|
||||
@selection-change="handleItemSelection"
|
||||
row-key="id"
|
||||
border
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column prop="name" label="项目名称" show-overflow-tooltip />
|
||||
<el-table-column prop="spec" label="规格" width="120" />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 其他列保持不变 -->
|
||||
<el-table-column prop="spec" label="规格" width="120" />
|
||||
<el-table-column prop="deptName" label="申请科室" width="120" />
|
||||
<el-table-column prop="applyDoctor" label="申请医生" width="120" />
|
||||
<el-table-column prop="applyTime" label="申请时间" width="180" />
|
||||
</el-table>
|
||||
<!-- 右侧:已选择区域 & 检查方法 -->
|
||||
<div class="panel right-panel">
|
||||
<h3 class="panel-title">已选择项目</h3>
|
||||
<div class="selected-list">
|
||||
<div v-for="item in selectedItems" :key="item.id" class="selected-card">
|
||||
<div class="card-header" @click="toggleExpand(item)">
|
||||
<el-checkbox
|
||||
v-model="item.checked"
|
||||
@change="handleItemCheckChange(item)"
|
||||
@click.stop
|
||||
/>
|
||||
<el-tooltip :content="item.name" placement="top" :show-after="300">
|
||||
<span class="item-name">{{ item.name }}</span>
|
||||
</el-tooltip>
|
||||
<el-icon class="expand-icon">
|
||||
<ArrowDown v-if="item.expanded" />
|
||||
<ArrowRight v-else />
|
||||
</el-icon>
|
||||
</div>
|
||||
<!-- 检查方法/明细区域 (默认收起) -->
|
||||
<transition name="slide-fade">
|
||||
<div v-show="item.expanded" class="method-list">
|
||||
<div v-for="method in item.methods" :key="method.id" class="method-item">
|
||||
<el-checkbox
|
||||
v-model="method.checked"
|
||||
@change="handleMethodCheckChange(item, method)"
|
||||
@click.stop
|
||||
/>
|
||||
<span class="method-name">{{ method.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
<div v-if="selectedItems.length === 0" class="empty-tip">暂无选择项目</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<el-button type="primary" @click="confirmSelection">确认</el-button>
|
||||
<el-button @click="clearSelection">清空</el-button>
|
||||
<el-button type="primary" @click="submitRequests" :loading="submitting">提交申请</el-button>
|
||||
<el-button @click="clearAll">清空</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, reactive } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { ArrowDown, ArrowRight } from '@element-plus/icons-vue';
|
||||
import { fetchCheckRequests, submitCheckRequests } from '@/api/outpatient';
|
||||
|
||||
const requestList = ref([]);
|
||||
const selectedRows = ref([]);
|
||||
// 模拟分类树数据(实际应从接口获取)
|
||||
const categoryTree = ref([
|
||||
{ id: 'cat1', name: '彩超', children: [] },
|
||||
{ id: 'cat2', name: 'CT', children: [] },
|
||||
{ id: 'cat3', name: 'MRI', children: [] }
|
||||
]);
|
||||
|
||||
// 表格实例
|
||||
const table = ref(null);
|
||||
const currentItems = ref([]);
|
||||
const selectedItems = reactive([]);
|
||||
const submitting = ref(false);
|
||||
|
||||
// 获取检查申请列表
|
||||
onMounted(async () => {
|
||||
const { data } = await fetchCheckRequests();
|
||||
requestList.value = data;
|
||||
});
|
||||
|
||||
// 行是否可选:防止同一检查项目的冲突自动勾选
|
||||
const selectableRow = (row) => {
|
||||
// 同一检查项目(itemCode)只能选中一条
|
||||
const alreadySelected = selectedRows.value.some(
|
||||
(item) => item.itemCode === row.itemCode
|
||||
);
|
||||
return !alreadySelected;
|
||||
// 点击分类加载项目
|
||||
const handleCategoryClick = async (data) => {
|
||||
// 实际项目中替换为真实API调用
|
||||
currentItems.value = [
|
||||
{ id: `${data.id}_1`, name: '128线排彩超', spec: '常规', methods: [
|
||||
{ id: 'm1', name: '腹部彩超', checked: false },
|
||||
{ id: 'm2', name: '心脏彩超', checked: false }
|
||||
]},
|
||||
{ id: `${data.id}_2`, name: '高频浅表彩超', spec: '高频', methods: [
|
||||
{ id: 'm3', name: '甲状腺彩超', checked: false }
|
||||
]}
|
||||
];
|
||||
};
|
||||
|
||||
// 处理手动勾选变化
|
||||
const handleSelectionChange = (selection) => {
|
||||
selectedRows.value = selection;
|
||||
// 中间表格勾选联动(仅添加/移除卡片,不自动勾选方法)
|
||||
const handleItemSelection = (selection) => {
|
||||
const selectedIds = new Set(selection.map(i => i.id));
|
||||
|
||||
// 移除未勾选的
|
||||
for (let i = selectedItems.length - 1; i >= 0; i--) {
|
||||
if (!selectedIds.has(selectedItems[i].id)) {
|
||||
selectedItems.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// 新增勾选的
|
||||
selection.forEach(item => {
|
||||
if (!selectedItems.find(s => s.id === item.id)) {
|
||||
selectedItems.push({
|
||||
...item,
|
||||
checked: true,
|
||||
expanded: false, // 默认收起
|
||||
methods: item.methods.map(m => ({ ...m, checked: false })) // 方法独立状态
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 确认选择
|
||||
const confirmSelection = async () => {
|
||||
if (selectedRows.value.length === 0) {
|
||||
ElMessage.warning('请先选择检查项目');
|
||||
// 项目勾选状态变更
|
||||
const handleItemCheckChange = (item) => {
|
||||
// 仅控制项目本身状态,不联动方法
|
||||
};
|
||||
|
||||
// 方法勾选状态变更(完全独立)
|
||||
const handleMethodCheckChange = (item, method) => {
|
||||
// 独立控制,无联动逻辑
|
||||
};
|
||||
|
||||
// 展开/收起明细
|
||||
const toggleExpand = (item) => {
|
||||
item.expanded = !item.expanded;
|
||||
};
|
||||
|
||||
// 提交申请
|
||||
const submitRequests = async () => {
|
||||
const payload = selectedItems
|
||||
.filter(i => i.checked)
|
||||
.map(i => ({
|
||||
itemCode: i.id,
|
||||
itemName: i.name,
|
||||
spec: i.spec,
|
||||
methods: i.methods.filter(m => m.checked).map(m => ({ methodCode: m.id, methodName: m.name }))
|
||||
}));
|
||||
|
||||
if (payload.length === 0) {
|
||||
ElMessage.warning('请至少选择一个检查项目');
|
||||
return;
|
||||
}
|
||||
|
||||
submitting.value = true;
|
||||
try {
|
||||
await submitCheckRequests(selectedRows.value);
|
||||
ElMessage.success('检查申请已提交');
|
||||
// 提交成功后刷新列表并清空选择
|
||||
const { data } = await fetchCheckRequests();
|
||||
requestList.value = data;
|
||||
clearSelection();
|
||||
} catch (e) {
|
||||
ElMessage.error('提交失败,请重试');
|
||||
await submitCheckRequests(payload);
|
||||
ElMessage.success('提交成功');
|
||||
clearAll();
|
||||
} catch (err) {
|
||||
ElMessage.error(err.message || '提交失败');
|
||||
} finally {
|
||||
submitting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 清空选择
|
||||
const clearSelection = () => {
|
||||
selectedRows.value = [];
|
||||
if (table.value) {
|
||||
table.value.clearSelection();
|
||||
}
|
||||
// 清空
|
||||
const clearAll = () => {
|
||||
selectedItems.length = 0;
|
||||
currentItems.value = [];
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.check-request {
|
||||
.check-request-container {
|
||||
padding: 20px;
|
||||
background: #f5f7fa;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.actions {
|
||||
margin-top: 20px;
|
||||
text-align: right;
|
||||
.layout-wrapper {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.ellipsis {
|
||||
display: inline-block;
|
||||
max-width: 180px;
|
||||
.panel {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
|
||||
}
|
||||
.left-panel { flex: 1; min-width: 200px; }
|
||||
.middle-panel { flex: 2; min-width: 300px; }
|
||||
.right-panel { flex: 2; min-width: 300px; }
|
||||
.panel-title {
|
||||
margin: 0 0 12px 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
.category-tree { max-height: 500px; overflow-y: auto; }
|
||||
.selected-list {
|
||||
max-height: 450px;
|
||||
overflow-y: auto;
|
||||
padding-right: 4px;
|
||||
}
|
||||
.selected-card {
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 10px;
|
||||
background: #fafafa;
|
||||
overflow: hidden;
|
||||
}
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 12px;
|
||||
cursor: pointer;
|
||||
background: #fff;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.card-header:hover { background: #f0f2f5; }
|
||||
.item-name {
|
||||
flex: 1;
|
||||
margin: 0 10px;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.expand-icon { color: #909399; }
|
||||
.method-list {
|
||||
padding: 8px 12px 12px 32px;
|
||||
background: #f9fafc;
|
||||
border-top: 1px dashed #ebeef5;
|
||||
}
|
||||
.method-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 6px 0;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
}
|
||||
.method-name { margin-left: 8px; }
|
||||
.empty-tip {
|
||||
text-align: center;
|
||||
color: #909399;
|
||||
padding: 40px 0;
|
||||
}
|
||||
.actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
}
|
||||
.slide-fade-enter-active, .slide-fade-leave-active {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.slide-fade-enter-from, .slide-fade-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user