前端最新版本同步
This commit is contained in:
@@ -1,2 +1,436 @@
|
||||
<template>
|
||||
</template>
|
||||
<div class="case-templates-container">
|
||||
<!-- 顶部工具栏 -->
|
||||
<div class="toolbar">
|
||||
<el-button type="primary" @click="newTemplate">新建</el-button>
|
||||
<el-button type="primary" @click="editTemplate">编辑</el-button>
|
||||
<el-button @click="refresh">刷新</el-button>
|
||||
<el-button type="danger" @click="deleteTemplate">删除</el-button>
|
||||
<el-button @click="printTemplate">打印</el-button>
|
||||
</div>
|
||||
|
||||
<div class="content-area">
|
||||
<!-- 左侧病历类型树 -->
|
||||
<div class="left-panel">
|
||||
<div style="margin-bottom: 10px">
|
||||
<el-tree-select
|
||||
v-model="orgId"
|
||||
:data="orgOptions"
|
||||
:props="{
|
||||
value: 'id',
|
||||
label: 'name',
|
||||
children: 'children',
|
||||
}"
|
||||
value-key="id"
|
||||
placeholder="请选择就诊科室"
|
||||
check-strictly
|
||||
:expand-on-click-node="false"
|
||||
:filter-node-method="filterNode"
|
||||
ref="locationTreeRef"
|
||||
node-key="id"
|
||||
highlight-current
|
||||
default-expand-all
|
||||
@node-click="initTemplateTree"
|
||||
@clear="handleOrgClear"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
<div class="search-box">
|
||||
<el-input
|
||||
placeholder="病历名称搜索..."
|
||||
v-model="searchKeyword"
|
||||
></el-input>
|
||||
<el-button class="search-btn" @click="handleSearch">查询</el-button>
|
||||
</div>
|
||||
|
||||
<el-tree
|
||||
ref="templateTree"
|
||||
:data="templateData"
|
||||
:props="defaultProps"
|
||||
node-key="id"
|
||||
@node-click="handleNodeClick"
|
||||
class="template-tree"
|
||||
></el-tree>
|
||||
<el-button @click="toggleExpand">{{ isExpanded ? '全部收起' : '全部展开' }}</el-button>
|
||||
</div>
|
||||
<div class="middle-panel">
|
||||
<el-tabs v-model="activeName" type="card" class="demo-tabs" @tab-click="handleClick">
|
||||
<el-tab-pane label="打印预览" name="first">
|
||||
<!-- {{components}} -->
|
||||
<component :is="currentComponent" />
|
||||
</el-tab-pane>
|
||||
<!-- <el-tab-pane label="编辑内容" name="second">
|
||||
<component :is="currentComponent" />
|
||||
</el-tab-pane> -->
|
||||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
<EditTemplate
|
||||
v-model:dialogVisible="dialogVisible"
|
||||
:title="currentNodeData ? '编辑病历文件信息' : '病历文件基本信息'"
|
||||
:formData="formData"
|
||||
:currentNodeData="currentNodeData"
|
||||
@submitOk="handleSubmitOk"
|
||||
:docTypes="templateDataInit.docTypes"
|
||||
:useRanges="templateDataInit.useRanges"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
// 从Vue导入所需的API
|
||||
import { ref, reactive, onMounted, defineAsyncComponent, nextTick, watch } from 'vue';
|
||||
import { ElMessageBox, ElMessage, ElLoading, ElTree } from 'element-plus';
|
||||
import { getTreeList, init, getDefinitionById, deleteDefinition,getLocationTree } from './api';
|
||||
import EditTemplate from './components/editTemplate.vue';
|
||||
// 添加当前模板路径和组件的响应式变量
|
||||
const currentComponent = ref('');
|
||||
const currentNodeData = ref(null); // 存储当前选中的节点数据
|
||||
const isExpanded = ref(true); // 控制树形结构的展开状态
|
||||
// 弹窗可见性
|
||||
const dialogVisible = ref(false);
|
||||
|
||||
const orgId = ref('');
|
||||
const orgOptions = ref([]); // 科室选项(整数ID)
|
||||
const locationTreeRef = ref(null); // TreeSelect引用
|
||||
const templateTree = ref(null);
|
||||
const searchKeyword = ref(''); // 搜索关键字
|
||||
|
||||
const activeName = ref('first');
|
||||
// Transfer组件选项类型定义(ID为整数类型)
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
primaryMenuEnum: undefined,
|
||||
subMenu: '',
|
||||
displayOrder: 1,
|
||||
version: '',
|
||||
name: '',
|
||||
vueRouter: '',
|
||||
useRangeEnum: 0, // 默认"暂不使用"(0:暂不使用,1:全院使用,2:科室使用)
|
||||
organizationIds: [], // 选中的科室ID列表(整数类型)
|
||||
environment: '0',
|
||||
});
|
||||
|
||||
const initFormData = () => {
|
||||
formData.primaryMenuEnum = undefined;
|
||||
formData.subMenu = '';
|
||||
formData.displayOrder = 1;
|
||||
formData.version = '';
|
||||
formData.name = '';
|
||||
formData.vueRouter = '';
|
||||
formData.useRangeEnum = 0;
|
||||
formData.organizationIds = [];
|
||||
formData.environment = '0';
|
||||
};
|
||||
const getLocationInfo = () => {
|
||||
getLocationTree().then((response) => {
|
||||
orgOptions.value = response?.data || [];
|
||||
}).catch((error) => {
|
||||
ElMessage.error('获取科室树失败');
|
||||
});
|
||||
}
|
||||
const handleSubmitOk = () => {
|
||||
dialogVisible.value = false;
|
||||
initFormData();
|
||||
refresh();
|
||||
};
|
||||
|
||||
// 组件初始化时加载基础数据
|
||||
onMounted(() => {
|
||||
getInit(); // 加载模板初始化数据(一级菜单、使用范围等)
|
||||
getLocationInfo(); // 加载科室树
|
||||
handleOrgClear(); // 初始化模板树(加载所有科室模板)
|
||||
});
|
||||
|
||||
/** 将树形结构转换为Transfer组件所需的格式(不扁平化,保留层级关系) */
|
||||
const convertTreeToTransferFormat = (tree) => {
|
||||
return tree.map((item) => {
|
||||
const option = {
|
||||
key: item.id, // 整数ID
|
||||
label: item.name,
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
// 如果有子节点,递归处理(Transfer组件会自动处理层级显示)
|
||||
if (item.children && item.children.length > 0) {
|
||||
option.children = convertTreeToTransferFormat(item.children);
|
||||
}
|
||||
|
||||
return option;
|
||||
});
|
||||
};
|
||||
|
||||
// 病历模板树数据
|
||||
const templateData = ref([]);
|
||||
const templateDataInit = ref({}); // 初始化数据(菜单、使用范围)
|
||||
|
||||
// 树配置(模板树)
|
||||
const defaultProps = {
|
||||
children: 'children',
|
||||
label: 'name',
|
||||
value: 'id',
|
||||
};
|
||||
|
||||
/** 过滤节点(科室TreeSelect搜索) */
|
||||
const filterNode = (value, data) => {
|
||||
if (!value) return true;
|
||||
return data?.name.toLowerCase().includes(value.toLowerCase()); // 不区分大小写搜索
|
||||
};
|
||||
|
||||
/** 统一的API错误处理函数 */
|
||||
const handleApiError = (userMessage, logMessage) => {
|
||||
return (error) => {
|
||||
// 记录详细错误日志,包括错误对象和调用栈
|
||||
console.error(`${logMessage}:`, error);
|
||||
// 显示用户友好的错误提示
|
||||
ElMessage.error(
|
||||
`${userMessage}失败${error.message ? ': ' + error.message : ',请刷新页面重试'}`
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
/** 加载模板初始化数据(一级菜单、使用范围枚举) */
|
||||
const getInit = async () => {
|
||||
try {
|
||||
const response = await init();
|
||||
templateDataInit.value = response.data || {};
|
||||
console.log('模板初始化数据:', templateDataInit.value);
|
||||
} catch (error) {
|
||||
handleApiError('初始化', '初始化接口异常')(error);
|
||||
}
|
||||
};
|
||||
|
||||
/** 清除科室选择时,加载所有科室模板 */
|
||||
const handleOrgClear = () => {
|
||||
orgId.value = '';
|
||||
initTemplateTree({ id: '' });
|
||||
};
|
||||
|
||||
/** 搜索模板(可扩展按科室+关键字筛选) */
|
||||
const handleSearch = () => {
|
||||
console.log('搜索模板,关键字:', searchKeyword.value);
|
||||
initTemplateTree({ id: orgId.value });
|
||||
};
|
||||
|
||||
/** 初始化病历模板树(按科室筛选) */
|
||||
function initTemplateTree(data) {
|
||||
const queryParams = {
|
||||
organizationId: data.id || '', // 科室ID(空表示所有科室)
|
||||
name: searchKeyword.value || '', // 模板名称(空表示不筛选)
|
||||
};
|
||||
|
||||
getTreeList(queryParams)
|
||||
.then((res) => {
|
||||
templateData.value = res.data || [];
|
||||
nextTick().then(() => {
|
||||
expandTree(); // 展开树节点
|
||||
})
|
||||
|
||||
// console.log('模板树数据(按科室筛选):', templateData.value);
|
||||
})
|
||||
.catch((error) => {
|
||||
handleApiError('获取模板列表', '获取模板树失败')(error);
|
||||
templateData.value = [];
|
||||
});
|
||||
}
|
||||
|
||||
/** 编辑模板(打开弹窗并回显数据) */
|
||||
const editTemplate = async () => {
|
||||
if (!currentNodeData.value) {
|
||||
ElMessage.warning('请先选择一个模板节点');
|
||||
return;
|
||||
}
|
||||
const loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: '加载模板信息...',
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await getDefinitionById(currentNodeData.value.id);
|
||||
if (response.data) {
|
||||
openEditDialog(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
handleApiError('加载模板信息', '加载模板信息失败')(error);
|
||||
} finally {
|
||||
loading.close();
|
||||
}
|
||||
};
|
||||
|
||||
/** 打开编辑弹窗,回显选中的模板数据并正确初始化科室选择 */
|
||||
const openEditDialog = async (nodeData) => {
|
||||
currentNodeData.value = nodeData;
|
||||
console.log('回显模板数据:', nodeData);
|
||||
|
||||
// 回显表单数据(与接口返回字段匹配)
|
||||
formData.primaryMenuEnum = nodeData.primaryMenuEnum;
|
||||
formData.subMenu = nodeData.subMenu;
|
||||
formData.version = nodeData.version;
|
||||
formData.name = nodeData.name;
|
||||
formData.vueRouter = nodeData.vueRouter;
|
||||
formData.displayOrder = nodeData.displayOrder;
|
||||
formData.useRangeEnum = nodeData.useRangeEnum;
|
||||
formData.environment = nodeData.environment || '0';
|
||||
|
||||
formData.organizationIds = nodeData.organizationIds.map((id) => id.toString());
|
||||
// 打开弹窗
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 处理节点点击,根据后台返回的路径加载组件
|
||||
const handleNodeClick = async (data, node) => {
|
||||
console.log('点击节点:', data, node);
|
||||
// 检查是否为子节点(没有children或children为空)
|
||||
// const isLeafNode = !data.children || data.children.length === 0;
|
||||
if (node.isLeaf) {
|
||||
// 存储当前节点数据
|
||||
currentNodeData.value = data.document;
|
||||
// 检查是否为子节点(没有children或children为空)
|
||||
currentComponent.value = data.document.vueRouter || '';
|
||||
} else {
|
||||
currentNodeData.value = null;
|
||||
currentComponent.value = null;
|
||||
}
|
||||
};
|
||||
const toggleExpand = () => {
|
||||
isExpanded.value = !isExpanded.value;
|
||||
console.log('展开状态:', templateTree.value.store);
|
||||
expandTree();
|
||||
};
|
||||
const expandTree = () => {
|
||||
templateTree.value.store._getAllNodes().forEach((node) => {
|
||||
node.expanded = isExpanded.value;
|
||||
});
|
||||
};
|
||||
const refresh = () => {
|
||||
initTemplateTree({ id: orgId.value });
|
||||
};
|
||||
|
||||
// 新建模板
|
||||
const newTemplate = () => {
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
// 删除模板
|
||||
const deleteTemplate = async () => {
|
||||
// 1. 检查是否选中节点
|
||||
if (!currentNodeData.value) {
|
||||
ElMessage.warning('请先选择一个模板节点');
|
||||
return;
|
||||
}
|
||||
|
||||
let loading = null;
|
||||
const templateName = currentNodeData.value.name;
|
||||
const templateId = currentNodeData.value.id;
|
||||
try {
|
||||
// 2. 显示确认对话框,增加操作描述
|
||||
const confirmResult = await ElMessageBox.confirm(
|
||||
`确定要删除模板「${templateName}」吗?<br>此操作不可撤销,删除后将无法恢复。`,
|
||||
'删除确认',
|
||||
{
|
||||
confirmButtonText: '确认删除',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
dangerouslyUseHTMLString: true,
|
||||
center: true,
|
||||
closeOnClickModal: false,
|
||||
}
|
||||
);
|
||||
|
||||
// 3. 用户确认删除后执行操作
|
||||
if (confirmResult === 'confirm') {
|
||||
// 显示加载状态
|
||||
loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: '正在删除模板...',
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
});
|
||||
|
||||
// 调用删除API
|
||||
await deleteDefinition(templateId);
|
||||
// 删除成功处理
|
||||
ElMessage.success(`模板「${templateName}」删除成功`);
|
||||
// 清空当前选中状态
|
||||
currentNodeData.value = null;
|
||||
initFormData();
|
||||
currentComponent.value = null;
|
||||
// 刷新列表
|
||||
refresh();
|
||||
}
|
||||
} catch (error) {
|
||||
// 错误处理:区分用户取消和API错误
|
||||
if (error === 'cancel' || error === undefined) {
|
||||
// 用户取消删除,不显示错误提示
|
||||
console.log('用户取消删除操作');
|
||||
} else {
|
||||
// API错误或其他错误,使用统一的错误处理函数
|
||||
handleApiError('删除模板', '删除模板失败')(error);
|
||||
}
|
||||
} finally {
|
||||
// 确保加载状态总是被关闭
|
||||
if (loading) {
|
||||
loading.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 打印模板
|
||||
const printTemplate = () => {
|
||||
window.print();
|
||||
};
|
||||
|
||||
// 标签页点击事件
|
||||
const handleClick = (tab) => {
|
||||
console.log('标签页点击:', tab);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.case-templates-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 91vh;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
background-color: #f5f5f5;
|
||||
border-bottom: 1px solid #ddd;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.content-area {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
width: 280px;
|
||||
border-right: 1px solid #ddd;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.template-tree {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.middle-panel {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user