|
@@ -0,0 +1,677 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <Dialog
|
|
|
|
|
+ v-model="dialogVisible"
|
|
|
|
|
+ :title="title"
|
|
|
|
|
+ width="70%"
|
|
|
|
|
+ class="discharge-summary-dialog"
|
|
|
|
|
+ @close="handleClosed"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-form
|
|
|
|
|
+ ref="formRef"
|
|
|
|
|
+ :model="form"
|
|
|
|
|
+ :rules="rules"
|
|
|
|
|
+ label-width="130px"
|
|
|
|
|
+ v-loading="formLoading"
|
|
|
|
|
+ >
|
|
|
|
|
+ <!-- ============ 基本信息(选择长者后自动回填) ============ -->
|
|
|
|
|
+ <el-divider content-position="left">基本信息</el-divider>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="长者姓名" prop="elderId">
|
|
|
|
|
+ <selectElder
|
|
|
|
|
+ v-if="!isDetail"
|
|
|
|
|
+ :key="selectKey"
|
|
|
|
|
+ v-model="form.elderId"
|
|
|
|
|
+ v-model:elder-name="form.elderName"
|
|
|
|
|
+ v-model:elder-sex="form.gender"
|
|
|
|
|
+ v-model:elder-age="form.elderAge"
|
|
|
|
|
+ :disabled="!!form.id"
|
|
|
|
|
+ @elder="handleSelectElder"
|
|
|
|
|
+ />
|
|
|
|
|
+ <el-input v-else :model-value="form.elderName" disabled />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-row :gutter="16">
|
|
|
|
|
+ <el-col :span="6">
|
|
|
|
|
+ <el-form-item label="性别">
|
|
|
|
|
+ <el-input :model-value="form.genderName" disabled placeholder="选择长者后自动填充" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="6">
|
|
|
|
|
+ <el-form-item label="年龄">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ :model-value="form.elderAge !== '' && form.elderAge !== undefined && form.elderAge !== null ? `${form.elderAge}岁` : ''"
|
|
|
|
|
+ disabled
|
|
|
|
|
+ placeholder="选择长者后自动填充"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <el-form-item label="居住区域">
|
|
|
|
|
+ <el-input :model-value="form.bedName" disabled placeholder="选择长者后自动填充" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ </el-row>
|
|
|
|
|
+
|
|
|
|
|
+ <el-row :gutter="16">
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <el-form-item label="入住日期" prop="checkInDate">
|
|
|
|
|
+ <!-- 选择长者后由 checkInTime 自动回填,不可编辑 -->
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ :model-value="form.checkInDate"
|
|
|
|
|
+ disabled
|
|
|
|
|
+ placeholder="选择长者后自动填充"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <el-form-item label="出院日期" prop="dischargeDate">
|
|
|
|
|
+ <el-date-picker
|
|
|
|
|
+ v-model="form.dischargeDate"
|
|
|
|
|
+ type="date"
|
|
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
|
|
+ format="YYYY-MM-DD"
|
|
|
|
|
+ placeholder="选择出院日期"
|
|
|
|
|
+ style="width: 100%"
|
|
|
|
|
+ :disabled="isDetail"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ </el-row>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- ============ 一、入住基本健康评估状况 ============ -->
|
|
|
|
|
+ <el-divider content-position="left">一、入住基本健康评估状况</el-divider>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="既往病史">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="form.pastMedicalHistory"
|
|
|
|
|
+ type="textarea"
|
|
|
|
|
+ :rows="3"
|
|
|
|
|
+ placeholder="请填写入院时已确诊的疾病及症状程度"
|
|
|
|
|
+ :disabled="isDetail"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="近期健康问题">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="form.recentHealthProblems"
|
|
|
|
|
+ type="textarea"
|
|
|
|
|
+ :rows="3"
|
|
|
|
|
+ placeholder="如近期血压、糖尿是否平稳、关节疼痛情况(部位、疼痛性质)等,需明确记录入院时已确诊的疾病及症状程度"
|
|
|
|
|
+ :disabled="isDetail"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="身体活动能力">
|
|
|
|
|
+ <el-radio-group v-model="form.physicalAbility" :disabled="isDetail">
|
|
|
|
|
+ <el-radio
|
|
|
|
|
+ v-for="o in PHYSICAL_ABILITY_OPTIONS"
|
|
|
|
|
+ :key="o.value"
|
|
|
|
|
+ :value="o.value"
|
|
|
|
|
+ class="block-radio"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ o.label }}
|
|
|
|
|
+ </el-radio>
|
|
|
|
|
+ </el-radio-group>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="认知与精神状态">
|
|
|
|
|
+ <el-radio-group v-model="form.cognitiveStatus" :disabled="isDetail">
|
|
|
|
|
+ <el-radio
|
|
|
|
|
+ v-for="o in COGNITIVE_STATUS_OPTIONS"
|
|
|
|
|
+ :key="o.value"
|
|
|
|
|
+ :value="o.value"
|
|
|
|
|
+ class="block-radio"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ o.label }}
|
|
|
|
|
+ </el-radio>
|
|
|
|
|
+ </el-radio-group>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- ============ 二、在院期间发生疾病和治疗情况 ============ -->
|
|
|
|
|
+ <el-divider content-position="left">二、在院期间发生疾病和治疗情况</el-divider>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="疾病治疗与控制">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="form.diseaseTreatment"
|
|
|
|
|
+ type="textarea"
|
|
|
|
|
+ :rows="3"
|
|
|
|
|
+ placeholder="记录在院期间针对基础疾病的治疗措施(如分级护理、吸氧、饮食、用药问题)"
|
|
|
|
|
+ :disabled="isDetail"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="近期就医情况">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="form.recentMedicalVisit"
|
|
|
|
|
+ type="textarea"
|
|
|
|
|
+ :rows="3"
|
|
|
|
|
+ placeholder="3-6个月的外出就医情况(如:何时因何原因外出就医,就诊医院,主要诊断,回院日期,回院后长者身体情况)"
|
|
|
|
|
+ :disabled="isDetail"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- ============ 三、出院长者状况 ============ -->
|
|
|
|
|
+ <el-divider content-position="left">三、出院长者状况</el-divider>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="出院原因" prop="dischargeReason">
|
|
|
|
|
+ <el-radio-group v-model="form.dischargeReason" :disabled="isDetail">
|
|
|
|
|
+ <el-radio
|
|
|
|
|
+ v-for="o in DISCHARGE_REASON_OPTIONS"
|
|
|
|
|
+ :key="o.value"
|
|
|
|
|
+ :value="o.value"
|
|
|
|
|
+ class="inline-radio"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ o.label }}
|
|
|
|
|
+ </el-radio>
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-if="form.dischargeReason === DISCHARGE_REASON.OTHER"
|
|
|
|
|
+ v-model="form.dischargeReasonOther"
|
|
|
|
|
+ placeholder="请填写其他出院原因"
|
|
|
|
|
+ style="width: 240px; margin-left: 8px"
|
|
|
|
|
+ :disabled="isDetail"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-radio-group>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="生命体征">
|
|
|
|
|
+ <div class="vital-signs">
|
|
|
|
|
+ <span class="vital-label">P:</span>
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="form.pulse"
|
|
|
|
|
+ placeholder="脉搏"
|
|
|
|
|
+ style="width: 100px"
|
|
|
|
|
+ :disabled="isDetail"
|
|
|
|
|
+ />
|
|
|
|
|
+ <span class="vital-unit">次/分</span>
|
|
|
|
|
+
|
|
|
|
|
+ <span class="vital-label">R:</span>
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="form.respiration"
|
|
|
|
|
+ placeholder="呼吸"
|
|
|
|
|
+ style="width: 100px"
|
|
|
|
|
+ :disabled="isDetail"
|
|
|
|
|
+ />
|
|
|
|
|
+ <span class="vital-unit">次/分</span>
|
|
|
|
|
+
|
|
|
|
|
+ <span class="vital-label">HP:</span>
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="form.systolicPressure"
|
|
|
|
|
+ placeholder="收缩压"
|
|
|
|
|
+ style="width: 90px"
|
|
|
|
|
+ :disabled="isDetail"
|
|
|
|
|
+ />
|
|
|
|
|
+ <span class="vital-unit">/</span>
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="form.diastolicPressure"
|
|
|
|
|
+ placeholder="舒张压"
|
|
|
|
|
+ style="width: 90px"
|
|
|
|
|
+ :disabled="isDetail"
|
|
|
|
|
+ />
|
|
|
|
|
+ <span class="vital-unit">mmhg</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="身体功能">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="form.bodyFunction"
|
|
|
|
|
+ type="textarea"
|
|
|
|
|
+ :rows="3"
|
|
|
|
|
+ placeholder="对当前的意识状态、认知能力(如有无痴呆症状加重)、肢体活动能力、吞咽功能、皮肤状况、留置管道等情况进行描述"
|
|
|
|
|
+ :disabled="isDetail"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- ============ 四、用药情况(死亡出院不需要填写) ============ -->
|
|
|
|
|
+ <template v-if="!isDeathDischarge(form.dischargeReason)">
|
|
|
|
|
+ <el-divider content-position="left">
|
|
|
|
|
+ 四、用药情况(死亡出院不需要填写)
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ v-if="!isDetail"
|
|
|
|
|
+ link
|
|
|
|
|
+ type="primary"
|
|
|
|
|
+ class="!ml-10px"
|
|
|
|
|
+ @click="handleAddMedication"
|
|
|
|
|
+ >
|
|
|
|
|
+ <Icon icon="ep:plus" class="mr-2px" />新增药品
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </el-divider>
|
|
|
|
|
+
|
|
|
|
|
+ <el-table :data="form.medications" border style="width: 100%" size="default">
|
|
|
|
|
+ <el-table-column label="序号" type="index" width="60" align="center" />
|
|
|
|
|
+ <el-table-column label="药名" min-width="160">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-input v-model="row.drugName" placeholder="请输入药名" :disabled="isDetail" />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="剂量" min-width="120">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-input v-model="row.dosage" placeholder="如 5mg" :disabled="isDetail" />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="用法" min-width="140">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-input v-model="row.usageMethod" placeholder="如 口服" :disabled="isDetail" />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="频次" min-width="140">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-input v-model="row.frequency" placeholder="如 每日3次" :disabled="isDetail" />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column v-if="!isDetail" label="操作" width="90" align="center">
|
|
|
|
|
+ <template #default="{ $index }">
|
|
|
|
|
+ <el-button link type="danger" @click="handleRemoveMedication($index)">删除</el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+
|
|
|
|
|
+ <div v-if="!form.medications || form.medications.length === 0" class="empty-tip">
|
|
|
|
|
+ 暂无用药记录,点击右上「新增药品」添加
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- ============ 五、出院指导(死亡出院不需填写) ============ -->
|
|
|
|
|
+ <template v-if="!isDeathDischarge(form.dischargeReason)">
|
|
|
|
|
+ <el-divider content-position="left">五、出院指导(死亡出院不需填写)</el-divider>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="重点关注问题">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="form.focusProblems"
|
|
|
|
|
+ type="textarea"
|
|
|
|
|
+ :rows="3"
|
|
|
|
|
+ placeholder="请填写出院后需要重点关注的问题"
|
|
|
|
|
+ :disabled="isDetail"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="安全防护">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="form.safetyProtection"
|
|
|
|
|
+ type="textarea"
|
|
|
|
|
+ :rows="3"
|
|
|
|
|
+ placeholder="防跌倒、防走失、防呛咳、防管道脱落等措施"
|
|
|
|
|
+ :disabled="isDetail"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="饮食与就医">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="form.dietAndMedical"
|
|
|
|
|
+ type="textarea"
|
|
|
|
|
+ :rows="3"
|
|
|
|
|
+ placeholder="饮食指导,出现什么症状建议就医"
|
|
|
|
|
+ :disabled="isDetail"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- ============ 签名 ============ -->
|
|
|
|
|
+ <el-divider content-position="left">签名</el-divider>
|
|
|
|
|
+
|
|
|
|
|
+ <el-row :gutter="16">
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <el-form-item label="医生签名">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="form.doctorSign"
|
|
|
|
|
+ placeholder="请输入医生签名"
|
|
|
|
|
+ :disabled="isDetail"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <el-form-item label="签名日期">
|
|
|
|
|
+ <el-date-picker
|
|
|
|
|
+ v-model="form.signDate"
|
|
|
|
|
+ type="date"
|
|
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
|
|
+ format="YYYY-MM-DD"
|
|
|
|
|
+ placeholder="选择签名日期"
|
|
|
|
|
+ style="width: 100%"
|
|
|
|
|
+ :disabled="isDetail"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ </el-row>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+
|
|
|
|
|
+ <template #footer>
|
|
|
|
|
+ <el-button @click="handleClosed">关闭</el-button>
|
|
|
|
|
+ <el-button v-if="isDetail" type="primary" @click="handlePrint">打印</el-button>
|
|
|
|
|
+ <el-button v-if="!isDetail" v-loading="formLoading" type="primary" @click="submitForm">
|
|
|
|
|
+ 保存
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Dialog>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 打印预览 -->
|
|
|
|
|
+ <Print ref="printRef" />
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script lang="ts" setup>
|
|
|
|
|
+import {
|
|
|
|
|
+ getDischargeSummary,
|
|
|
|
|
+ createDischargeSummary,
|
|
|
|
|
+ updateDischargeSummary,
|
|
|
|
|
+ DISCHARGE_REASON,
|
|
|
|
|
+ DISCHARGE_REASON_OPTIONS,
|
|
|
|
|
+ isDeathDischarge,
|
|
|
|
|
+ PHYSICAL_ABILITY_OPTIONS,
|
|
|
|
|
+ COGNITIVE_STATUS_OPTIONS,
|
|
|
|
|
+ type DischargeSummaryForm,
|
|
|
|
|
+ type DischargeMedication
|
|
|
|
|
+} from '@/api/elderly/elder/discharge-summary'
|
|
|
|
|
+import { getDictLabel, DICT_TYPE } from '@/utils/dict'
|
|
|
|
|
+import dayjs from 'dayjs'
|
|
|
|
|
+import { getElderInfoById } from '@/api/elderly/elder/elderly-Info'
|
|
|
|
|
+import Print from './Print.vue'
|
|
|
|
|
+
|
|
|
|
|
+defineOptions({ name: 'DischargeSummaryForm' })
|
|
|
|
|
+
|
|
|
|
|
+const message = useMessage()
|
|
|
|
|
+const { t } = useI18n()
|
|
|
|
|
+
|
|
|
|
|
+const dialogVisible = ref(false)
|
|
|
|
|
+const formLoading = ref(false)
|
|
|
|
|
+const isDetail = ref(false)
|
|
|
|
|
+const formRef = ref()
|
|
|
|
|
+const printRef = ref()
|
|
|
|
|
+// 每次开弹窗递增,强制 selectElder 重新挂载,避免其内部 list 残留
|
|
|
|
|
+const selectKey = ref(0)
|
|
|
|
|
+
|
|
|
|
|
+const emptyMedication = (): DischargeMedication => ({
|
|
|
|
|
+ drugName: '',
|
|
|
|
|
+ dosage: '',
|
|
|
|
|
+ usageMethod: '',
|
|
|
|
|
+ frequency: ''
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 日期统一格式化为 YYYY-MM-DD
|
|
|
|
|
+ * 兼容毫秒时间戳(13位) / 秒级时间戳(10位) / Date / 各种日期字符串;非法值返回空串
|
|
|
|
|
+ * (长者档案的 checkInTime 后端可能返回时间戳,直接塞给 el-input 会显示成一串数字)
|
|
|
|
|
+ */
|
|
|
|
|
+const formatDate = (val: any): string => {
|
|
|
|
|
+ if (val === '' || val === null || val === undefined) return ''
|
|
|
|
|
+ let input: any = val
|
|
|
|
|
+ const num = Number(val)
|
|
|
|
|
+ if (!Number.isNaN(num) && num > 0 && String(val).length <= 10) {
|
|
|
|
|
+ input = num * 1000 // 秒级时间戳
|
|
|
|
|
+ }
|
|
|
|
|
+ const d = dayjs(input)
|
|
|
|
|
+ return d.isValid() ? d.format('YYYY-MM-DD') : ''
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const defaultForm: DischargeSummaryForm = {
|
|
|
|
|
+ id: undefined,
|
|
|
|
|
+ elderId: undefined,
|
|
|
|
|
+ elderName: '',
|
|
|
|
|
+ gender: '',
|
|
|
|
|
+ genderName: '',
|
|
|
|
|
+ elderAge: '',
|
|
|
|
|
+ bedName: '',
|
|
|
|
|
+ checkInDate: '',
|
|
|
|
|
+ dischargeDate: '',
|
|
|
|
|
+ // 一、入住基本健康评估状况
|
|
|
|
|
+ pastMedicalHistory: '',
|
|
|
|
|
+ recentHealthProblems: '',
|
|
|
|
|
+ physicalAbility: undefined,
|
|
|
|
|
+ cognitiveStatus: undefined,
|
|
|
|
|
+ // 二、在院期间发生疾病和治疗情况
|
|
|
|
|
+ diseaseTreatment: '',
|
|
|
|
|
+ recentMedicalVisit: '',
|
|
|
|
|
+ // 三、出院长者状况
|
|
|
|
|
+ dischargeReason: undefined,
|
|
|
|
|
+ dischargeReasonOther: '',
|
|
|
|
|
+ pulse: '',
|
|
|
|
|
+ respiration: '',
|
|
|
|
|
+ systolicPressure: '',
|
|
|
|
|
+ diastolicPressure: '',
|
|
|
|
|
+ bodyFunction: '',
|
|
|
|
|
+ // 四、用药情况
|
|
|
|
|
+ medications: [emptyMedication()],
|
|
|
|
|
+ // 五、出院指导
|
|
|
|
|
+ focusProblems: '',
|
|
|
|
|
+ safetyProtection: '',
|
|
|
|
|
+ dietAndMedical: '',
|
|
|
|
|
+ // 签名
|
|
|
|
|
+ doctorSign: '',
|
|
|
|
|
+ signDate: ''
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const form = reactive(JSON.parse(JSON.stringify(defaultForm)))
|
|
|
|
|
+
|
|
|
|
|
+const title = computed(() => {
|
|
|
|
|
+ if (isDetail.value) return '出院小结详情'
|
|
|
|
|
+ return form.id ? '编辑出院小结' : '新增出院小结'
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const rules = {
|
|
|
|
|
+ elderId: [{ required: true, message: '请选择长者', trigger: 'change' }],
|
|
|
|
|
+ dischargeDate: [{ required: true, message: '请选择出院日期', trigger: 'change' }],
|
|
|
|
|
+ dischargeReason: [{ required: true, message: '请选择出院原因', trigger: 'change' }],
|
|
|
|
|
+ dischargeReasonOther: [
|
|
|
|
|
+ {
|
|
|
|
|
+ validator: (_rule: any, _value: any, callback: any) => {
|
|
|
|
|
+ // 出院原因 = 其他(5) 时,必须补充说明
|
|
|
|
|
+ if (
|
|
|
|
|
+ Number(form.dischargeReason) === DISCHARGE_REASON.OTHER &&
|
|
|
|
|
+ !form.dischargeReasonOther
|
|
|
|
|
+ ) {
|
|
|
|
|
+ callback(new Error('请填写其他出院原因'))
|
|
|
|
|
+ } else {
|
|
|
|
|
+ callback()
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ trigger: ['change', 'blur']
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 选择长者后补全:性别字典、居住区域(楼-区-房-床)、入住日期
|
|
|
|
|
+ * 注意:不绑 v-model:bed-name,居住区域需要拼接 楼/区/房/床 四段,
|
|
|
|
|
+ * 由本函数在 @elder 事件里统一赋值(selectElder 内部先 emit bed-name 再 emit elder,本函数后执行生效)
|
|
|
|
|
+ *
|
|
|
|
|
+ * ⚠️ 入住日期来源:selectElder 在下拉选择时 emit 的是【分页列表项】,该对象不含 checkInTime 字段,
|
|
|
|
|
+ * 只有详情接口 elderlyInfo/findDetailById 才返回完整档案(含 checkInTime)。
|
|
|
|
|
+ * 因此这里必须按 id 拉一次详情来取入住时间,否则入住日期永远回填为空。
|
|
|
|
|
+ */
|
|
|
|
|
+const handleSelectElder = async (elder: any) => {
|
|
|
|
|
+ if (!elder || !elder.id) return
|
|
|
|
|
+ // 优先用详情接口补全 checkInTime(下拉列表项不含入住时间字段)
|
|
|
|
|
+ let full = elder
|
|
|
|
|
+ try {
|
|
|
|
|
+ const detail = await getElderInfoById(elder.id)
|
|
|
|
|
+ if (detail) full = detail
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ full = elder
|
|
|
|
|
+ }
|
|
|
|
|
+ form.gender = full.elderSex ?? elder.elderSex ?? form.gender
|
|
|
|
|
+ form.genderName = getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, form.gender) || ''
|
|
|
|
|
+ form.elderAge = full.elderAge ?? elder.elderAge ?? ''
|
|
|
|
|
+ // 居住区域:楼-区-房-床,缺失段落自动跳过(详情优先,列表项兜底)
|
|
|
|
|
+ const area = [
|
|
|
|
|
+ full.buildName ?? elder.buildName,
|
|
|
|
|
+ full.floorName ?? elder.floorName,
|
|
|
|
|
+ full.roomName ?? elder.roomName,
|
|
|
|
|
+ full.bedName ?? elder.bedName
|
|
|
|
|
+ ]
|
|
|
|
|
+ .filter(Boolean)
|
|
|
|
|
+ .join('-')
|
|
|
|
|
+ form.bedName = area || full.bedName || elder.bedName || ''
|
|
|
|
|
+ // 入住日期:取长者档案的 checkInTime 自动回填(可能是毫秒时间戳或带时分秒的字符串,统一格式化为 YYYY-MM-DD)
|
|
|
|
|
+ // 详情接口字段名 checkInTime;列表项/兜底字段名为 checkInDate / inDate
|
|
|
|
|
+ form.checkInDate = formatDate(
|
|
|
|
|
+ full.checkInTime ??
|
|
|
|
|
+ elder.checkInTime ??
|
|
|
|
|
+ full.checkInDate ??
|
|
|
|
|
+ elder.checkInDate ??
|
|
|
|
|
+ full.inDate ??
|
|
|
|
|
+ elder.inDate ??
|
|
|
|
|
+ ''
|
|
|
|
|
+ )
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 打开弹窗:detail=true 表示只读(详情场景) */
|
|
|
|
|
+const open = async (row: any = {}, detail: boolean = false) => {
|
|
|
|
|
+ // 1. 先把内部状态彻底清空,避免 selectElder 拿到旧 modelValue 触发其内部 watch
|
|
|
|
|
+ resetForm()
|
|
|
|
|
+ // 2. 递增 selectKey,强制 selectElder 重新挂载(防止内部 list/搜索关键字残留)
|
|
|
|
|
+ selectKey.value++
|
|
|
|
|
+ // 3. 开弹窗
|
|
|
|
|
+ dialogVisible.value = true
|
|
|
|
|
+ isDetail.value = !!detail
|
|
|
|
|
+ await nextTick()
|
|
|
|
|
+ if (row?.id) {
|
|
|
|
|
+ formLoading.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ const data: any = await getDischargeSummary(row.id)
|
|
|
|
|
+ Object.assign(form, defaultForm, data)
|
|
|
|
|
+ form.genderName = getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, form.gender) || ''
|
|
|
|
|
+ // 日期统一格式化,避免后端返回时间戳导致 el-date-picker / 回填输入框显示异常
|
|
|
|
|
+ form.checkInDate = formatDate(form.checkInDate)
|
|
|
|
|
+ form.dischargeDate = formatDate(form.dischargeDate)
|
|
|
|
|
+ form.signDate = formatDate(form.signDate)
|
|
|
|
|
+ form.medications = (data.medications || []).map((m: any) => ({ ...emptyMedication(), ...m }))
|
|
|
|
|
+ if (form.medications.length === 0) form.medications = [emptyMedication()]
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ formLoading.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+defineExpose({ open })
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 表单重置:必须逐字段显式重置!
|
|
|
|
|
+ * 不能用 Object.assign(form, JSON.parse(JSON.stringify(defaultForm))):
|
|
|
|
|
+ * JSON.stringify 会丢弃值为 undefined 的字段(如 id / elderId / dischargeReason),
|
|
|
|
|
+ * 反序列化后 source 没有这些 key,Object.assign 只复制 source 自身可枚举属性,
|
|
|
|
|
+ * 导致 form.id 等残留 → Dialog 标题误判为「编辑」、selectElder 被 :disabled="!!form.id" 锁死。
|
|
|
|
|
+ */
|
|
|
|
|
+const resetForm = () => {
|
|
|
|
|
+ form.id = undefined
|
|
|
|
|
+ form.elderId = undefined
|
|
|
|
|
+ form.elderName = ''
|
|
|
|
|
+ form.gender = ''
|
|
|
|
|
+ form.genderName = ''
|
|
|
|
|
+ form.elderAge = ''
|
|
|
|
|
+ form.bedName = ''
|
|
|
|
|
+ form.checkInDate = ''
|
|
|
|
|
+ form.dischargeDate = ''
|
|
|
|
|
+ form.pastMedicalHistory = ''
|
|
|
|
|
+ form.recentHealthProblems = ''
|
|
|
|
|
+ form.physicalAbility = undefined
|
|
|
|
|
+ form.cognitiveStatus = undefined
|
|
|
|
|
+ form.diseaseTreatment = ''
|
|
|
|
|
+ form.recentMedicalVisit = ''
|
|
|
|
|
+ form.dischargeReason = undefined
|
|
|
|
|
+ form.dischargeReasonOther = ''
|
|
|
|
|
+ form.pulse = ''
|
|
|
|
|
+ form.respiration = ''
|
|
|
|
|
+ form.systolicPressure = ''
|
|
|
|
|
+ form.diastolicPressure = ''
|
|
|
|
|
+ form.bodyFunction = ''
|
|
|
|
|
+ form.medications = [emptyMedication()]
|
|
|
|
|
+ form.focusProblems = ''
|
|
|
|
|
+ form.safetyProtection = ''
|
|
|
|
|
+ form.dietAndMedical = ''
|
|
|
|
|
+ form.doctorSign = ''
|
|
|
|
|
+ form.signDate = ''
|
|
|
|
|
+ formRef.value?.clearValidate()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const handleClosed = () => {
|
|
|
|
|
+ resetForm()
|
|
|
|
|
+ dialogVisible.value = false
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 新增 / 删除用药记录 */
|
|
|
|
|
+const handleAddMedication = () => {
|
|
|
|
|
+ form.medications.push(emptyMedication())
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const handleRemoveMedication = (idx: number) => {
|
|
|
|
|
+ if (idx < 0) return
|
|
|
|
|
+ form.medications.splice(idx, 1)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 从详情页打开打印 */
|
|
|
|
|
+const handlePrint = () => {
|
|
|
|
|
+ printRef.value?.open({ id: form.id })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const emit = defineEmits(['success'])
|
|
|
|
|
+
|
|
|
|
|
+const submitForm = async () => {
|
|
|
|
|
+ if (formLoading.value) return
|
|
|
|
|
+ const valid = await formRef.value?.validate().catch(() => false)
|
|
|
|
|
+ if (!valid) return
|
|
|
|
|
+ formLoading.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 死亡出院(院内/院外):用药情况与出院指导不需填写,提交时清空,避免脏数据入库
|
|
|
|
|
+ const death = isDeathDischarge(form.dischargeReason)
|
|
|
|
|
+ const payload: DischargeSummaryForm = {
|
|
|
|
|
+ ...form,
|
|
|
|
|
+ medications: death
|
|
|
|
|
+ ? []
|
|
|
|
|
+ : (form.medications || []).filter((m: DischargeMedication) => m.drugName),
|
|
|
|
|
+ focusProblems: death ? '' : form.focusProblems,
|
|
|
|
|
+ safetyProtection: death ? '' : form.safetyProtection,
|
|
|
|
|
+ dietAndMedical: death ? '' : form.dietAndMedical
|
|
|
|
|
+ }
|
|
|
|
|
+ if (form.id) {
|
|
|
|
|
+ await updateDischargeSummary(payload)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ await createDischargeSummary(payload)
|
|
|
|
|
+ }
|
|
|
|
|
+ message.success(t(form.id ? 'common.updateSuccess' : 'common.createSuccess'))
|
|
|
|
|
+ emit('success')
|
|
|
|
|
+ handleClosed()
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ formLoading.value = false
|
|
|
|
|
+ }, 300)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped lang="scss">
|
|
|
|
|
+.discharge-summary-dialog :deep(.el-form-item) {
|
|
|
|
|
+ margin-bottom: 18px;
|
|
|
|
|
+}
|
|
|
|
|
+// 身体活动能力 / 认知状态 选项文案较长,每项独占一行
|
|
|
|
|
+.block-radio {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ margin-right: 0;
|
|
|
|
|
+ height: auto;
|
|
|
|
|
+ line-height: 24px;
|
|
|
|
|
+ white-space: normal;
|
|
|
|
|
+}
|
|
|
|
|
+.inline-radio {
|
|
|
|
|
+ margin-right: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+.vital-signs {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ gap: 4px;
|
|
|
|
|
+ .vital-label {
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ margin-left: 8px;
|
|
|
|
|
+ &:first-child {
|
|
|
|
|
+ margin-left: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .vital-unit {
|
|
|
|
|
+ color: #606266;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+.empty-tip {
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ color: #999;
|
|
|
|
|
+ padding: 16px 0;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ border: 1px dashed #ddd;
|
|
|
|
|
+ border-top: none;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|