Files
his/openhis-ui-vue3/src/views/basicmanage/medicalOrderSet/components/adviceBaseList.vue
chenqi 14cb913943 refactor(table): 更新表格组件的单元格合并配置和事件处理
- 将所有表格的单元格合并方法从数组格式 [rowspan, colspan] 改为对象格式 { rowspan, colspan }
- 为 vxe-table 组件添加 checkbox-config 配置以支持复选框保留选择功能
- 移除复选框的 :reserve-selection 属性并改用 checkbox-config 配置
- 全局注册 VxeTableCompat 组件来归一化 cell-click 和 current-change 事件参数
- 更新技术执行和技术审批页面的表格组件配置和操作逻辑
- 优化
2026-06-05 11:44:31 +08:00

333 lines
8.1 KiB
Vue
Executable File
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
ref="tableWrapper"
tabindex="0"
class="table-container"
@keyup="handleKeyDown"
>
<vxe-table
ref="adviceBaseRef"
v-loading="loading"
height="350"
:data="adviceBaseList"
:row-config="{ keyField: 'patientId' }"
@current-change="handleCurrentChange"
@cell-click="clickRow"
>
<vxe-column
title="名称"
align="center"
field="adviceName"
/>
<vxe-column
title="类型"
align="center"
field="activityType_enumText"
/>
<vxe-column
title="包装单位"
align="center"
field="unitCode_dictText"
/>
<vxe-column
title="最小单位"
align="center"
field="minUnitCode_dictText"
/>
<vxe-column
title="规格"
align="center"
field="volume"
/>
<vxe-column
title="用法"
align="center"
field="methodCode_dictText"
/>
<vxe-column
title="频次"
align="center"
field="rateCode_dictText"
/>
<vxe-column
title="单次剂量"
align="center"
field="dose"
/>
<vxe-column
title="剂量单位"
align="center"
field="doseUnitCode_dictText"
/>
<vxe-column
title="注射药品"
align="center"
field="injectFlag_enumText"
/>
<vxe-column
title="皮试"
align="center"
field="skinTestFlag_enumText"
/>
</vxe-table>
<!-- 分页组件 -->
<div class="pagination-wrapper">
<el-pagination
v-model:current-page="queryParams.pageNum"
:page-size="20"
:total="total"
layout="prev, pager, next"
@current-change="handlePageChange"
/>
</div>
</div>
</template>
<script setup>
import {nextTick} from 'vue';
import {getAdviceBaseInfo} from './api';
import {debounce} from 'lodash-es';
const props = defineProps({
adviceQueryParams: {
type: Object,
default: '',
},
patientInfo: {
type: Object,
required: true,
},
});
const emit = defineEmits(['selectAdviceBase']);
const total = ref(0);
const loading = ref(false);
const adviceBaseRef = ref();
const tableWrapper = ref();
const currentIndex = ref(0); // 当前选中行索引
const currentSelectRow = ref({});
const queryParams = ref({
pageSize: 20,
pageNum: 1,
adviceTypes: '1,2,3',
organizationId: null,
});
const adviceBaseList = ref([]);
// 前端缓存 - 使用 sessionStorage 持久化缓存
const CACHE_PREFIX = 'advice_cache_';
const CACHE_EXPIRE = 5 * 60 * 1000; // 缓存5分钟
function getCacheKey(orgId, pageNum) {
return CACHE_PREFIX + orgId + '_' + pageNum;
}
function getFromCache(orgId, pageNum) {
try {
const key = getCacheKey(orgId, pageNum);
const cachedData = sessionStorage.getItem(key);
if (!cachedData) return null;
const cacheData = JSON.parse(cachedData);
if (Date.now() - cacheData.timestamp > CACHE_EXPIRE) {
sessionStorage.removeItem(key);
return null;
}
console.log('从前端缓存获取:', key);
return cacheData;
} catch (e) {
console.error('读取缓存失败:', e);
return null;
}
}
function setToCache(orgId, pageNum, data, total) {
try {
const key = getCacheKey(orgId, pageNum);
const cacheData = {
data: data,
total: total,
timestamp: Date.now()
};
sessionStorage.setItem(key, JSON.stringify(cacheData));
console.log('写入前端缓存:', key);
} catch (e) {
console.error('写入缓存失败:', e);
}
}
// 防抖函数 - 避免重复请求
const debouncedGetList = debounce(
() => {
// 只有当 organizationId 有效时才请求
if (!queryParams.value.organizationId) {
console.log('organizationId 无效,跳过请求');
return;
}
getList();
},
300,
{ leading: false, trailing: true }
);
// 监听adviceQueryParams变化
watch(
() => props.adviceQueryParams,
(newValue) => {
console.log('adviceQueryParams 变化:', newValue);
queryParams.value.searchKey = newValue.searchKey;
queryParams.value.adviceType = newValue.adviceType;
queryParams.value.organizationId = newValue.organizationId;
console.log('更新后的queryParams:', queryParams.value);
debouncedGetList();
},
{ deep: true }
);
// 监听searchKey变化
watch(
() => props.adviceQueryParams?.searchKey,
(newVal) => {
queryParams.value.searchKey = newVal;
debouncedGetList();
}
);
// 监听organizationId变化
watch(
() => props.adviceQueryParams?.organizationId,
(newVal) => {
console.log('watch organizationId 变化:', newVal);
queryParams.value.organizationId = newVal;
// 当organizationId有效时重新获取数据
if (newVal) {
debouncedGetList();
}
}
);
// 不再页面加载时立即请求,等待用户点击时再请求
function getList() {
// 确保有 organizationId 才调用API
if (!queryParams.value.organizationId) {
console.log('organizationId 为空跳过API调用');
return;
}
const orgId = queryParams.value.organizationId;
const pageNum = queryParams.value.pageNum;
// 尝试从本地缓存获取(只有第一页且无搜索关键字时使用缓存)
if (pageNum === 1 && !queryParams.value.searchKey) {
const cached = getFromCache(orgId, pageNum);
if (cached) {
adviceBaseList.value = cached.data;
total.value = cached.total;
return;
}
}
// 显示 loading
loading.value = true;
// queryParams.value.organizationId = '1922545444781481985';
getAdviceBaseInfo(queryParams.value).then((res) => {
adviceBaseList.value = res.data.records || [];
console.log('获取到医嘱数据:', adviceBaseList.value)
total.value = res.data.total || 0;
// 缓存第一页数据
if (pageNum === 1 && !queryParams.value.searchKey) {
setToCache(orgId, pageNum, adviceBaseList.value, total.value);
}
nextTick(() => {
currentIndex.value = 0;
if (adviceBaseList.value.length > 0 && adviceBaseRef.value) {
adviceBaseRef.value.setCurrentRow(adviceBaseList.value[0]);
}
});
})
.finally(() => {
loading.value = false;
});
}
// 当前页改变(分页)
function handlePageChange(page) {
queryParams.value.pageNum = page;
getList();
}
// 处理键盘事件
const handleKeyDown = (event) => {
const key = event.key;
const data = adviceBaseList.value;
switch (key) {
case 'ArrowUp': // 上箭头
event.preventDefault(); // 阻止默认滚动行为
if (currentIndex.value > 0) {
currentIndex.value--;
setCurrentRow(data[currentIndex.value]);
}
break;
case 'ArrowDown': // 下箭头`
event.preventDefault();
if (currentIndex.value < data.length - 1) {
currentIndex.value++;
setCurrentRow(data[currentIndex.value]);
}
break;
case 'Enter': // 回车键
// const currentRow = adviceBaseRef.value.getSelectionRows();
event.preventDefault();
if (currentSelectRow.value) {
// 这里可以触发自定义逻辑,如弹窗、跳转等
emit('selectAdviceBase', currentSelectRow.value);
}
break;
}
};
// 设置选中行(带滚动)
const setCurrentRow = (row) => {
adviceBaseRef.value.setCurrentRow(row);
// 滚动到选中行
const tableBody = adviceBaseRef.value.$el.querySelector('.vxe-table--body-wrapper');
const currentRowEl = adviceBaseRef.value.$el.querySelector('.current-row');
if (tableBody && currentRowEl) {
currentRowEl.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
};
// 当前行变化时更新索引
const handleCurrentChange = (currentRow) => {
currentIndex.value = adviceBaseList.value.findIndex((item) => item === currentRow);
currentSelectRow.value = currentRow;
};
function clickRow(row) {
emit('selectAdviceBase', row);
}
defineExpose({
handleKeyDown,
});
</script>
<style scoped>
.table-container {
display: flex;
flex-direction: column;
}
.pagination-wrapper {
display: flex;
justify-content: center;
padding: 10px 0;
background: #fff;
}
.popover-table-wrapper:focus {
outline: 2px solid #3B82F6;
}
</style>