Преглед изворни кода

完善健康档案模态框内容

cc12458 пре 1 година
родитељ
комит
125749e443

+ 64 - 6
src/components/PatientHealthRecordPreview.vue

@@ -2,7 +2,7 @@
 import { h, ref } from 'vue';
 import { h, ref } from 'vue';
 
 
 import { VxeUI } from 'vxe-pc-ui';
 import { VxeUI } from 'vxe-pc-ui';
-import { EditOutlined } from '@ant-design/icons-vue';
+import { ArrowDownOutlined, ArrowUpOutlined, EditOutlined } from '@ant-design/icons-vue';
 
 
 import { useWatcher } from 'alova/client';
 import { useWatcher } from 'alova/client';
 import { getPatientTagsMethod, patientMethod } from '@/request/api/patient.api';
 import { getPatientTagsMethod, patientMethod } from '@/request/api/patient.api';
@@ -123,6 +123,50 @@ function openPatientTagEdit(event: MouseEvent) {
     },
     },
   });
   });
 }
 }
+
+function openPatientRecordsPreview() {
+  const component = defineAsyncComponent(() => import('@/components/RecordsPatientPreview.vue'));
+  const id = `modal:record-patient:preview`;
+  const onDestroy = () => { VxeUI.modal.close(id); };
+  onDestroy();
+  VxeUI.modal.open({
+    id, remember: true,
+    showMaximize: true, mask: false, lockView: false, padding: false,
+    resize: true, width: Math.floor(window.innerWidth * 0.5), height: Math.floor(window.innerHeight * 0.5),
+    escClosable: true, maskClosable: true,
+    title: `基础信息更新记录`,
+    slots: {
+      default() {
+        return h(component, {
+          patient: patient.value,
+          onDestroy,
+        });
+      },
+    },
+  });
+}
+
+function openIndicatorRecordsPreview() {
+  const component = defineAsyncComponent(() => import('@/components/RecordsIndicatorPreview.vue'));
+  const id = `modal:record-indicator:preview`;
+  const onDestroy = () => { VxeUI.modal.close(id); };
+  onDestroy();
+  VxeUI.modal.open({
+    id, remember: true,
+    showMaximize: true, mask: false, lockView: false, padding: false,
+    resize: true, width: Math.floor(window.innerWidth * 0.5), height: Math.floor(window.innerHeight * 0.5),
+    escClosable: true, maskClosable: true,
+    title: `指标信息更新记录`,
+    slots: {
+      default() {
+        return h(component, {
+          patient: patient.value,
+          onDestroy,
+        });
+      },
+    },
+  });
+}
 </script>
 </script>
 
 
 <template>
 <template>
@@ -131,7 +175,7 @@ function openPatientTagEdit(event: MouseEvent) {
       <section class="flex-auto">
       <section class="flex-auto">
         <header class="flex items-center">
         <header class="flex items-center">
           <div class="title">基本信息</div>
           <div class="title">基本信息</div>
-          <a-button type="link">更新记录</a-button>
+          <a-button type="link" @click="openPatientRecordsPreview">更新记录</a-button>
         </header>
         </header>
         <main>
         <main>
           <div class="row">
           <div class="row">
@@ -232,14 +276,18 @@ function openPatientTagEdit(event: MouseEvent) {
         <div class="row" v-if="indicator.length">
         <div class="row" v-if="indicator.length">
           <header>
           <header>
             <label>生理指标</label>
             <label>生理指标</label>
+            <a-button type="link" @click="openIndicatorRecordsPreview">更新记录</a-button>
           </header>
           </header>
           <main>
           <main>
             <div class="flex flex-wrap">
             <div class="flex flex-wrap">
               <div class="text-center w-260px row" v-for="item in indicator" :key="item.id">
               <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="flex justify-center">
+                  <span><label>{{ item.name }}</label>{{ item.value }}{{ item.unit }}</span>
+                  <div class="inline-block ml-2 size-24px">
+                    <a-button v-if="item.trend > 0" :icon="h(ArrowUpOutlined)" shape="circle" size="small" class="trend-up" />
+                    <a-button v-else-if="item.trend < 0" :icon="h(ArrowDownOutlined)" shape="circle" size="small" class="trend-down" />
+                  </div>
+                </div>
                 <div class="text-center mt-1" style="font-size: 14px; color: rgba(0, 0, 0, 0.45)">{{ item.date }}</div>
                 <div class="text-center mt-1" style="font-size: 14px; color: rgba(0, 0, 0, 0.45)">{{ item.date }}</div>
               </div>
               </div>
             </div>
             </div>
@@ -346,4 +394,14 @@ section {
     }
     }
   }
   }
 }
 }
+
+.trend-up {
+  color: #ff4d4f;
+  border-color: #ff4d4f;
+}
+
+.trend-down {
+  color: #87d068;
+  border-color: #87d068;
+}
 </style>
 </style>

+ 2 - 2
src/components/RecordsPatientPreview.vue

@@ -5,7 +5,7 @@ import { patientDictionariesMethod }                                  from '@/re
 import { patientUpdateRecordsMethod }                                 from '@/request/api/report.api';
 import { patientUpdateRecordsMethod }                                 from '@/request/api/report.api';
 import { usePagination, useRequest }                                  from 'alova/client';
 import { usePagination, useRequest }                                  from 'alova/client';
 
 
-import { type VxeColumnPropTypes, type VxeTableEvents, type VxeTableInstance } from 'vxe-pc-ui';
+import type { VxeColumnPropTypes, VxeTableEvents, VxeTableInstance } from 'vxe-table';
 
 
 
 
 const props = defineProps<{
 const props = defineProps<{
@@ -59,7 +59,7 @@ const scrollEvent: VxeTableEvents.Scroll<AnalysisRecordModel> = (params) => {
 <template>
 <template>
   <vxe-table
   <vxe-table
     ref="tableRef" :data="records" :loading
     ref="tableRef" :data="records" :loading
-    max-height="100%" auto-resize align="center"
+    height="100%" auto-resize align="center"
     :column-config="{resizable:true,isCurrent: true}"
     :column-config="{resizable:true,isCurrent: true}"
     :row-config="{isCurrent: true, isHover: true}"
     :row-config="{isCurrent: true, isHover: true}"
     @cell-click="cellClickEvent"
     @cell-click="cellClickEvent"

+ 11 - 5
src/components/ReportPreview.vue

@@ -10,15 +10,15 @@ import { useWatcher }
 
 
 
 
 const props = defineProps<{
 const props = defineProps<{
-  patient: Partial<PatientModel>;
-  report: Partial<ReportModel>;
+  patient?: Partial<PatientModel>;
+  report?: Partial<ReportModel>;
   scheme?: Partial<ReportSchemeModel>;
   scheme?: Partial<ReportSchemeModel>;
 }>();
 }>();
 const emits = defineEmits<{
 const emits = defineEmits<{
   destroy: [];
   destroy: [];
 }>();
 }>();
 
 
-const patientId = computed(() => props.patient.id);
+const patientId = defineModel<string>('patientId', { default: void 0 });;
 const reportId = defineModel<string>('reportId', { default: void 0 });
 const reportId = defineModel<string>('reportId', { default: void 0 });
 const showType = defineModel<'analysis' | 'scheme'>('type', { default: 'analysis' });
 const showType = defineModel<'analysis' | 'scheme'>('type', { default: 'analysis' });
 
 
@@ -29,7 +29,10 @@ const { data: report, loading: reportLoading } = useWatcher(
     initialData: { ...props.report }, immediate: true,
     initialData: { ...props.report }, immediate: true,
     middleware: (_, next) => { if ( reportId.value && showType.value === 'analysis' ) next(); },
     middleware: (_, next) => { if ( reportId.value && showType.value === 'analysis' ) next(); },
   },
   },
-).onSuccess(() => scrollIntoView());
+).onSuccess(({data}) => {
+  scrollIntoView();
+  patientId.value ??= data.patientId;
+});
 const { data: indicator, loading: indicatorLoading } = useWatcher(
 const { data: indicator, loading: indicatorLoading } = useWatcher(
   () => indicatorByReportIdMethod(reportId.value!),
   () => indicatorByReportIdMethod(reportId.value!),
   [ reportId, showType ],
   [ reportId, showType ],
@@ -57,7 +60,10 @@ const { data: scheme, loading: schemeLoading } = useWatcher(
   },
   },
 ).onSuccess(() => scrollIntoView());
 ).onSuccess(() => scrollIntoView());
 
 
-onBeforeMount(() => { reportId.value ??= props.report.id!; });
+onBeforeMount(() => {
+  reportId.value ??= props.report?.id!;
+  patientId.value ??= props.patient?.id!;
+});
 
 
 const schemeKeys = ref([]);
 const schemeKeys = ref([]);
 const collapsed = ref(false);
 const collapsed = ref(false);

+ 25 - 2
src/widgets/PatientHealthRecordsWidget.vue

@@ -7,6 +7,7 @@ import { usePagination } from 'alova/client';
 import { getPatientHealthRecordsMethod } from '@/request/api/report.api';
 import { getPatientHealthRecordsMethod } from '@/request/api/report.api';
 import type { VxeGridInstance, VxeGridListeners, VxeGridProps } from 'vxe-table';
 import type { VxeGridInstance, VxeGridListeners, VxeGridProps } from 'vxe-table';
 import type { HealthReportSymptomItemVo } from '@/model/health-report.model';
 import type { HealthReportSymptomItemVo } from '@/model/health-report.model';
+import { VxeUI } from 'vxe-pc-ui';
 
 
 const props = defineProps<{ patient: { id: string } }>();
 const props = defineProps<{ patient: { id: string } }>();
 
 
@@ -31,7 +32,7 @@ const grid = ref<VxeGridInstance>();
 const { loading, page, isLastPage } = usePagination((page, size) => getPatientHealthRecordsMethod(page, size, { patientId: props.patient.id }), {
 const { loading, page, isLastPage } = usePagination((page, size) => getPatientHealthRecordsMethod(page, size, { patientId: props.patient.id }), {
   initialData: { total: 0, data: [] },
   initialData: { total: 0, data: [] },
   initialPage: 0,
   initialPage: 0,
-  initialPageSize: 10,
+  initialPageSize: 100,
   append: true,
   append: true,
   watchingStates: [() => props.patient.id],
   watchingStates: [() => props.patient.id],
 }).onSuccess(({ data: { data } }) => {
 }).onSuccess(({ data: { data } }) => {
@@ -110,13 +111,35 @@ const gridEvents: VxeGridListeners = {
     if (isBottom && direction === 'bottom' && !isLastPage.value) page.value++;
     if (isBottom && direction === 'bottom' && !isLastPage.value) page.value++;
   },
   },
 };
 };
+
+function open(row: Model) {
+  const component = defineAsyncComponent(() => import('@/components/ReportPreview.vue'));
+  const id = `drawer:report:preview`;
+  const onDestroy = () => { VxeUI.drawer.close(id); };
+  onDestroy();
+  VxeUI.drawer.open({
+    id,
+    mask: true, lockView: false, padding: false,
+    width: window.innerWidth - 256,
+    escClosable: true, maskClosable: true,
+    title: `健康分析报告`,
+    slots: {
+      default() {
+        return h(component, {
+          reportId: row.id.toString(),
+          onDestroy,
+        });
+      },
+    },
+  });
+}
 </script>
 </script>
 
 
 <template>
 <template>
   <vxe-grid ref="grid" v-bind="gridOptions" v-on="gridEvents">
   <vxe-grid ref="grid" v-bind="gridOptions" v-on="gridEvents">
     <template #records="{ row, column }">
     <template #records="{ row, column }">
       <div style="font-size: 16px">{{ row[column.field] }}</div>
       <div style="font-size: 16px">{{ row[column.field] }}</div>
-      <a-button class="mt-2" :icon="h(FileTextOutlined)" type="primary" size="small" :disabled="!row.id">健康分析报告</a-button>
+      <a-button class="mt-2" :icon="h(FileTextOutlined)" type="primary" size="small" :disabled="!row.id" @click="open(row)">健康分析报告</a-button>
     </template>
     </template>
     <template #symptom="{ row, column }">
     <template #symptom="{ row, column }">
       <div style="transform: translateX(12px)">
       <div style="transform: translateX(12px)">

+ 19 - 3
src/widgets/PatientPhysicalSignRecordsWidget.vue

@@ -1,6 +1,6 @@
 <script setup lang="ts">
 <script setup lang="ts">
-import { CaretRightOutlined } from '@ant-design/icons-vue';
-import { ref } from 'vue';
+import { ArrowDownOutlined, ArrowUpOutlined, CaretRightOutlined } from '@ant-design/icons-vue';
+import { h, ref } from 'vue';
 import { useRequest } from 'alova/client';
 import { useRequest } from 'alova/client';
 import { getPatientHealthIndicatorsMethod } from '@/request/api/report.api';
 import { getPatientHealthIndicatorsMethod } from '@/request/api/report.api';
 import type { HealthIndicatorItemVO, HealthIndicatorVO } from '@/model/health-report.model';
 import type { HealthIndicatorItemVO, HealthIndicatorVO } from '@/model/health-report.model';
@@ -44,7 +44,13 @@ function conversionGrouping(data: HealthIndicatorVO[]): HealthIndicatorVO[] {
       <a-collapse-panel v-for="indicator in indicators" :key="indicator.name" :header="indicator.name">
       <a-collapse-panel v-for="indicator in indicators" :key="indicator.name" :header="indicator.name">
         <div class="flex flex-wrap">
         <div class="flex flex-wrap">
           <div class="text-center w-260px row" v-for="item in indicator.items" :key="item.name">
           <div class="text-center w-260px row" v-for="item in indicator.items" :key="item.name">
-            <span><label>{{ item.name }}</label>{{item.value}}{{item.unit}}</span>
+            <div class="flex justify-center">
+              <span><label>{{ item.name }}</label>{{ item.value }}{{ item.unit }}</span>
+              <div class="inline-block ml-2 size-24px">
+                <a-button v-if="item.trend > 0" :icon="h(ArrowUpOutlined)" shape="circle" size="small" class="trend-up" />
+                <a-button v-else-if="item.trend < 0" :icon="h(ArrowDownOutlined)" shape="circle" size="small" class="trend-down" />
+              </div>
+            </div>
           </div>
           </div>
         </div>
         </div>
       </a-collapse-panel>
       </a-collapse-panel>
@@ -91,4 +97,14 @@ function conversionGrouping(data: HealthIndicatorVO[]): HealthIndicatorVO[] {
     }
     }
   }
   }
 }
 }
+
+.trend-up {
+  color: #ff4d4f;
+  border-color: #ff4d4f;
+}
+
+.trend-down {
+  color: #87d068;
+  border-color: #87d068;
+}
 </style>
 </style>