|
@@ -0,0 +1,408 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <Dialog v-model="dialogVisible" :title="formTitle" width="92%">
|
|
|
|
|
+ <el-form
|
|
|
|
|
+ ref="formRef"
|
|
|
|
|
+ :model="dataForm"
|
|
|
|
|
+ :rules="dataRule"
|
|
|
|
|
+ label-width="100px"
|
|
|
|
|
+ v-loading="formLoading"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-row :gutter="20">
|
|
|
|
|
+ <el-col :xs="24" :sm="24" :md="12" :lg="6" :xl="6">
|
|
|
|
|
+ <el-form-item label="长者姓名" prop="elderId">
|
|
|
|
|
+ <SelectElder
|
|
|
|
|
+ v-model="dataForm.elderId"
|
|
|
|
|
+ :tId="dataForm.tenantId"
|
|
|
|
|
+ :disabled="isEdit"
|
|
|
|
|
+ @elder="handleSelectElder"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :xs="24" :sm="24" :md="12" :lg="6" :xl="6">
|
|
|
|
|
+ <el-form-item label="楼层房号床号">
|
|
|
|
|
+ <el-input v-model="dataForm.bedInfo" disabled placeholder="选择长者后自动带出" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :xs="24" :sm="24" :md="12" :lg="6" :xl="6">
|
|
|
|
|
+ <el-form-item label="性别">
|
|
|
|
|
+ <el-input v-model="sexText" disabled />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :xs="24" :sm="24" :md="12" :lg="6" :xl="6">
|
|
|
|
|
+ <el-form-item label="记录日期" prop="recordDate">
|
|
|
|
|
+ <el-date-picker
|
|
|
|
|
+ v-model="dataForm.recordDate"
|
|
|
|
|
+ type="date"
|
|
|
|
|
+ style="width: 100%"
|
|
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
|
|
+ placeholder="请选择记录日期"
|
|
|
|
|
+ :disabled-date="disabledDate"
|
|
|
|
|
+ :disabled="isEdit"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ </el-row>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="mb-10px">
|
|
|
|
|
+ <el-button type="primary" @click="handleAdd" :disabled="isEdit">
|
|
|
|
|
+ <Icon icon="ep:plus" class="mr-5px" />添加记录
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <el-button type="danger" @click="handleClear" :disabled="isEdit">
|
|
|
|
|
+ <Icon icon="ep:delete" class="mr-5px" />清空
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <el-table
|
|
|
|
|
+ :data="dataForm.list"
|
|
|
|
|
+ :header-cell-style="tableHeaderColor"
|
|
|
|
|
+ max-height="440"
|
|
|
|
|
+ border
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ label="序号"
|
|
|
|
|
+ type="index"
|
|
|
|
|
+ align="center"
|
|
|
|
|
+ header-align="center"
|
|
|
|
|
+ width="60"
|
|
|
|
|
+ fixed
|
|
|
|
|
+ />
|
|
|
|
|
+ <el-table-column label="时间" align="center" header-align="center" width="150">
|
|
|
|
|
+ <template #default="scope">
|
|
|
|
|
+ <el-time-picker
|
|
|
|
|
+ v-model="scope.row.recordTime"
|
|
|
|
|
+ style="width: 100%"
|
|
|
|
|
+ value-format="HH:mm"
|
|
|
|
|
+ format="HH:mm"
|
|
|
|
|
+ placeholder="选择时间"
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="体温℃" align="center" header-align="center" width="120">
|
|
|
|
|
+ <template #default="scope">
|
|
|
|
|
+ <el-input-number
|
|
|
|
|
+ v-model="scope.row.temperature"
|
|
|
|
|
+ :controls="false"
|
|
|
|
|
+ :precision="1"
|
|
|
|
|
+ :min="20"
|
|
|
|
|
+ :max="45"
|
|
|
|
|
+ style="width: 100%"
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="血氧Spo2" align="center" header-align="center" width="120">
|
|
|
|
|
+ <template #default="scope">
|
|
|
|
|
+ <el-input-number
|
|
|
|
|
+ v-model="scope.row.bloodOxygen"
|
|
|
|
|
+ :controls="false"
|
|
|
|
|
+ :min="0"
|
|
|
|
|
+ :max="100"
|
|
|
|
|
+ style="width: 100%"
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="脉搏(次/分)" align="center" header-align="center" width="130">
|
|
|
|
|
+ <template #default="scope">
|
|
|
|
|
+ <el-input-number
|
|
|
|
|
+ v-model="scope.row.pulse"
|
|
|
|
|
+ :controls="false"
|
|
|
|
|
+ :min="0"
|
|
|
|
|
+ :max="300"
|
|
|
|
|
+ style="width: 100%"
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="呼吸(次/分)" align="center" header-align="center" width="130">
|
|
|
|
|
+ <template #default="scope">
|
|
|
|
|
+ <el-input-number
|
|
|
|
|
+ v-model="scope.row.respiration"
|
|
|
|
|
+ :controls="false"
|
|
|
|
|
+ :min="0"
|
|
|
|
|
+ :max="100"
|
|
|
|
|
+ style="width: 100%"
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="血压mmHg" align="center" header-align="center" width="180">
|
|
|
|
|
+ <template #default="scope">
|
|
|
|
|
+ <el-input-number
|
|
|
|
|
+ v-model="scope.row.systolicPressure"
|
|
|
|
|
+ :controls="false"
|
|
|
|
|
+ :min="0"
|
|
|
|
|
+ :max="300"
|
|
|
|
|
+ style="width: 45%"
|
|
|
|
|
+ />
|
|
|
|
|
+ <span style="width: 10%; display: inline-block; text-align: center">/</span>
|
|
|
|
|
+ <el-input-number
|
|
|
|
|
+ v-model="scope.row.diastolicPressure"
|
|
|
|
|
+ :controls="false"
|
|
|
|
|
+ :min="0"
|
|
|
|
|
+ :max="300"
|
|
|
|
|
+ style="width: 45%"
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="病情观察及护理" header-align="center" min-width="220">
|
|
|
|
|
+ <template #default="scope">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="scope.row.observation"
|
|
|
|
|
+ type="textarea"
|
|
|
|
|
+ :rows="1"
|
|
|
|
|
+ :autosize="{ minRows: 1, maxRows: 3 }"
|
|
|
|
|
+ maxlength="500"
|
|
|
|
|
+ show-word-limit
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="签名" align="center" header-align="center" width="130">
|
|
|
|
|
+ <template #default="scope">
|
|
|
|
|
+ <el-input v-model="scope.row.signer" maxlength="20" />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ label="操作"
|
|
|
|
|
+ align="center"
|
|
|
|
|
+ header-align="center"
|
|
|
|
|
+ width="80"
|
|
|
|
|
+ fixed="right"
|
|
|
|
|
+ v-if="!isEdit"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #default="scope">
|
|
|
|
|
+ <el-button link type="danger" @click="handleDelete(scope.$index)">删除</el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+
|
|
|
|
|
+ <template #footer>
|
|
|
|
|
+ <el-button @click="handleClosed">取消</el-button>
|
|
|
|
|
+ <el-button type="primary" v-loading="formLoading" @click="submitForm">确定</el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Dialog>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script lang="ts" setup>
|
|
|
|
|
+import { FormRules } from 'element-plus'
|
|
|
|
|
+import {
|
|
|
|
|
+ createNursingRecord,
|
|
|
|
|
+ updateNursingRecord,
|
|
|
|
|
+ getNursingRecord
|
|
|
|
|
+} from '@/api/elderly/assess/nursing-record-sheet'
|
|
|
|
|
+import { tableHeaderColor } from '@/utils/table'
|
|
|
|
|
+import { useUserStore } from '@/store/modules/user'
|
|
|
|
|
+
|
|
|
|
|
+defineOptions({ name: 'NursingRecordForm' })
|
|
|
|
|
+
|
|
|
|
|
+const userStore = useUserStore()
|
|
|
|
|
+const nickname = userStore.getUser.nickname
|
|
|
|
|
+const message = useMessage()
|
|
|
|
|
+const { t } = useI18n()
|
|
|
|
|
+
|
|
|
|
|
+const dialogVisible = ref(false) // 弹窗
|
|
|
|
|
+const formRef = ref() // 表单 Ref
|
|
|
|
|
+const formLoading = ref(false) // 提交中
|
|
|
|
|
+const isEdit = ref(false) // 是否编辑
|
|
|
|
|
+
|
|
|
|
|
+const getToday = () => {
|
|
|
|
|
+ const now = new Date()
|
|
|
|
|
+ return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(
|
|
|
|
|
+ now.getDate()
|
|
|
|
|
+ ).padStart(2, '0')}`
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const getCurrentTime = () => {
|
|
|
|
|
+ const now = new Date()
|
|
|
|
|
+ return `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 生成一行空记录 */
|
|
|
|
|
+const buildRow = (row?: Recordable) => ({
|
|
|
|
|
+ id: row?.id,
|
|
|
|
|
+ recordTime: row?.recordTime || getCurrentTime(),
|
|
|
|
|
+ temperature: row?.temperature ?? undefined,
|
|
|
|
|
+ bloodOxygen: row?.bloodOxygen ?? undefined,
|
|
|
|
|
+ pulse: row?.pulse ?? undefined,
|
|
|
|
|
+ respiration: row?.respiration ?? undefined,
|
|
|
|
|
+ systolicPressure: row?.systolicPressure ?? undefined,
|
|
|
|
|
+ diastolicPressure: row?.diastolicPressure ?? undefined,
|
|
|
|
|
+ observation: row?.observation || '',
|
|
|
|
|
+ signer: row?.signer || nickname
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const dataForm = ref<any>({
|
|
|
|
|
+ id: undefined,
|
|
|
|
|
+ tenantId: undefined,
|
|
|
|
|
+ elderId: '',
|
|
|
|
|
+ elderName: '',
|
|
|
|
|
+ elderSex: undefined,
|
|
|
|
|
+ bedInfo: '',
|
|
|
|
|
+ recordDate: getToday(),
|
|
|
|
|
+ list: []
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const dataRule = reactive<FormRules>({
|
|
|
|
|
+ elderId: [{ required: true, message: '长者姓名不能为空', trigger: 'change' }],
|
|
|
|
|
+ recordDate: [{ required: true, message: '记录日期不能为空', trigger: 'change' }]
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const formTitle = computed(() => (isEdit.value ? '编辑-护理记录单' : '新增-护理记录单'))
|
|
|
|
|
+
|
|
|
|
|
+const sexText = computed(() => {
|
|
|
|
|
+ const sex = dataForm.value.elderSex
|
|
|
|
|
+ if (sex === 1 || sex === '1') return '男'
|
|
|
|
|
+ if (sex === 2 || sex === '2') return '女'
|
|
|
|
|
+ return ''
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const disabledDate = (time) => time > Date.now()
|
|
|
|
|
+
|
|
|
|
|
+/** 选择长者后自动带出床位与性别 */
|
|
|
|
|
+const handleSelectElder = (item) => {
|
|
|
|
|
+ if (!item) return
|
|
|
|
|
+ dataForm.value.elderName = item.elderName
|
|
|
|
|
+ dataForm.value.elderSex = item.elderSex
|
|
|
|
|
+ dataForm.value.bedInfo =
|
|
|
|
|
+ [item.buildName, item.floorName, item.roomName, item.bedName].filter(Boolean).join('-') ||
|
|
|
|
|
+ item.bedName ||
|
|
|
|
|
+ ''
|
|
|
|
|
+ if (item.tenantId) dataForm.value.tenantId = item.tenantId
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 打开弹窗 */
|
|
|
|
|
+const open = async (tenantId, id?) => {
|
|
|
|
|
+ resetForm()
|
|
|
|
|
+ dialogVisible.value = true
|
|
|
|
|
+ dataForm.value.tenantId = tenantId
|
|
|
|
|
+ isEdit.value = !!id
|
|
|
|
|
+ if (id) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ formLoading.value = true
|
|
|
|
|
+ const res = await getNursingRecord(id)
|
|
|
|
|
+ dataForm.value.id = res.id
|
|
|
|
|
+ dataForm.value.elderId = res.elderId
|
|
|
|
|
+ dataForm.value.elderName = res.elderName
|
|
|
|
|
+ dataForm.value.elderSex = res.elderSex
|
|
|
|
|
+ dataForm.value.bedInfo = res.bedInfo
|
|
|
|
|
+ dataForm.value.recordDate = res.recordDate
|
|
|
|
|
+ dataForm.value.list = [buildRow(res)]
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ formLoading.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ dataForm.value.list = [buildRow()]
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+defineExpose({ open })
|
|
|
|
|
+
|
|
|
|
|
+const emit = defineEmits(['success'])
|
|
|
|
|
+
|
|
|
|
|
+/** 校验体征数值范围 */
|
|
|
|
|
+const validateRows = () => {
|
|
|
|
|
+ if (dataForm.value.list.length === 0) {
|
|
|
|
|
+ message.warning('请至少添加一条记录')
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
|
|
+ for (const row of dataForm.value.list) {
|
|
|
|
|
+ if (!row.recordTime) {
|
|
|
|
|
+ message.warning('请填写记录时间')
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
|
|
+ const checks = [
|
|
|
|
|
+ [row.temperature, 20, 45, '体温'],
|
|
|
|
|
+ [row.bloodOxygen, 0, 100, '血氧'],
|
|
|
|
|
+ [row.pulse, 0, 300, '脉搏'],
|
|
|
|
|
+ [row.respiration, 0, 100, '呼吸'],
|
|
|
|
|
+ [row.systolicPressure, 0, 300, '收缩压'],
|
|
|
|
|
+ [row.diastolicPressure, 0, 300, '舒张压']
|
|
|
|
|
+ ]
|
|
|
|
|
+ for (const [val, min, max, label] of checks) {
|
|
|
|
|
+ if (val === undefined || val === null || val === '') continue
|
|
|
|
|
+ if (Number(val) < min || Number(val) > max) {
|
|
|
|
|
+ message.error(`${label}应在 ${min} ~ ${max} 之间`)
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (
|
|
|
|
|
+ row.systolicPressure !== undefined &&
|
|
|
|
|
+ row.systolicPressure !== null &&
|
|
|
|
|
+ row.diastolicPressure !== undefined &&
|
|
|
|
|
+ row.diastolicPressure !== null &&
|
|
|
|
|
+ Number(row.diastolicPressure) >= Number(row.systolicPressure)
|
|
|
|
|
+ ) {
|
|
|
|
|
+ message.error('舒张压应小于收缩压')
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return true
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 提交表单 */
|
|
|
|
|
+const submitForm = async () => {
|
|
|
|
|
+ if (formLoading.value) return
|
|
|
|
|
+ if (!formRef.value) return
|
|
|
|
|
+ const valid = await formRef.value.validate()
|
|
|
|
|
+ if (!valid) return
|
|
|
|
|
+ if (!validateRows()) return
|
|
|
|
|
+
|
|
|
|
|
+ formLoading.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ const base = {
|
|
|
|
|
+ tenantId: dataForm.value.tenantId,
|
|
|
|
|
+ elderId: dataForm.value.elderId,
|
|
|
|
|
+ elderName: dataForm.value.elderName,
|
|
|
|
|
+ elderSex: dataForm.value.elderSex,
|
|
|
|
|
+ bedInfo: dataForm.value.bedInfo,
|
|
|
|
|
+ recordDate: dataForm.value.recordDate
|
|
|
|
|
+ }
|
|
|
|
|
+ if (dataForm.value.id) {
|
|
|
|
|
+ await updateNursingRecord({
|
|
|
|
|
+ id: dataForm.value.id,
|
|
|
|
|
+ ...base,
|
|
|
|
|
+ ...dataForm.value.list[0]
|
|
|
|
|
+ })
|
|
|
|
|
+ } else {
|
|
|
|
|
+ for (const row of dataForm.value.list) {
|
|
|
|
|
+ await createNursingRecord({ ...base, ...row })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ message.success(t('common.updateSuccess'))
|
|
|
|
|
+ handleClosed()
|
|
|
|
|
+ emit('success')
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ formLoading.value = false
|
|
|
|
|
+ }, 300)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 重置表单 */
|
|
|
|
|
+const resetForm = () => {
|
|
|
|
|
+ dataForm.value = {
|
|
|
|
|
+ id: undefined,
|
|
|
|
|
+ tenantId: undefined,
|
|
|
|
|
+ elderId: '',
|
|
|
|
|
+ elderName: '',
|
|
|
|
|
+ elderSex: undefined,
|
|
|
|
|
+ bedInfo: '',
|
|
|
|
|
+ recordDate: getToday(),
|
|
|
|
|
+ list: []
|
|
|
|
|
+ }
|
|
|
|
|
+ formRef.value?.resetFields()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const handleClosed = () => {
|
|
|
|
|
+ resetForm()
|
|
|
|
|
+ dialogVisible.value = false
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const handleAdd = () => {
|
|
|
|
|
+ dataForm.value.list.push(buildRow())
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const handleClear = () => {
|
|
|
|
|
+ dataForm.value.list = []
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const handleDelete = (index: number) => {
|
|
|
|
|
+ dataForm.value.list.splice(index, 1)
|
|
|
|
|
+}
|
|
|
|
|
+</script>
|