109 住院医生工作站-》住院病历的【存为模板】界面升级

This commit is contained in:
Ranyunqiao
2026-03-23 17:24:01 +08:00
parent 251cf263ff
commit 88088c01ac
7 changed files with 869 additions and 111 deletions

View File

@@ -59,7 +59,7 @@ public class DocTemplateAppServiceImpl implements IDocTemplateAppService {
docTemplateDto.setUserId(SecurityUtils.getLoginUser().getUserId());
}
docTemplate.setOrganizationId(docTemplateDto.getOrganizationId());
docTemplate.setId(docTemplateDto.getUserId());
docTemplate.setUserId(docTemplateDto.getUserId());
docTemplate.setUseRange(docTemplateDto.getUseRange());
docTemplate.setRemark(docTemplateDto.getRemark());
docTemplateService.save(docTemplate);
@@ -140,7 +140,7 @@ public class DocTemplateAppServiceImpl implements IDocTemplateAppService {
docTemplate.setOrganizationId(docTemplateDto.getOrganizationId());
docTemplate.setUserId(docTemplateDto.getUserId());
docTemplate.setRemark(docTemplateDto.getRemark());
docTemplateService.save(docTemplate);
docTemplateService.updateById(docTemplate);
return R.ok("更新成功");
}

View File

@@ -9,7 +9,6 @@
</div> -->
<el-scrollbar class="emr-template-scrollbar-container" style="width: 100%">
<div v-for="item in templateData" :key="item.id" class="scrollbar-item">
<el-tooltip effect="dark" :content="`${item.name}`" placement="bottom">
<el-text class="2" truncated @click="handleNodeClick(item)">
<div class="template-item">
{{ item.name }}
@@ -19,7 +18,6 @@
</el-space>
</div>
</el-text>
</el-tooltip>
</div>
</el-scrollbar>
</div>

View File

@@ -74,10 +74,29 @@ export function updateTemplate(data) {
}
// 删除模板
export function deleteTemplate(ids) {
export function deleteTemplate(id) {
return request({
url: '/document/template/delete',
method: 'delete',
data: ids,
params: { id },
});
}
// 保存或更新模板
export function saveOrUpdate(data) {
if (data.id && data.id !== null && data.id !== 0 && String(data.id).trim() !== '') {
return request({
url: '/document/template/update',
method: 'put',
data,
});
} else {
const { id, ...restData } = data;
return request({
url: '/document/template/add',
method: 'post',
data: restData,
});
}
}

View File

@@ -0,0 +1,590 @@
<template>
<div class="template-editor">
<el-form :model="formData" label-width="120px" class="form-container">
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="name">
<template #label> <span style="color: red">*</span>模板名称: </template>
<el-input v-model="formData.name" placeholder="请输入模板名称"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="使用范围:">
<el-select v-model="formData.useRange" placeholder="请选择使用范围">
<el-option
v-for="item in useRangeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-button type="primary" @click="handleAdd" class="add-btn">新增</el-button>
<div class="table-container">
<el-table :data="templateItems" border style="width: 100%">
<el-table-column prop="fieldKey" label="病历元素">
<template #default="scope">
<el-select
filterable
v-model="scope.row.fieldKey"
placeholder="请选择"
style="width: 100%"
@change="handleElementChange(scope.$index, scope.row)"
>
<el-option
v-for="item in elementOptions"
:key="item.value"
:label="item.name"
:value="item.value"
/>
</el-select>
</template>
</el-table-column>
<el-table-column prop="recordName" label="模板内容">
<template #default="scope">
<el-input
v-model="scope.row.recordName"
type="textarea"
:autosize="{ minRows: 1, maxRows: 10 }"
></el-input>
</template>
</el-table-column>
<el-table-column prop="code" label="编码">
<template #default="scope">
<el-input disabled v-model="scope.row.code" placeholder="请输入编码"></el-input>
</template>
</el-table-column>
<el-table-column prop="operation" label="操作" width="80">
<template #default="scope">
<el-button
type="danger"
icon="Delete"
circle
@click="handleDelete(scope.$index)"
></el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="btn-group">
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleConfirm">确认</el-button>
</div>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { ElMessage } from 'element-plus';
import { saveOrUpdate } from '../api';
import useUserStore from '@/store/modules/user';
const userStore = useUserStore();
const emit = defineEmits(['close', 'submitOk', 'update:dialogVisible']);
const dialogVisible = defineModel('dialogVisible', {
type: Boolean,
default: false,
});
const elementOptions = ref([]);
const formData = reactive({
name: '',
useRange: '',
useRangeName: '',
organizationId: undefined,
definitionId: undefined,
id: null,
});
const templateItems = ref([]);
const handleAdd = () => {
for (let i = 0; i < templateItems.value.length; i++) {
const item = templateItems.value[i];
if (!item.fieldKey || item.fieldKey.trim() === '') {
ElMessage.warning('请先选择病历元素');
return;
}
if (!item.recordName || item.recordName.trim() === '') {
ElMessage.warning('请先填写模版内容');
return;
}
if (!item.code || item.code.trim() === '') {
ElMessage.warning('请先填写编码');
return;
}
}
templateItems.value.push({
recordName: '',
fieldKey: '',
code: '',
});
};
const handleElementChange = (index, row) => {
const selectedItem = templateItems.value[index];
const elementOption = elementOptions.value.find((item) => item.fieldKey === selectedItem.fieldKey);
if (elementOption) {
selectedItem.fieldKey = elementOption.fieldKey || '';
selectedItem.code = elementOption.name + '-' + elementOption.fieldKey || '';
}
};
const handleDelete = (index) => {
templateItems.value.splice(index, 1);
ElMessage.success('删除成功');
};
const clearData = () => {
formData.name = '';
templateItems.value = [];
};
const handleCancel = () => {
clearData();
dialogVisible.value = false;
emit('close');
};
const handleConfirm = async () => {
if (!formData.definitionId || formData.definitionId.trim() === '') {
ElMessage.warning('请选择病历模版');
return;
}
if (!formData.name || formData.name.trim() === '') {
ElMessage.warning('请填写模版名称');
return;
}
if (templateItems.value.length === 0) {
ElMessage.warning('请至少添加一条模板内容');
return;
}
for (let i = 0; i < templateItems.value.length; i++) {
const item = templateItems.value[i];
if (!item.fieldKey || item.fieldKey.trim() === '') {
ElMessage.warning('请先选择病历元素');
return;
}
if (!item.recordName || item.recordName.trim() === '') {
ElMessage.warning('请先填写模版内容');
return;
}
const validationResult = validateField(item.fieldKey, item.recordName);
if (!validationResult.valid) {
const fieldLabel = emrFieldLabels[item.fieldKey] || item.fieldKey;
ElMessage.warning(`${fieldLabel}${validationResult.message}`);
return;
}
}
const params = {
name: formData.name,
definitionId: formData.definitionId,
contextJson: JSON.stringify(templateItems.value),
useRange: parseInt(formData.useRange) || 3,
organizationId: formData.organizationId,
userId: formData.userId,
remark: formData.remark,
};
const res = await saveOrUpdate(params);
if (res.code == 200) {
ElMessage.success('保存成功');
clearData();
dialogVisible.value = false;
emit('submitOk');
emit('close');
} else {
ElMessage.error(res.msg || '保存失败');
}
};
const useRangeOptions = ref([
{
label: '个人',
value: '3',
},
{
label: '科室',
value: '2',
},
{
label: '全院',
value: '1',
},
]);
const useRangeFind = (name) => {
const mapArr = [
{ label: '个人', value: '3' },
{ label: '科室', value: '2' },
{ label: '全院', value: '1' },
];
const findObj = mapArr.find((item) => item.label === name);
return findObj;
};
const initData = async (data) => {
try {
elementOptions.value = Object.keys(emrFieldLabels).map((key) => ({
label: emrFieldLabels[key],
value: key,
fieldKey: key,
name: emrFieldLabels[key],
code: key,
}));
formData.definitionId = data.definitionId;
if (formData.useRange === '1') {
formData.organizationId = userStore.orgId;
} else {
formData.organizationId = undefined;
}
if (data.isEdit) {
formData.name = data.templateType;
formData.id = data.id;
if (data.useRange == '1') {
formData.useRange = '1';
formData.useRangeName = '全院';
} else if (data.useRange == '2') {
formData.useRange = '2';
formData.useRangeName = '科室';
} else {
formData.useRange = '3';
formData.useRangeName = '个人';
}
const content = typeof data.contextJson === 'string' ? JSON.parse(data.contextJson) : data.contextJson;
templateItems.value = content;
} else {
formData.id = null;
formData.useRange = useRangeFind(data.templateType)?.value || '3';
formData.useRangeName = useRangeFind(data.templateType)?.label || '个人';
templateItems.value = [];
if (data.contextJson) {
let content = typeof data.contextJson === 'string' ? JSON.parse(data.contextJson) : data.contextJson;
if (Array.isArray(content)) {
templateItems.value = content.map((item) => ({
fieldKey: item.fieldKey || '',
recordName: item.recordName || '',
code: item.code || '',
}));
} else {
templateItems.value = Object.keys(content)
.filter((key) => content[key] !== null && content[key] !== undefined && content[key] !== '')
.map((key) => ({
fieldKey: key,
recordName: typeof content[key] === 'object' ? JSON.stringify(content[key]) : String(content[key]),
code: (emrFieldLabels[key] || key) + '-' + key,
}));
}
}
}
} catch (error) {
console.log('初始化模板数据失败', error);
}
};
const emrFieldLabels = {
chiefComplaint: '主诉',
complaint: '主诉',
currentIllnessHistory: '现病史',
pastMedicalHistory: '既往史',
pastHistory: '既往史',
menstrualHistory: '个人史',
allergyHistory: '过敏史',
physicalExamination: '体格检查',
treatment: '处理',
auxiliaryExamination: '辅助检查',
diagnosis: '诊断',
diagnosisName: '诊断名称',
diagnosisCode: '诊断编码',
height: '身高',
weight: '体重',
temperature: '体温',
pulse: '脉搏',
respiration: '呼吸',
bloodPressure: '血压',
smokingHistory: '吸烟史',
drinkingHistory: '饮酒史',
familyHistory: '家族史',
surgicalHistory: '手术史',
traumaHistory: '外伤史',
onsetDate: '发病日期',
signDate: '签字日期',
recordTime: '记录时间',
admissionTime: '入院时间',
reliability: '可靠性',
patientName: '患者姓名',
hospitalNo: '住院号',
gender: '性别',
age: '年龄',
medicationList: '用药列表',
nursingLevel: '护理等级',
medicalOrder: '医嘱',
};
const fieldValidationRules = {
patientName: {
label: '患者姓名',
type: 'chinese',
message: '患者姓名必须是中文',
},
hospitalNo: {
label: '住院号',
type: 'alphanumeric',
message: '住院号必须是字母或数字',
},
admissionTime: {
label: '入院时间',
type: 'datetime',
message: '请输入有效的日期时间格式',
},
recordTime: {
label: '记录时间',
type: 'datetime',
message: '请输入有效的日期时间格式',
},
signDate: {
label: '签字日期',
type: 'datetime',
message: '请输入有效的日期时间格式',
},
onsetDate: {
label: '发病日期',
type: 'datetime',
message: '请输入有效的日期时间格式',
},
inHospitalTime: {
label: '入院时间',
type: 'datetime',
message: '请输入有效的日期时间格式',
},
outHospitalTime: {
label: '出院时间',
type: 'datetime',
message: '请输入有效的日期时间格式',
},
gender: {
label: '性别',
type: 'select',
options: ['男', '女', '未知'],
message: '请选择性别',
},
genderEnum: {
label: '性别',
type: 'select',
options: ['男', '女', '未知'],
message: '请选择性别',
},
genderEnum_enumText: {
label: '性别',
type: 'select',
options: ['男', '女', '未知'],
message: '请选择性别',
},
age: {
label: '年龄',
type: 'number',
message: '年龄必须是正整数',
},
height: {
label: '身高',
type: 'decimal',
message: '身高必须是数字',
},
weight: {
label: '体重',
type: 'decimal',
message: '体重必须是数字',
},
temperature: {
label: '体温',
type: 'decimal',
message: '体温必须是数字',
},
pulse: {
label: '脉搏',
type: 'integer',
message: '脉搏必须是整数',
},
respiration: {
label: '呼吸',
type: 'integer',
message: '呼吸必须是整数',
},
bloodPressure: {
label: '血压',
type: 'bloodPressure',
message: '血压格式应为收缩压/舒张压120/80',
},
inHospitalDays: {
label: '住院天数',
type: 'integer',
message: '住院天数必须是正整数',
},
};
const getValidationRule = (fieldKey) => {
return fieldValidationRules[fieldKey];
};
const validateField = (fieldKey, value) => {
if (!value || value.trim() === '') return { valid: true };
const rule = fieldValidationRules[fieldKey];
if (!rule) return { valid: true };
const val = String(value).trim();
switch (rule.type) {
case 'chinese':
if (!/^[\u4e00-\u9fa5]+$/.test(val)) {
return { valid: false, message: rule.message };
}
break;
case 'alphanumeric':
if (!/^[A-Za-z0-9]+$/.test(val)) {
return { valid: false, message: rule.message };
}
break;
case 'datetime':
if (!/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}$/.test(val)) {
return { valid: false, message: rule.message };
}
break;
case 'number':
if (!/^[0-9]+$/.test(val)) {
return { valid: false, message: rule.message };
}
break;
case 'integer':
if (!/^[0-9]+$/.test(val)) {
return { valid: false, message: rule.message };
}
break;
case 'decimal':
if (!/^[0-9]+(\.[0-9]+)?$/.test(val)) {
return { valid: false, message: rule.message };
}
break;
case 'bloodPressure':
if (!/^[0-9]+\/[0-9]+$/.test(val)) {
return { valid: false, message: rule.message };
}
break;
case 'select':
break;
}
return { valid: true };
};
const getFieldLabel = (key) => {
const fieldLabels = {
chiefComplaint: '主诉',
currentIllnessHistory: '现病史',
pastMedicalHistory: '既往史',
menstrualHistory: '个人史',
allergyHistory: '过敏史',
physicalExamination: '体格检查',
treatment: '处理',
auxiliaryExamination: '辅助检查',
diagnosis: '诊断',
height: '身高',
weight: '体重',
temperature: '体温',
pulse: '脉搏',
respiration: '呼吸',
bloodPressure: '血压',
smokingHistory: '吸烟史',
drinkingHistory: '饮酒史',
familyHistory: '家族史',
surgicalHistory: '手术史',
traumaHistory: '外伤史',
onsetDate: '发病日期',
diagnosisName: '诊断名称',
diagnosisCode: '诊断编码',
encounterId: '就诊ID',
statusEnum: '状态',
busNo: '住院号',
inHospitalTime: '入院时间',
outHospitalTime: '出院时间',
patientId: '患者ID',
patientName: '患者姓名',
genderEnum: '性别',
genderEnum_enumText: '性别',
birthDate: '出生日期',
age: '年龄',
wardName: '病区',
houseName: '科室',
bedName: '床位',
inOrgTime: '入院时间',
inHospitalDays: '住院天数',
inHospitalOrgId: '入院科室ID',
inHospitalOrgName: '入院科室',
contractNo: '合同编号',
contractName: '合同名称',
accountId: '账户ID',
advanceAmount: '预交金额',
totalAmount: '总金额',
balanceAmount: '余额',
medicalOrder: '医嘱',
nursingLevel: '护理等级',
diagnosisList: '诊断列表',
medicationList: '用药列表',
examinationResult: '检查结果',
labResult: '检验结果',
};
return fieldLabels[key] || key;
};
defineExpose({
initData,
});
</script>
<style scoped>
.template-editor {
padding: 20px;
background-color: #f5f7fa;
max-height: 500px;
overflow-y: auto;
}
.form-container {
margin-bottom: 15px;
}
.add-btn {
margin-bottom: 10px;
}
.table-container {
margin-bottom: 15px;
max-height: 300px;
overflow-y: auto;
}
.btn-group {
display: flex;
justify-content: flex-end;
gap: 10px;
}
.el-table {
background-color: #fff;
}
.el-table th {
background-color: #f5f7fa;
font-weight: bold;
}
</style>

View File

@@ -9,7 +9,6 @@
</div> -->
<el-scrollbar class="emr-template-scrollbar-container" style="width: 100%">
<div v-for="item in templateData" :key="item.id" class="scrollbar-item">
<el-tooltip effect="dark" :content="`${item.name}`" placement="bottom">
<el-text class="2" truncated @click="handleNodeClick(item)">
<div class="template-item">
{{ item.name }}
@@ -19,7 +18,6 @@
</el-space>
</div>
</el-text>
</el-tooltip>
</div>
</el-scrollbar>
</div>
@@ -108,12 +106,18 @@ const handleEdit = (data) => {
// 删除模板
const handleDelete = async (item) => {
try {
const templateId = item.id || item.templateId;
if (!templateId) {
console.error('模板数据:', item);
ElMessage.error('模板ID不存在');
return;
}
ElMessageBox.confirm('确定要删除该模板吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
await deleteTemplate(item.id);
await deleteTemplate(templateId);
ElMessage.success('删除成功');
// 清除缓存中的数据,强制重新加载
templateCache.delete(unref(definitionId));
@@ -127,7 +131,10 @@ const handleDelete = async (item) => {
};
const currentSelectTemplate = ref({});
defineExpose({ queryList });
const clearCache = () => {
templateCache.delete(unref(definitionId));
};
defineExpose({ queryList, clearCache });
</script>
<style lang="scss" scoped>

View File

@@ -1,5 +1,4 @@
<template>
<!-- 病历文件基本信息弹窗 -->
<el-dialog
:title="formData.id ? '编辑模板' : '新增模板'"
v-model="dialogVisible"
@@ -7,40 +6,83 @@
destroy-on-close
@open="handleOpen"
>
<!-- 使用el-form包裹表单 -->
<el-form :model="formData" ref="formRef" :rules="rules" label-width="120px">
<el-row :gutter="24" class="mb8">
<el-col :span="24">
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="模板名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入模板名称"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-col :span="12">
<el-form-item label="使用范围" prop="useRange">
<el-radio-group v-model="formData.useRange">
<el-radio :value="0" size="large">全院</el-radio>
<el-radio :value="1" size="large">指定机构</el-radio>
<el-radio :value="2" size="large">指定用户</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入版本"></el-input>
<el-select v-model="formData.useRange" placeholder="请选择使用范围">
<el-option label="个人" :value="3" />
<el-option label="科室" :value="2" />
<el-option label="全院" :value="1" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-button type="primary" @click="handleAdd" class="add-btn">新增</el-button>
<div class="table-container">
<el-table :data="templateItems" border style="width: 100%">
<el-table-column prop="fieldKey" label="病历元素">
<template #default="scope">
<el-select
filterable
v-model="scope.row.fieldKey"
placeholder="请选择"
style="width: 100%"
@change="handleElementChange(scope.$index, scope.row)"
>
<el-option
v-for="item in elementOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</template>
</el-table-column>
<el-table-column prop="recordName" label="模板内容">
<template #default="scope">
<el-input
v-model="scope.row.recordName"
type="textarea"
:autosize="{ minRows: 1, maxRows: 10 }"
></el-input>
</template>
</el-table-column>
<el-table-column prop="code" label="编码">
<template #default="scope">
<el-input disabled v-model="scope.row.code" placeholder="请输入编码"></el-input>
</template>
</el-table-column>
<el-table-column prop="operation" label="操作" width="80">
<template #default="scope">
<el-button
type="danger"
icon="Delete"
circle
@click="handleDelete(scope.$index)"
></el-button>
</template>
</el-table-column>
</el-table>
</div>
<template #footer>
<div class="dialog-footer"></div>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitForm">确定</el-button>
</template>
</el-dialog>
</template>
<script setup>
import {onMounted, ref} from 'vue';
import { ref, reactive } from 'vue';
import { addTemplate, updateTemplate } from '../api';
import { ElMessage } from 'element-plus';
@@ -58,7 +100,6 @@ const dialogVisible = defineModel('dialogVisible', {
default: false,
});
// 表单数据
const formData = ref({
id: 0,
name: '',
@@ -68,65 +109,156 @@ const formData = ref({
useRange: 2,
organizationId: 0,
userId: 0,
remark: '',
});
// 表单验证规则(响应式,支持动态验证)
const templateItems = ref([]);
const elementOptions = ref([]);
const emrFieldLabels = {
chiefComplaint: '主诉',
complaint: '主诉',
currentIllnessHistory: '现病史',
pastMedicalHistory: '既往史',
pastHistory: '既往史',
menstrualHistory: '个人史',
allergyHistory: '过敏史',
physicalExamination: '体格检查',
treatment: '处理',
auxiliaryExamination: '辅助检查',
diagnosis: '诊断',
diagnosisName: '诊断名称',
diagnosisCode: '诊断编码',
height: '身高',
weight: '体重',
temperature: '体温',
pulse: '脉搏',
respiration: '呼吸',
bloodPressure: '血压',
smokingHistory: '吸烟史',
drinkingHistory: '饮酒史',
familyHistory: '家族史',
surgicalHistory: '手术史',
traumaHistory: '外伤史',
onsetDate: '发病日期',
signDate: '签字日期',
recordTime: '记录时间',
admissionTime: '入院时间',
reliability: '可靠性',
patientName: '患者姓名',
hospitalNo: '住院号',
gender: '性别',
age: '年龄',
medicationList: '用药列表',
nursingLevel: '护理等级',
medicalOrder: '医嘱',
};
const rules = reactive({
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
});
const handleOpen = () => {
if (props.formData) {
formData.value = props.formData;
formData.value = JSON.parse(JSON.stringify(props.formData));
if (props.formData.contextJson) {
try {
templateItems.value = typeof props.formData.contextJson === 'string'
? JSON.parse(props.formData.contextJson)
: JSON.parse(JSON.stringify(props.formData.contextJson));
} catch (e) {
templateItems.value = [];
}
} else {
templateItems.value = [];
}
} else {
resetForm();
}
elementOptions.value = Object.keys(emrFieldLabels).map((key) => ({
label: emrFieldLabels[key],
value: key,
}));
};
const handleAdd = () => {
templateItems.value.push({
fieldKey: '',
recordName: '',
code: '',
});
};
const handleElementChange = (index, row) => {
row.code = (emrFieldLabels[row.fieldKey] || row.fieldKey) + '-' + row.fieldKey;
};
const handleDelete = (index) => {
templateItems.value.splice(index, 1);
};
// 提交表单
const submitForm = () => {
formRef.value.validate((valid) => {
if (valid) {
// 表单验证通过,执行保存操作
saveForm();
} else {
// 表单验证失败
ElMessage.error('请填写必填项');
return false;
}
});
};
// 保存表单
const saveForm = async () => {
try {
// 如果有当前节点数据,表示是编辑操作
if (formData.value.id && formData.value.id !== '') {
const res = await updateTemplate(formData.value);
const params = {
...formData.value,
contextJson: JSON.stringify(templateItems.value),
};
if (formData.value.id && formData.value.id !== 0 && String(formData.value.id).trim() !== '') {
const res = await updateTemplate(params);
if (res.code == 200) {
ElMessage.success('更新成功');
emits('submitOk');
dialogVisible.value = false;
} else {
ElMessage.error('更新失败', error);
ElMessage.error(res.msg || '更新失败');
}
} else {
// 新建操作
const res = await addTemplate(formData.value);
const res = await addTemplate(params);
if (res.code == 200) {
ElMessage.success('保存成功');
emits('submitOk');
dialogVisible.value = false;
} else {
ElMessage.error('保存失败', error);
ElMessage.error(res.msg || '保存失败');
}
}
} catch (error) {
console.log(error);
// ElMessage.error('保存失败',error);
}
};
// 重置表单
const resetForm = () => {
formRef.value?.resetFields();
};
onMounted(() => {});
const resetForm = () => {
formData.value = {
id: 0,
name: '',
displayOrder: 0,
contextJson: '',
definitionId: 0,
useRange: 2,
organizationId: 0,
userId: 0,
};
templateItems.value = [];
};
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.add-btn {
margin-bottom: 10px;
}
.table-container {
margin-bottom: 15px;
max-height: 300px;
overflow-y: auto;
}
</style>

View File

@@ -101,6 +101,19 @@
@submitOk="templateEditSubmitOk"
/>
<el-dialog
v-model="createTemplateVisible"
title="创建模板"
width="50%"
destroy-on-close
>
<CreateTemplate
ref="createTemplateRef"
@close="createTemplateVisible = false"
@submitOk="createTemplateSubmitOk"
/>
</el-dialog>
<el-drawer v-model="openDrawer" size="100%">
<template #default>
<div>
@@ -124,6 +137,7 @@ import useUserStore from '@/store/modules/user';
import History from './components/history';
import Template from './components/template';
import TemplateEdit from './components/templateEdit.vue';
import CreateTemplate from './components/createTemplate.vue';
const userStore = useUserStore();
// 移除未使用的变量
@@ -249,12 +263,20 @@ const newEmr = () => {
};
const saveAsModel = async () => {
try {
currentOperate.value = 'addTemplate';
await emrComponentRef.value?.submit();
} catch (error) {
ElMessage.error('存为模版失败');
if (!currentSelectTemplate.value || !currentSelectTemplate.value.id) {
ElMessage.warning('请先选择病历模板');
return;
}
const emrFormData = emrComponentRef.value?.formData || {};
createTemplateVisible.value = true;
nextTick(() => {
createTemplateRef.value?.initData({
definitionId: currentSelectTemplate.value.id,
templateType: '全院',
isEdit: false,
contextJson: emrFormData,
});
});
};
const editForm = ref({
id: '',
@@ -728,9 +750,24 @@ const templateRef = ref(null);
const handleTemplateClick = async (data) => {
try {
newEmr();
editForm.value = data;
editForm.value = {
...data,
id: '',
recordTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
};
nextTick(() => {
emrComponentRef.value?.setFormData(JSON.parse(editForm.value.contextJson));
if (data.contextJson) {
let parsedData = typeof data.contextJson === 'string' ? JSON.parse(data.contextJson) : data.contextJson;
if (Array.isArray(parsedData)) {
parsedData = parsedData.reduce((acc, item) => {
if (item.fieldKey) {
acc[item.fieldKey] = item.recordName;
}
return acc;
}, {});
}
emrComponentRef.value?.setFormData(parsedData);
}
});
} catch (error) {
ElMessage.error('设置模板数据失败');
@@ -738,56 +775,31 @@ const handleTemplateClick = async (data) => {
}
};
const templateEdit = (data) => {
editTemplateForm.value = data;
editTemplateForm.value = JSON.parse(JSON.stringify(data));
templateEditVisible.value = true;
};
// ====dialog
const templateEditVisible = ref(false);
const createTemplateVisible = ref(false);
const createTemplateRef = ref(null);
const templateEditSubmitOk = async () => {
try {
// 根据是否存在ID来决定是新增还是编辑
if (!editTemplateForm.value.id) {
// 新增模板
const addResult = await addTemplate(editTemplateForm.value);
if (addResult && addResult.code === 200) {
ElMessage.success('模板新增成功');
// 刷新模板列表
if (templateRef.value && typeof templateRef.value.queryList === 'function') {
// 在模板操作后,需要清除缓存并重新加载
if (templateRef.value) {
if (templateRef.value.clearCache) {
templateRef.value.clearCache();
}
templateRef.value.queryList();
}
// 关闭模板编辑弹窗
templateEditVisible.value = false;
// 清空模板编辑表单
Object.assign(editTemplateForm.value, {
id: '',
name: '',
displayOrder: 0,
contextJson: '',
definitionId: '',
useRange: 2,
organizationId: userStore.orgId,
userId: '',
useRanges: [1],
remark: '',
});
} else {
ElMessage.error('模板新增失败');
console.error('模板新增失败:', addResult);
};
// 新增模板成功后的回调
const createTemplateSubmitOk = () => {
if (templateRef.value) {
if (templateRef.value.clearCache) {
templateRef.value.clearCache();
}
} else {
// 编辑模板 - 暂不实现编辑功能,只支持新增
ElMessage.warning('暂不支持编辑模板');
}
} catch (error) {
console.error('处理模板编辑提交失败:', error);
ElMessage.error('处理模板编辑提交失败: ' + (error.message || '未知错误'));
} finally {
// 无论成功失败都刷新列表
historyRef.value?.queryList();
// 模板查询已经在模板组件内部通过防抖和缓存优化,这里不再重复调用
// templateRef.value?.queryList();
templateRef.value.queryList();
}
ElMessage.success('保存模板成功');
};
// onBeforeMount(() => {});
// 监听患者信息变化,实现联动显示