确保username参数存在,避免因为空值造成接口调用失败 feat(editor): 重构富文本编辑器组件并优化图片上传逻辑 - 使用 Composition API 重构代码结构,提升可维护性 - 改进图片上传功能,增强对 quill 实例的安全访问 - 更新样式排版,提高组件可读性和一致性 refactor(file-upload): 移除旧代理引用,使用 modern Vue API 替换 `proxy` 调用为 `modal` 插件直接调用,提升代码清晰度与健壮性 refactor(image-upload): 替换旧实例调用方式,强化错误提示机制 统一使用 `modal` 进行消息提示和加载状态控制,改善用户体验 refactor(tree-select): 引入 Composition API 优化节点操作逻辑 移除 `getCurrentInstance` 的不必要使用,改为明确的模板引用管理 chore(main): 添加 util._extend 补丁以消除 Node.js 环境警告 解决开发环境下由于 Node.js 内建模块缺失造成的运行时警告问题 feat(template): 完善跌倒/坠床评估护理记录单模板 - 增加详细注释说明各部分作用,便于后续维护 - 明确组件名称为中文,利于业务识别 - 丰富表单交互细节及数据处理逻辑,支持动态打分、措施选择等功能 refactor(template-index): 加强模板组件自动注册逻辑 增加组件 name 属性校验,防止无效或匿名组件被注册到全局
460 lines
13 KiB
Vue
460 lines
13 KiB
Vue
<template>
|
||
<!-- 门诊病历表单主容器 -->
|
||
<div class="medical-form">
|
||
<!-- 患者基本信息展示区域 -->
|
||
<div class="patient-name">
|
||
患者姓名:{{ patient?.patientName || '未知' }} 病历号:{{
|
||
patient?.busNo || '未知'
|
||
}}
|
||
</div>
|
||
<!-- 医院名称和标题 -->
|
||
<h2 style="text-align: center">{{ userStore.hospitalName }}</h2>
|
||
<h2 style="text-align: center">门诊病历</h2>
|
||
|
||
<!-- 滚动内容区域 -->
|
||
<div class="form-scroll-container">
|
||
<!-- Element Plus表单组件 -->
|
||
<el-form
|
||
ref="formRef"
|
||
:model="formData"
|
||
:rules="rules"
|
||
label-width="100px"
|
||
label-align="left"
|
||
class="medical-full-form"
|
||
>
|
||
<!-- 基础信息区域标题 -->
|
||
<h4 class="section-title">基础信息</h4>
|
||
<!-- 1. 基础信息:单行自适应排列 -->
|
||
<el-form-item class="form-section">
|
||
<div class="single-row-layout">
|
||
<!-- 身高输入项 -->
|
||
<el-form-item label="身高" prop="height" class="row-item">
|
||
<div class="input-with-unit">
|
||
<el-input v-model="formData.height" type="text" placeholder="请输入" />
|
||
<span class="unit">cm</span>
|
||
</div>
|
||
</el-form-item>
|
||
<!-- 体重输入项 -->
|
||
<el-form-item label="体重" prop="weight" class="row-item">
|
||
<div class="input-with-unit">
|
||
<el-input v-model="formData.weight" type="text" placeholder="请输入" />
|
||
<span class="unit">kg</span>
|
||
</div>
|
||
</el-form-item>
|
||
<!-- 体温输入项 -->
|
||
<el-form-item label="体温" prop="temperature" class="row-item">
|
||
<div class="input-with-unit">
|
||
<el-input v-model="formData.temperature" type="text" placeholder="请输入" />
|
||
<span class="unit">℃</span>
|
||
</div>
|
||
</el-form-item>
|
||
<!-- 脉搏输入项 -->
|
||
<el-form-item label="脉搏" prop="pulse" class="row-item">
|
||
<div class="input-with-unit">
|
||
<el-input v-model="formData.pulse" type="text" placeholder="请输入" />
|
||
<span class="unit">次/分</span>
|
||
</div>
|
||
</el-form-item>
|
||
<!-- 发病日期选择项 -->
|
||
<el-form-item label="发病日期" prop="onsetDate" class="row-item">
|
||
<el-date-picker
|
||
v-model="formData.onsetDate"
|
||
type="date"
|
||
placeholder="选择发病日期"
|
||
value-format="YYYY-MM-DD"
|
||
style="width: 100%"
|
||
/>
|
||
<!-- <el-input v-model="formData.onsetDate" type="date" /> -->
|
||
</el-form-item>
|
||
</div>
|
||
</el-form-item>
|
||
|
||
<!-- 病史信息区域标题 -->
|
||
<h4 class="section-title">病史信息</h4>
|
||
<!-- 2. 病史信息:单行自适应排列(新增调整) -->
|
||
<el-form-item class="form-section">
|
||
<div class="single-row-layout">
|
||
<!-- 现病史输入项 -->
|
||
<el-form-item label="现病史" prop="presentIllness" class="row-item history-item">
|
||
<el-input
|
||
v-model="formData.presentIllness"
|
||
type="textarea"
|
||
placeholder="无"
|
||
autosize
|
||
/>
|
||
</el-form-item>
|
||
<!-- 既往史输入项 -->
|
||
<el-form-item label="既往史" prop="pastIllness" class="row-item history-item">
|
||
<el-input v-model="formData.pastIllness" type="textarea" placeholder="无" autosize />
|
||
</el-form-item>
|
||
<!-- 个人史输入项 -->
|
||
<el-form-item label="个人史" prop="personalHistory" class="row-item history-item">
|
||
<el-input
|
||
v-model="formData.personalHistory"
|
||
type="textarea"
|
||
placeholder="无"
|
||
autosize
|
||
/>
|
||
</el-form-item>
|
||
<!-- 过敏史输入项 -->
|
||
<el-form-item label="过敏史" prop="allergyHistory" class="row-item history-item">
|
||
<el-input
|
||
v-model="formData.allergyHistory"
|
||
type="textarea"
|
||
placeholder="无"
|
||
autosize
|
||
/>
|
||
</el-form-item>
|
||
<!-- 家族史输入项 -->
|
||
<el-form-item label="家族史" prop="familyHistory" class="row-item history-item">
|
||
<el-input
|
||
v-model="formData.familyHistory"
|
||
type="textarea"
|
||
placeholder="无"
|
||
autosize
|
||
/>
|
||
</el-form-item>
|
||
</div>
|
||
</el-form-item>
|
||
|
||
<!-- 主诉、查体(治疗)、处置、辅助检查区域标题 -->
|
||
<h4 class="section-title">主诉、查体(治疗)、处置、辅助检查</h4>
|
||
<!-- 3. 主诉(必填) -->
|
||
<el-form-item label="主诉" prop="complaint" class="required form-item-single">
|
||
<el-input
|
||
v-model="formData.complaint"
|
||
type="textarea"
|
||
placeholder="请输入主诉"
|
||
class="tall-textarea"
|
||
autosize
|
||
/>
|
||
</el-form-item>
|
||
<!-- 4. 查体、处理、辅助检查 -->
|
||
<!-- 查体(治疗)输入项 -->
|
||
<el-form-item label="查体(治疗)" prop="physicalExam" class="form-item-single">
|
||
<el-input
|
||
v-model="formData.physicalExam"
|
||
type="textarea"
|
||
placeholder="请输入查体结果"
|
||
class="tall-textarea"
|
||
autosize
|
||
/>
|
||
</el-form-item>
|
||
|
||
<!-- 处置输入项 -->
|
||
<el-form-item label="处置" prop="treatment" class="form-item-single">
|
||
<el-input
|
||
v-model="formData.treatment"
|
||
type="textarea"
|
||
placeholder="请输入处理方案"
|
||
class="tall-textarea"
|
||
autosize
|
||
/>
|
||
</el-form-item>
|
||
|
||
<!-- 辅助检查输入项 -->
|
||
<el-form-item label="辅助检查" prop="auxiliaryExam" class="form-item-single">
|
||
<el-input
|
||
v-model="formData.auxiliaryExam"
|
||
type="textarea"
|
||
placeholder="请输入辅助检查结果"
|
||
class="tall-textarea"
|
||
autosize
|
||
/>
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
// 导入Vue相关功能和组件
|
||
import { reactive, ref, onBeforeMount, onMounted, watch } from 'vue';
|
||
import useUserStore from '../store/modules/user';
|
||
import { ElInput, ElMessage, ElForm, ElFormItem } from 'element-plus';
|
||
import { patientInfo } from '../views/doctorstation/components/store/patient';
|
||
import { pa } from 'element-plus/es/locales.mjs';
|
||
|
||
// 定义组件选项
|
||
defineOptions({
|
||
name: 'OutpatientMedicalRecord',
|
||
components: { ElInput, ElMessage, ElForm, ElFormItem },
|
||
});
|
||
|
||
// // Props与事件,去掉props.patientInfo改为直接从store获取
|
||
// const props = defineProps({
|
||
// patientInfo: {
|
||
// type: Object,
|
||
// required: true,
|
||
// },
|
||
// });
|
||
|
||
// 定义组件接收的属性(目前为空)
|
||
const props = defineProps({});
|
||
|
||
// 定义组件触发的事件
|
||
const emits = defineEmits(['submitOk']);
|
||
|
||
// 数据初始化
|
||
// 获取用户store实例,用于获取医院名称等全局信息
|
||
const userStore = useUserStore();
|
||
// 患者信息引用,存储当前就诊患者的基本信息
|
||
const patient = ref(null);
|
||
// 表单引用,用于访问表单实例进行验证等操作
|
||
const formRef = ref(null);
|
||
|
||
// 表单数据(全部字符类型)
|
||
// 存储门诊病历表单的所有字段数据
|
||
const formData = reactive({
|
||
height: '', // 身高(cm)
|
||
weight: '', // 体重(kg)
|
||
temperature: '', // 体温(℃)
|
||
pulse: '', // 脉搏(次/分)
|
||
onsetDate: '', // 发病日期
|
||
complaint: '', // 主诉(必填项)
|
||
presentIllness: '', // 现病史
|
||
pastIllness: '', // 既往史
|
||
personalHistory: '', // 个人史
|
||
allergyHistory: '', // 过敏史
|
||
physicalExam: '', // 查体结果
|
||
treatment: '', // 处理方案
|
||
auxiliaryExam: '', // 辅助检查结果
|
||
familyHistory: '', // 家族史
|
||
});
|
||
|
||
// 表单校验规则
|
||
// 定义表单字段的验证规则,目前仅主诉为必填项
|
||
const rules = reactive({
|
||
complaint: [
|
||
{
|
||
required: true,
|
||
message: '请填写主诉',
|
||
trigger: ['blur', 'submit'],
|
||
},
|
||
],
|
||
});
|
||
|
||
// 提交函数
|
||
// 用于触发表单验证并提交数据到父组件
|
||
const submit = () => {
|
||
// 表单验证
|
||
formRef.value.validate((isValid) => {
|
||
if (isValid) {
|
||
// 触发submitOk事件,传递表单数据
|
||
emits('submitOk', formData);
|
||
// 显示成功消息
|
||
ElMessage.success('提交成功');
|
||
}
|
||
});
|
||
};
|
||
|
||
// 日期格式化工具函数
|
||
// 将Date对象格式化为 YYYY-MM-DD HH:mm 格式的字符串
|
||
const formatDateTime = (date) => {
|
||
const year = date.getFullYear();
|
||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||
const day = String(date.getDate()).padStart(2, '0');
|
||
const hour = String(date.getHours()).padStart(2, '0');
|
||
const minute = String(date.getMinutes()).padStart(2, '0');
|
||
return `${year}-${month}-${day} ${hour}:${minute}`;
|
||
};
|
||
|
||
// 表单数据赋值函数
|
||
// 用于外部组件向表单填充已有数据
|
||
const setFormData = (data) => {
|
||
if (data) {
|
||
// 将传入的数据合并到表单数据中
|
||
Object.assign(formData, data);
|
||
}
|
||
};
|
||
|
||
// 生命周期钩子 - 组件挂载前
|
||
onBeforeMount(() => {});
|
||
|
||
// 生命周期钩子 - 组件挂载后
|
||
onMounted(() => {
|
||
console.log('当前患者信息:', patientInfo);
|
||
// 从store获取患者信息
|
||
patient.value = patientInfo.value;
|
||
// 初始化发病日期为当前时间
|
||
if (!formData.onsetDate) {
|
||
formData.onsetDate = formatDateTime(new Date());
|
||
}
|
||
});
|
||
|
||
// 监听患者信息变化,实现联动显示
|
||
// 当patientInfo发生变化时更新本地patient引用
|
||
watch(
|
||
() => patientInfo.value,
|
||
(newPatientInfo) => {
|
||
patient.value = newPatientInfo;
|
||
},
|
||
{ deep: true }
|
||
);
|
||
|
||
// 暴露接口供父组件调用
|
||
// 将formData、submit方法和setFormData方法暴露给父组件使用
|
||
defineExpose({ formData, submit, setFormData });
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* 表单外层容器 */
|
||
.medical-form {
|
||
max-width: 1200px;
|
||
width: 100%;
|
||
min-height: 800px;
|
||
height: 900px;
|
||
margin: 15px auto;
|
||
padding: 15px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 8px;
|
||
font-family: Arial, sans-serif;
|
||
box-sizing: border-box;
|
||
overflow: visible;
|
||
}
|
||
|
||
/* 顶部姓名样式 */
|
||
.patient-name {
|
||
display: inline-block;
|
||
margin-bottom: 15px;
|
||
font-size: 14px;
|
||
color: #333;
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* 滚动内容容器 */
|
||
.form-scroll-container {
|
||
width: 100%;
|
||
max-height: 80vh;
|
||
overflow-y: auto;
|
||
overflow-x: hidden;
|
||
scrollbar-width: thin;
|
||
scrollbar-color: #ccc #f5f5f5;
|
||
}
|
||
.form-scroll-container::-webkit-scrollbar {
|
||
width: 6px;
|
||
}
|
||
.form-scroll-container::-webkit-scrollbar-thumb {
|
||
background-color: #ccc;
|
||
border-radius: 3px;
|
||
}
|
||
.form-scroll-container::-webkit-scrollbar-track {
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
/* 完整表单容器 */
|
||
.medical-full-form {
|
||
width: 100%;
|
||
}
|
||
|
||
/* 区域通用样式 */
|
||
.form-section {
|
||
margin-bottom: 20px;
|
||
}
|
||
.section-title {
|
||
margin: 0 0 12px;
|
||
padding-bottom: 6px;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
color: #333;
|
||
font-size: 16px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* 通用单行自适应布局(基础信息+病史信息共用) */
|
||
.single-row-layout {
|
||
display: flex;
|
||
flex-wrap: wrap; /* 自动换行 */
|
||
align-items: flex-start; /* 顶部对齐,适配文本域高度 */
|
||
gap: 15px; /* 统一元素间距 */
|
||
}
|
||
.row-item {
|
||
margin-bottom: 0; /* 取消底部间距,避免换行重叠 */
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* 基础信息项:适配短输入框 */
|
||
.row-item:not(.history-item) {
|
||
min-width: 160px; /* 基础信息项最小宽度 */
|
||
}
|
||
|
||
/* 病史信息项:适配文本域,设置更大最小宽度 */
|
||
.history-item {
|
||
min-width: 220px; /* 确保文本域有足够宽度 */
|
||
}
|
||
|
||
/* 带单位的输入框样式 */
|
||
.input-with-unit {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
width: 100%;
|
||
}
|
||
.input-with-unit .el-input {
|
||
flex: 1;
|
||
}
|
||
.unit {
|
||
font-weight: 500;
|
||
color: #333;
|
||
white-space: nowrap;
|
||
font-size: 14px;
|
||
}
|
||
|
||
/* 单行表单项样式(主诉、查体等) */
|
||
.form-item-single {
|
||
margin-bottom: 18px;
|
||
}
|
||
|
||
/* 文本域高度控制 */
|
||
.tall-textarea {
|
||
--el-input-textarea-min-height: 100px;
|
||
}
|
||
/* 病史信息文本域:适当降低高度,适配单行布局 */
|
||
.history-item .el-input__inner {
|
||
--el-input-textarea-min-height: 60px;
|
||
}
|
||
|
||
/* 必填项红色星号 */
|
||
.required .el-form-item__label::before {
|
||
content: '* ';
|
||
color: #ff4d4f;
|
||
}
|
||
|
||
/* 输入框统一样式 */
|
||
.el-form-item .el-input,
|
||
.el-form-item .el-input__wrapper {
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
}
|
||
.el-form-item .el-input__inner {
|
||
font-size: 14px;
|
||
padding: 8px 12px;
|
||
}
|
||
|
||
/* 响应式调整 */
|
||
@media (max-width: 768px) {
|
||
.medical-form {
|
||
height: 80vh;
|
||
padding: 10px;
|
||
}
|
||
.form-scroll-container {
|
||
height: calc(100% - 35px);
|
||
}
|
||
.el-form {
|
||
label-width: 70px !important;
|
||
}
|
||
.row-item:not(.history-item) {
|
||
min-width: 130px;
|
||
}
|
||
.history-item {
|
||
min-width: 100%; /* 移动端病史信息全屏宽度,单行显示 */
|
||
}
|
||
.form-item-single,
|
||
.form-section {
|
||
margin-bottom: 15px;
|
||
}
|
||
.tall-textarea {
|
||
--el-input-textarea-min-height: 80px;
|
||
}
|
||
}
|
||
</style> |