|
@@ -36,7 +36,13 @@
|
|
|
|
|
|
|
|
<!-- 列表 -->
|
|
<!-- 列表 -->
|
|
|
<ContentWrap v-if="!visible">
|
|
<ContentWrap v-if="!visible">
|
|
|
- <TabBarBtn @add="openForm()" @export="handleExport" @del="handleDelete" />
|
|
|
|
|
|
|
+ <TabBarBtn @add="openForm()" @export="handleExport" @del="handleDelete">
|
|
|
|
|
+ <template #next>
|
|
|
|
|
+ <el-button type="warning" plain @click="handleSingleExport">
|
|
|
|
|
+ <Icon icon="ep:download" class="mr-5px" /> 单人导出
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </TabBarBtn>
|
|
|
<Table2
|
|
<Table2
|
|
|
selection
|
|
selection
|
|
|
@selectionChange="handleSelectionChange"
|
|
@selectionChange="handleSelectionChange"
|
|
@@ -45,14 +51,7 @@
|
|
|
:columns="VitalSignColumns"
|
|
:columns="VitalSignColumns"
|
|
|
:queryParams="queryParams"
|
|
:queryParams="queryParams"
|
|
|
@detail="openDetail"
|
|
@detail="openDetail"
|
|
|
- :opWidth="220"
|
|
|
|
|
- >
|
|
|
|
|
- <template #next="{ scope }">
|
|
|
|
|
- <el-button link type="primary" @click="handleRowExport(scope)">
|
|
|
|
|
- <Icon icon="ep:download" class="mr-5px" /> 导出
|
|
|
|
|
- </el-button>
|
|
|
|
|
- </template>
|
|
|
|
|
- </Table2>
|
|
|
|
|
|
|
+ />
|
|
|
|
|
|
|
|
<!-- 分页 -->
|
|
<!-- 分页 -->
|
|
|
<Pagination
|
|
<Pagination
|
|
@@ -75,8 +74,6 @@ import Export from './Export.vue'
|
|
|
import Detail from './Detail.vue'
|
|
import Detail from './Detail.vue'
|
|
|
import { useUserStore } from '@/store/modules/user'
|
|
import { useUserStore } from '@/store/modules/user'
|
|
|
import * as XLSX from 'xlsx-js-style'
|
|
import * as XLSX from 'xlsx-js-style'
|
|
|
-import { getDictLabel } from '@/utils/dict'
|
|
|
|
|
-import { DICT_TYPE } from '@/utils/dict'
|
|
|
|
|
import { formatTime } from '@/utils'
|
|
import { formatTime } from '@/utils'
|
|
|
defineOptions({ name: 'VitalSign' })
|
|
defineOptions({ name: 'VitalSign' })
|
|
|
const userStore = useUserStore()
|
|
const userStore = useUserStore()
|
|
@@ -163,93 +160,90 @@ const handleDelete = async () => {
|
|
|
} catch {}
|
|
} catch {}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-/** 单行导出 */
|
|
|
|
|
-const handleRowExport = (row: any) => {
|
|
|
|
|
|
|
+/** 去除指标值中的偏高/偏低标记,只保留原始数值(如 36.5(偏高) => 36.5) */
|
|
|
|
|
+const stripMetric = (val: any) => {
|
|
|
|
|
+ if (val === null || val === undefined || val === '') return ''
|
|
|
|
|
+ const str = String(val)
|
|
|
|
|
+ const indexEn = str.indexOf('(')
|
|
|
|
|
+ const indexCn = str.indexOf('(')
|
|
|
|
|
+ let index = -1
|
|
|
|
|
+ if (indexEn !== -1 && indexCn !== -1) {
|
|
|
|
|
+ index = Math.min(indexEn, indexCn)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ index = indexEn !== -1 ? indexEn : indexCn
|
|
|
|
|
+ }
|
|
|
|
|
+ return index === -1 ? str : str.substring(0, index).trim()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 单人导出 */
|
|
|
|
|
+const handleSingleExport = async () => {
|
|
|
|
|
+ if (!queryParams.elderName) {
|
|
|
|
|
+ message.warning('请先输入长者姓名')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
const wb = XLSX.utils.book_new()
|
|
const wb = XLSX.utils.book_new()
|
|
|
- const headers = [
|
|
|
|
|
- '体温℃',
|
|
|
|
|
- '脉搏/分',
|
|
|
|
|
- '呼吸/分',
|
|
|
|
|
- '收缩压mmHg',
|
|
|
|
|
- '舒张压mmHg',
|
|
|
|
|
- '血压饱和度%',
|
|
|
|
|
- '血糖mmol/L',
|
|
|
|
|
- '体重kg',
|
|
|
|
|
- '大便',
|
|
|
|
|
- '小便',
|
|
|
|
|
- '备注',
|
|
|
|
|
- '测量人',
|
|
|
|
|
- '测量时间',
|
|
|
|
|
- '测量日期'
|
|
|
|
|
- ]
|
|
|
|
|
|
|
+ const headers = ['日期', '时间', '体温', '脉搏', '呼吸', '血压', '血氧']
|
|
|
const colCount = headers.length
|
|
const colCount = headers.length
|
|
|
- const sexText = getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, row.elderSex) || row.elderSex
|
|
|
|
|
- const measuringDateText = row.measuringDate ? formatTime(row.measuringDate, 'yyyy-MM-dd') : ''
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 查询该长者所有数据
|
|
|
|
|
+ const data = await getVitalSignsPage({ ...queryParams, pageNo: 1, pageSize: 99999 })
|
|
|
|
|
+ const records: Recordable[] = data.list || []
|
|
|
|
|
+ if (records.length === 0) {
|
|
|
|
|
+ message.warning('未查询到该长者的生命体征数据')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// 标题行
|
|
// 标题行
|
|
|
const titleRow: string[] = new Array(colCount).fill('')
|
|
const titleRow: string[] = new Array(colCount).fill('')
|
|
|
titleRow[0] = '生命体征'
|
|
titleRow[0] = '生命体征'
|
|
|
|
|
|
|
|
- // 基本信息行:姓名 / 性别 / 床号 均匀分布,中间留空列
|
|
|
|
|
|
|
+ // 基本信息行:姓名 / 床号
|
|
|
|
|
+ const first = records[0]
|
|
|
const infoItems = [
|
|
const infoItems = [
|
|
|
- { label: '姓名:', value: row.elderName || '', start: 0, span: 4 },
|
|
|
|
|
- { label: '性别:', value: sexText, start: 5, span: 4 },
|
|
|
|
|
- { label: '床号:', value: row.bedName || '', start: 10, span: 4 }
|
|
|
|
|
|
|
+ { label: '姓名:', value: first.elderName || '', start: 0, span: 3 },
|
|
|
|
|
+ { label: '床号:', value: first.bedName || '', start: 4, span: 3 }
|
|
|
]
|
|
]
|
|
|
const infoRow: string[] = new Array(colCount).fill('')
|
|
const infoRow: string[] = new Array(colCount).fill('')
|
|
|
infoItems.forEach((item) => {
|
|
infoItems.forEach((item) => {
|
|
|
infoRow[item.start] = item.label + item.value
|
|
infoRow[item.start] = item.label + item.value
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
- // 表头行
|
|
|
|
|
- const headerRow = headers
|
|
|
|
|
-
|
|
|
|
|
// 数据行
|
|
// 数据行
|
|
|
- const dataRow = [
|
|
|
|
|
- row.temperature,
|
|
|
|
|
- row.pulse,
|
|
|
|
|
- row.respiratoryRate,
|
|
|
|
|
- row.systolicPressure,
|
|
|
|
|
- row.diastolicPressure,
|
|
|
|
|
- row.bloodOxygenSaturation,
|
|
|
|
|
- row.bloodSugar,
|
|
|
|
|
- row.weight,
|
|
|
|
|
- row.stool,
|
|
|
|
|
- row.urinate,
|
|
|
|
|
- row.remark,
|
|
|
|
|
- row.measuringName,
|
|
|
|
|
- row.measuringTime,
|
|
|
|
|
- measuringDateText
|
|
|
|
|
- ]
|
|
|
|
|
|
|
+ const dataRows = records.map((row: any) => [
|
|
|
|
|
+ row.measuringDate ? formatTime(row.measuringDate, 'yyyy-MM-dd') : '',
|
|
|
|
|
+ row.measuringTime || '',
|
|
|
|
|
+ stripMetric(row.temperature),
|
|
|
|
|
+ stripMetric(row.pulse),
|
|
|
|
|
+ stripMetric(row.respiratoryRate),
|
|
|
|
|
+ [stripMetric(row.systolicPressure), stripMetric(row.diastolicPressure)].filter(Boolean).join('/'),
|
|
|
|
|
+ stripMetric(row.bloodOxygenSaturation)
|
|
|
|
|
+ ])
|
|
|
|
|
+
|
|
|
|
|
+ // 护士签名行
|
|
|
|
|
+ const nurseSignRow: string[] = new Array(colCount).fill('')
|
|
|
|
|
+ nurseSignRow[0] = '护士签名:'
|
|
|
|
|
|
|
|
- const ws = XLSX.utils.aoa_to_sheet([titleRow, infoRow, headerRow, dataRow])
|
|
|
|
|
|
|
+ const ws = XLSX.utils.aoa_to_sheet([titleRow, infoRow, headers, ...dataRows, nurseSignRow])
|
|
|
|
|
|
|
|
// 合并单元格
|
|
// 合并单元格
|
|
|
|
|
+ const nurseSignRowIndex = 3 + dataRows.length
|
|
|
ws['!merges'] = [
|
|
ws['!merges'] = [
|
|
|
{ s: { r: 0, c: 0 }, e: { r: 0, c: colCount - 1 } },
|
|
{ s: { r: 0, c: 0 }, e: { r: 0, c: colCount - 1 } },
|
|
|
- ...infoItems.map((item) => ({ s: { r: 1, c: item.start }, e: { r: 1, c: item.start + item.span - 1 } }))
|
|
|
|
|
|
|
+ ...infoItems.map((item) => ({ s: { r: 1, c: item.start }, e: { r: 1, c: item.start + item.span - 1 } })),
|
|
|
|
|
+ { s: { r: nurseSignRowIndex, c: 0 }, e: { r: nurseSignRowIndex, c: colCount - 1 } }
|
|
|
]
|
|
]
|
|
|
|
|
|
|
|
// 列宽
|
|
// 列宽
|
|
|
- ws['!cols'] = [
|
|
|
|
|
- { wch: 18 },
|
|
|
|
|
- { wch: 10 },
|
|
|
|
|
- { wch: 10 },
|
|
|
|
|
- { wch: 10 },
|
|
|
|
|
- { wch: 10 },
|
|
|
|
|
- { wch: 10 },
|
|
|
|
|
- { wch: 10 },
|
|
|
|
|
- { wch: 10 },
|
|
|
|
|
- { wch: 10 },
|
|
|
|
|
- { wch: 10 },
|
|
|
|
|
- { wch: 10 },
|
|
|
|
|
- { wch: 10 },
|
|
|
|
|
- { wch: 10 },
|
|
|
|
|
- { wch: 15 }
|
|
|
|
|
- ]
|
|
|
|
|
|
|
+ ws['!cols'] = [{ wch: 14 }, { wch: 12 }, { wch: 10 }, { wch: 10 }, { wch: 10 }, { wch: 12 }, { wch: 10 }]
|
|
|
|
|
|
|
|
// 行高
|
|
// 行高
|
|
|
- ws['!rows'] = [{ hpt: 38 }, { hpt: 28 }, { hpt: 32 }, { hpt: 28 }]
|
|
|
|
|
|
|
+ ws['!rows'] = [
|
|
|
|
|
+ { hpt: 38 },
|
|
|
|
|
+ { hpt: 28 },
|
|
|
|
|
+ { hpt: 32 },
|
|
|
|
|
+ ...dataRows.map(() => ({ hpt: 28 })),
|
|
|
|
|
+ { hpt: 34 }
|
|
|
|
|
+ ]
|
|
|
|
|
|
|
|
const range = XLSX.utils.decode_range(ws['!ref'] || '')
|
|
const range = XLSX.utils.decode_range(ws['!ref'] || '')
|
|
|
const headerFill = {
|
|
const headerFill = {
|
|
@@ -271,25 +265,32 @@ const handleRowExport = (row: any) => {
|
|
|
}
|
|
}
|
|
|
const cell = ws[cellRef]
|
|
const cell = ws[cellRef]
|
|
|
cell.s = cell.s || {}
|
|
cell.s = cell.s || {}
|
|
|
- cell.s.border = border
|
|
|
|
|
cell.s.alignment = { vertical: 'center', horizontal: 'center', wrapText: true }
|
|
cell.s.alignment = { vertical: 'center', horizontal: 'center', wrapText: true }
|
|
|
|
|
|
|
|
if (R === 0) {
|
|
if (R === 0) {
|
|
|
|
|
+ cell.s.border = border
|
|
|
cell.s.font = { bold: true, sz: 18, name: '宋体' }
|
|
cell.s.font = { bold: true, sz: 18, name: '宋体' }
|
|
|
} else if (R === 1) {
|
|
} else if (R === 1) {
|
|
|
|
|
+ cell.s.border = border
|
|
|
cell.s.alignment = { vertical: 'center', horizontal: 'left', wrapText: true }
|
|
cell.s.alignment = { vertical: 'center', horizontal: 'left', wrapText: true }
|
|
|
cell.s.font = { bold: true, sz: 11, name: '宋体' }
|
|
cell.s.font = { bold: true, sz: 11, name: '宋体' }
|
|
|
} else if (R === 2) {
|
|
} else if (R === 2) {
|
|
|
|
|
+ cell.s.border = border
|
|
|
cell.s.fill = headerFill
|
|
cell.s.fill = headerFill
|
|
|
cell.s.font = { bold: true, sz: 11, name: '宋体' }
|
|
cell.s.font = { bold: true, sz: 11, name: '宋体' }
|
|
|
|
|
+ } else if (R === nurseSignRowIndex) {
|
|
|
|
|
+ // 护士签名行:位于表格下方,无边框,左对齐,留空手签
|
|
|
|
|
+ cell.s.alignment = { vertical: 'center', horizontal: 'left' }
|
|
|
|
|
+ cell.s.font = { bold: true, sz: 11, name: '宋体' }
|
|
|
} else {
|
|
} else {
|
|
|
|
|
+ cell.s.border = border
|
|
|
cell.s.font = { sz: 11, name: '宋体' }
|
|
cell.s.font = { sz: 11, name: '宋体' }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
XLSX.utils.book_append_sheet(wb, ws, '生命体征')
|
|
XLSX.utils.book_append_sheet(wb, ws, '生命体征')
|
|
|
- XLSX.writeFile(wb, `${row.elderName || '生命体征'}_${measuringDateText || ''}.xlsx`)
|
|
|
|
|
|
|
+ XLSX.writeFile(wb, `生命体征_${queryParams.elderName}.xlsx`)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/** 初始化 **/
|
|
/** 初始化 **/
|