|
|
@@ -1,10 +1,16 @@
|
|
|
<script setup lang="ts">
|
|
|
+import { h, ref } from 'vue';
|
|
|
+
|
|
|
import { VxeUI } from 'vxe-pc-ui';
|
|
|
import { EditOutlined } from '@ant-design/icons-vue';
|
|
|
|
|
|
import { useWatcher } from 'alova/client';
|
|
|
-import type { PatientModel, PatientTagVO, ReportModel } from '@/model';
|
|
|
import { getPatientTagsMethod, patientMethod } from '@/request/api/patient.api';
|
|
|
+import { getPatientDiagnosisReportMethod, getPatientHealthIndicatorMethod, getPatientHealthRecordMethod } from '@/request/api/report.api';
|
|
|
+import type { PatientModel, PatientTagVO, ReportModel } from '@/model';
|
|
|
+
|
|
|
+import UseDict from '@/core/dictionary/component';
|
|
|
+import HealthReportAnalysisWidget from '@/widgets/HealthReportAnalysisWidget.vue';
|
|
|
|
|
|
const props = defineProps<{
|
|
|
patient: Partial<PatientModel>;
|
|
|
@@ -16,7 +22,8 @@ const emits = defineEmits<{
|
|
|
destroy: [];
|
|
|
}>();
|
|
|
|
|
|
-const { data: patient, loading: loadPatientPending } = useWatcher(() => patientMethod(props.patient?.id!), [() => props.patient.id], {
|
|
|
+// 患者基本信息
|
|
|
+const { data: patient } = useWatcher(() => patientMethod(props.patient?.id!), [() => props.patient.id], {
|
|
|
initialData: { ...props.patient },
|
|
|
immediate: true,
|
|
|
middleware: (_, next) => {
|
|
|
@@ -32,6 +39,55 @@ const { data: patientTags, loading: loadPatientTagsPending } = useWatcher(() =>
|
|
|
},
|
|
|
});
|
|
|
|
|
|
+// 患者最后一次就诊记录
|
|
|
+const { data: diagnosisRecord } = useWatcher(() => getPatientDiagnosisReportMethod(0, props.patient?.id!), [() => props.patient.id], {
|
|
|
+ initialData: { disease: {}, symptom: {} },
|
|
|
+ immediate: true,
|
|
|
+ middleware: (_, next) => {
|
|
|
+ if (props.patient.id) next();
|
|
|
+ },
|
|
|
+});
|
|
|
+
|
|
|
+// 患者最后一次健康分析报告
|
|
|
+const { data: healthRecord } = useWatcher(() => getPatientHealthRecordMethod(props.report?.id!), [() => props.report.id], {
|
|
|
+ initialData: {},
|
|
|
+ immediate: true,
|
|
|
+ middleware: (_, next) => {
|
|
|
+ if (props.report.id) next();
|
|
|
+ },
|
|
|
+});
|
|
|
+
|
|
|
+const { data: indicator } = useWatcher(() => getPatientHealthIndicatorMethod(props.patient?.id!), [() => props.patient.id], {
|
|
|
+ initialData: [],
|
|
|
+ immediate: true,
|
|
|
+ middleware: (_, next) => {
|
|
|
+ if (props.patient.id) next();
|
|
|
+ },
|
|
|
+});
|
|
|
+
|
|
|
+const panels = shallowReactive([
|
|
|
+ {
|
|
|
+ id: 'patient-diagnosis-records',
|
|
|
+ title: '就诊记录',
|
|
|
+ component: defineAsyncComponent(() => import('@/widgets/PatientDiagnosisRecordsWidget.vue')),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'patient-health-records',
|
|
|
+ title: '健康分析记录',
|
|
|
+ component: defineAsyncComponent(() => import('@/widgets/PatientHealthRecordsWidget.vue')),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'patient-physicalSign-records',
|
|
|
+ title: '生理指标',
|
|
|
+ component: defineAsyncComponent(() => import('@/widgets/PatientPhysicalSignRecordsWidget.vue')),
|
|
|
+ },
|
|
|
+]);
|
|
|
+
|
|
|
+const activePanel = ref(panels[0].id);
|
|
|
+const activePanelChange = (event: Event) => {
|
|
|
+ (event.target as HTMLElement)?.scrollIntoView({ block: 'start', behavior: 'smooth' });
|
|
|
+};
|
|
|
+
|
|
|
function openPatientTagEdit(event: MouseEvent) {
|
|
|
const width = 500;
|
|
|
const offset = 32;
|
|
|
@@ -72,6 +128,49 @@ function openPatientTagEdit(event: MouseEvent) {
|
|
|
<template>
|
|
|
<div class="p-6">
|
|
|
<div class="flex">
|
|
|
+ <section class="flex-auto">
|
|
|
+ <header class="flex items-center">
|
|
|
+ <div class="title">基本信息</div>
|
|
|
+ <a-button type="link">更新记录</a-button>
|
|
|
+ </header>
|
|
|
+ <main>
|
|
|
+ <div class="row">
|
|
|
+ <a-space class="separate" :size="0">
|
|
|
+ <span>{{ patient.name }}</span>
|
|
|
+ <UseDict v-slot="{ value }" sign="sys_user_sex" :raw="patient.gender">
|
|
|
+ <span v-if="value">{{ value }}</span>
|
|
|
+ </UseDict>
|
|
|
+ <span v-if="patient.age">{{ patient.age }} 岁</span>
|
|
|
+ <UseDict v-slot="{ value }" sign="women_special_period" :raw="patient.womenSpecialPeriod">
|
|
|
+ <span v-if="value && value !== '无'">{{ value }}</span>
|
|
|
+ </UseDict>
|
|
|
+ <UseDict v-slot="{ value }" sign="job" :raw="patient.job">
|
|
|
+ <span v-if="value && value !== '无'">{{ value }}</span>
|
|
|
+ </UseDict>
|
|
|
+ <span v-if="patient.phone"><label>手机号</label> {{ patient.phone }}</span>
|
|
|
+ <span v-if="patient.cardno"><label>身份证号</label> {{ patient.cardno }}</span>
|
|
|
+ </a-space>
|
|
|
+ </div>
|
|
|
+ <div class="row">
|
|
|
+ <a-space :size="40">
|
|
|
+ <span v-if="patient.height"><label>身高</label> {{ patient.height }} cm</span>
|
|
|
+ <span v-if="patient.weight"><label>体重</label> {{ patient.weight }} kg</span>
|
|
|
+ <UseDict v-slot="{ value }" sign="sys_yes_no" :raw="patient.drinkState">
|
|
|
+ <span v-if="value"><label>饮酒</label> {{ value }}</span>
|
|
|
+ </UseDict>
|
|
|
+ <UseDict v-slot="{ value }" sign="sys_yes_no" :raw="patient.smokeState">
|
|
|
+ <span v-if="value"><label>抽烟</label> {{ value }}</span>
|
|
|
+ </UseDict>
|
|
|
+ <UseDict v-slot="{ value }" sign="food_allergy" :raw="patient.foodAllergy2" :multiple="true" :separator="[',', '、']">
|
|
|
+ <span v-if="value"><label>食物过敏</label> {{ value }}</span>
|
|
|
+ </UseDict>
|
|
|
+ <UseDict v-slot="{ value }" sign="hobby_flavor" :raw="patient.hobbyFlavor" :multiple="true" :separator="[',', '、']">
|
|
|
+ <span v-if="value"><label>喜好口味</label> {{ value }}</span>
|
|
|
+ </UseDict>
|
|
|
+ </a-space>
|
|
|
+ </div>
|
|
|
+ </main>
|
|
|
+ </section>
|
|
|
<section class="flex-none min-w-100px max-w-400px">
|
|
|
<label>标签:</label>
|
|
|
<a-spin v-if="loadPatientTagsPending"></a-spin>
|
|
|
@@ -85,6 +184,81 @@ function openPatientTagEdit(event: MouseEvent) {
|
|
|
</template>
|
|
|
</section>
|
|
|
</div>
|
|
|
+ <section class="mt-4">
|
|
|
+ <header class="flex items-center">
|
|
|
+ <div class="title">健康状况</div>
|
|
|
+ </header>
|
|
|
+ <main>
|
|
|
+ <div class="row" v-if="diagnosisRecord">
|
|
|
+ <header>
|
|
|
+ <label>诊断</label>
|
|
|
+ <span>{{ diagnosisRecord.disease?.name }} - {{ diagnosisRecord.symptom?.name }}</span>
|
|
|
+ <span v-if="diagnosisRecord.date">({{ diagnosisRecord.date }})</span>
|
|
|
+ </header>
|
|
|
+ </div>
|
|
|
+ <div class="row">
|
|
|
+ <header>
|
|
|
+ <label>健康状态</label>
|
|
|
+ <span>{{ healthRecord.result?.status }}</span>
|
|
|
+ <span v-if="healthRecord.date">({{ healthRecord.date }})</span>
|
|
|
+ </header>
|
|
|
+ <main>
|
|
|
+ <div class="row">
|
|
|
+ <a-space :size="24">
|
|
|
+ <a-space direction="vertical" :size="12">
|
|
|
+ <span><label>程度</label>{{ healthRecord.result?.level }}</span>
|
|
|
+ <span><label>表现</label>{{ healthRecord.result?.description }}</span>
|
|
|
+ <span><label>症素</label>{{ healthRecord.syndromeElement?.label }}</span>
|
|
|
+ </a-space>
|
|
|
+ <a-space direction="vertical" :size="12">
|
|
|
+ <span><label>类型</label>{{ healthRecord.result?.category }}</span>
|
|
|
+ <span><label>体质</label>{{ healthRecord.physique?.label }}</span>
|
|
|
+ <span><label>证型</label>{{ healthRecord.syndrome?.label }}</span>
|
|
|
+ </a-space>
|
|
|
+ </a-space>
|
|
|
+ </div>
|
|
|
+ </main>
|
|
|
+ </div>
|
|
|
+ <div class="row">
|
|
|
+ <header>
|
|
|
+ <label>症状</label>
|
|
|
+ <span>{{ healthRecord.symptom?.value || ' - ' }}</span>
|
|
|
+ <span v-if="healthRecord.symptom?.duration">,{{ healthRecord.symptom?.duration }}</span>
|
|
|
+ <span v-if="healthRecord.symptom?.influence">,{{ healthRecord.symptom?.influence }}</span>
|
|
|
+ </header>
|
|
|
+ </div>
|
|
|
+ <HealthReportAnalysisWidget class="row" category="tongue" :analysis="healthRecord.analysis"></HealthReportAnalysisWidget>
|
|
|
+ <HealthReportAnalysisWidget class="row" category="face" :analysis="healthRecord.analysis"></HealthReportAnalysisWidget>
|
|
|
+ <div class="row" v-if="indicator.length">
|
|
|
+ <header>
|
|
|
+ <label>生理指标</label>
|
|
|
+ </header>
|
|
|
+ <main>
|
|
|
+ <div class="flex flex-wrap">
|
|
|
+ <div class="text-center w-260px row" v-for="item in indicator" :key="item.id">
|
|
|
+ <span
|
|
|
+ ><label>{{ item.name }}</label
|
|
|
+ >{{ item.value }}{{ item.unit }}</span
|
|
|
+ >
|
|
|
+ <div class="text-center mt-1" style="font-size: 14px; color: rgba(0, 0, 0, 0.45)">{{ item.date }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </main>
|
|
|
+ </div>
|
|
|
+ </main>
|
|
|
+ </section>
|
|
|
+ <a-tabs class="panel-wrapper" v-model:activeKey="activePanel">
|
|
|
+ <a-tab-pane v-for="panel in panels" :key="panel.id">
|
|
|
+ <component :is="panel.component" :patient="patient"></component>
|
|
|
+ </a-tab-pane>
|
|
|
+ <template #renderTabBar>
|
|
|
+ <a-radio-group v-model:value="activePanel" @change="activePanelChange($event.nativeEvent)">
|
|
|
+ <a-radio-button v-for="panel in panels" :key="panel.id" :value="panel.id" :disabled="panel.disabled">
|
|
|
+ {{ panel.title }}
|
|
|
+ </a-radio-button>
|
|
|
+ </a-radio-group>
|
|
|
+ </template>
|
|
|
+ </a-tabs>
|
|
|
</div>
|
|
|
</template>
|
|
|
|