|
@@ -1,7 +1,7 @@
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
import { useRoute } from 'vue-router';
|
|
import { useRoute } from 'vue-router';
|
|
|
import { ref, computed, nextTick, h, watch, onMounted } from 'vue';
|
|
import { ref, computed, nextTick, h, watch, onMounted } from 'vue';
|
|
|
-import { MinusCircleOutlined, EyeOutlined } from '@ant-design/icons-vue';
|
|
|
|
|
|
|
+import { MinusCircleOutlined, EyeOutlined, EditOutlined } from '@ant-design/icons-vue';
|
|
|
import { notification } from 'ant-design-vue';
|
|
import { notification } from 'ant-design-vue';
|
|
|
import { message } from 'ant-design-vue';
|
|
import { message } from 'ant-design-vue';
|
|
|
import type { OpenConditioningSchemeModel, SystemCwModel } from '@/model/care.model';
|
|
import type { OpenConditioningSchemeModel, SystemCwModel } from '@/model/care.model';
|
|
@@ -20,12 +20,16 @@ import {
|
|
|
getAreaMethod,
|
|
getAreaMethod,
|
|
|
getAvailableCwMethod,
|
|
getAvailableCwMethod,
|
|
|
} from '@/request/api/care.api';
|
|
} from '@/request/api/care.api';
|
|
|
-import { patientMethod, patientTags } from '@/request/api/patient.api';
|
|
|
|
|
|
|
+import { patientMethod, getPatientTagsMethod } from '@/request/api/patient.api';
|
|
|
import { useRequest, usePagination } from 'alova/client';
|
|
import { useRequest, usePagination } from 'alova/client';
|
|
|
import ServicePackageDetail from '@/service/ServicePackageDetail.vue';
|
|
import ServicePackageDetail from '@/service/ServicePackageDetail.vue';
|
|
|
import { VxeUI } from 'vxe-pc-ui';
|
|
import { VxeUI } from 'vxe-pc-ui';
|
|
|
-import type { PatientTagModel } from '@/model/patient.model';
|
|
|
|
|
|
|
+import type { HealthReportVO } from '@/model/health-report.model';
|
|
|
|
|
+import type { PatientTagVO } from '@/model/patient.model';
|
|
|
import dayjs from 'dayjs';
|
|
import dayjs from 'dayjs';
|
|
|
|
|
+
|
|
|
|
|
+import { getPatientHealthRecordsMethod } from '@/request/api/report.api';
|
|
|
|
|
+
|
|
|
type FollowModel = Partial<OpenConditioningSchemeModel>;
|
|
type FollowModel = Partial<OpenConditioningSchemeModel>;
|
|
|
// const props = defineProps<{ data: FollowModel }>();
|
|
// const props = defineProps<{ data: FollowModel }>();
|
|
|
|
|
|
|
@@ -98,6 +102,7 @@ export interface PatientModel {
|
|
|
patientAge: number;
|
|
patientAge: number;
|
|
|
diagnosis: string;
|
|
diagnosis: string;
|
|
|
symptom: string;
|
|
symptom: string;
|
|
|
|
|
+ healthAnalysisReportId: string;
|
|
|
healthAnalysisReport: {
|
|
healthAnalysisReport: {
|
|
|
willillStateName: string;
|
|
willillStateName: string;
|
|
|
willillDegreeName: string;
|
|
willillDegreeName: string;
|
|
@@ -115,7 +120,7 @@ interface CpDetail {
|
|
|
cardno?: string;
|
|
cardno?: string;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-let cpDetail = ref<CpDetail>({});
|
|
|
|
|
|
|
+let cpDetail = ref<CpDetail & Partial<PatientModel>>({});
|
|
|
async function getCpDetail(id: string) {
|
|
async function getCpDetail(id: string) {
|
|
|
await patientMethod(id).then((res2) => {
|
|
await patientMethod(id).then((res2) => {
|
|
|
cpDetail.value = res2;
|
|
cpDetail.value = res2;
|
|
@@ -127,6 +132,16 @@ interface PatientRecord {
|
|
|
estimatedEndDate: string;
|
|
estimatedEndDate: string;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// 患者健康分析报告记录
|
|
|
|
|
+const patientHealthRecords = ref<HealthReportVO[]>([]);
|
|
|
|
|
+async function loadHealthRecords(patientId?: string) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const { data } = await getPatientHealthRecordsMethod(1, 100, { patientId: patientId ?? currentPatient.value?.patientId! });
|
|
|
|
|
+ patientHealthRecords.value = data
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ patientHealthRecords.value = []
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
const patientRecord = ref<PatientRecord[]>([]);
|
|
const patientRecord = ref<PatientRecord[]>([]);
|
|
|
// 获取患者调养记录
|
|
// 获取患者调养记录
|
|
|
function getPatientRecord(id: any) {
|
|
function getPatientRecord(id: any) {
|
|
@@ -154,11 +169,12 @@ async function getCpRecordDetail(id: string) {
|
|
|
form.healthAnalysisReport = res.healthAnalysisReport;
|
|
form.healthAnalysisReport = res.healthAnalysisReport;
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
-async function getPatientList(id: string) {
|
|
|
|
|
|
|
+function getPatientList(id: string) {
|
|
|
// console.log(id, '切换');
|
|
// console.log(id, '切换');
|
|
|
if (id) {
|
|
if (id) {
|
|
|
getCpDetail(id);
|
|
getCpDetail(id);
|
|
|
loadTags(id);
|
|
loadTags(id);
|
|
|
|
|
+ loadHealthRecords(id);
|
|
|
getPatientRecord(id);
|
|
getPatientRecord(id);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -191,10 +207,10 @@ onMounted(async () => {
|
|
|
|
|
|
|
|
});
|
|
});
|
|
|
// 患者标签
|
|
// 患者标签
|
|
|
-const tags = ref<PatientTagModel>({ id: '', tags: [] });
|
|
|
|
|
|
|
+const patientTags = ref<PatientTagVO[]>([]);
|
|
|
function loadTags(patientId: string) {
|
|
function loadTags(patientId: string) {
|
|
|
- patientTags(patientId).then((res) => {
|
|
|
|
|
- tags.value = res;
|
|
|
|
|
|
|
+ getPatientTagsMethod(patientId).then((res) => {
|
|
|
|
|
+ patientTags.value = res;
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -802,6 +818,103 @@ watch(showProjectPopover, (val) => {
|
|
|
projectSearch.value = '';
|
|
projectSearch.value = '';
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
|
|
+
|
|
|
|
|
+function openPatientTagEdit(event: MouseEvent) {
|
|
|
|
|
+ const width = 500;
|
|
|
|
|
+ const offset = 32;
|
|
|
|
|
+ const component = defineAsyncComponent(() => import('@/components/PatientTagEdit.vue'));
|
|
|
|
|
+ const id = `PatientTagEdit`;
|
|
|
|
|
+ VxeUI.modal.open({
|
|
|
|
|
+ id,
|
|
|
|
|
+ title: '标签',
|
|
|
|
|
+ type: 'modal',
|
|
|
|
|
+ position: {
|
|
|
|
|
+ top: event.pageY + offset,
|
|
|
|
|
+ left: event.pageX - width,
|
|
|
|
|
+ },
|
|
|
|
|
+ escClosable: true,
|
|
|
|
|
+ resize: true,
|
|
|
|
|
+ width,
|
|
|
|
|
+ minWidth: width,
|
|
|
|
|
+ mask: false,
|
|
|
|
|
+ slots: {
|
|
|
|
|
+ default() {
|
|
|
|
|
+ return h(component, {
|
|
|
|
|
+ id: currentPatient.value?.patientId!,
|
|
|
|
|
+ tags: patientTags.value,
|
|
|
|
|
+ onDestroy(values?: PatientTagVO[]) {
|
|
|
|
|
+ if (values) { patientTags.value = values; }
|
|
|
|
|
+ VxeUI.modal.close(id);
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function openHistoryPreviewHandle() {
|
|
|
|
|
+ const data = currentPatient.value
|
|
|
|
|
+ const patient = { id: data?.patientId }
|
|
|
|
|
+ const report = { id: data?.healthAnalysisReportId }
|
|
|
|
|
+
|
|
|
|
|
+ const component = defineAsyncComponent(() => import('@/components/PatientHealthRecordPreview.vue'));
|
|
|
|
|
+ const id = `drawer:report-history:preview`;
|
|
|
|
|
+ const onDestroy = () => {
|
|
|
|
|
+ VxeUI.drawer.close(id);
|
|
|
|
|
+ };
|
|
|
|
|
+ onDestroy();
|
|
|
|
|
+ VxeUI.drawer.open({
|
|
|
|
|
+ id,
|
|
|
|
|
+ title: `健康档案`,
|
|
|
|
|
+ maskClosable: true,
|
|
|
|
|
+ escClosable: true,
|
|
|
|
|
+ padding: false,
|
|
|
|
|
+ width: window.innerWidth - 256,
|
|
|
|
|
+ slots: {
|
|
|
|
|
+ default() {
|
|
|
|
|
+ return h(component, {
|
|
|
|
|
+ patient,
|
|
|
|
|
+ report,
|
|
|
|
|
+ onDestroy,
|
|
|
|
|
+ onRefresh() {
|
|
|
|
|
+
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ onHide() {
|
|
|
|
|
+ VxeUI.modal.close();
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function openPatientHealthRecord(row: { id: string }, showType: 'analysis' | 'scheme' = 'analysis') {
|
|
|
|
|
+ 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: {analysis: `健康分析报告`, scheme: `调理方案`}[showType],
|
|
|
|
|
+ slots: {
|
|
|
|
|
+ default() {
|
|
|
|
|
+ return h(component, {
|
|
|
|
|
+ reportId: row.id.toString(),
|
|
|
|
|
+ type: showType,
|
|
|
|
|
+ onDestroy,
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
|
<template>
|
|
@@ -1081,30 +1194,43 @@ watch(showProjectPopover, (val) => {
|
|
|
<a-result class="area" v-else style="background-color: #fff" status="warning" title="暂无数据" />
|
|
<a-result class="area" v-else style="background-color: #fff" status="warning" title="暂无数据" />
|
|
|
</div>
|
|
</div>
|
|
|
<!-- 右侧调养记录 -->
|
|
<!-- 右侧调养记录 -->
|
|
|
- <div class="right-panel">
|
|
|
|
|
- <PatientTagWidget style="min-height: 112px; flex: none" :dataset="tags" editable @refresh="loadTags(currentPatient?.patientId)" :data="currentPatient" />
|
|
|
|
|
- <!-- <a-button
|
|
|
|
|
- type="primary"
|
|
|
|
|
- size="small"
|
|
|
|
|
- :disabled="!reportId"
|
|
|
|
|
- :loading="reportLoading || historyReportPreviewOpening"
|
|
|
|
|
- @click="
|
|
|
|
|
- historyReportPreviewOpening = true;
|
|
|
|
|
- openHistoryPreviewHandle();
|
|
|
|
|
- "
|
|
|
|
|
- >
|
|
|
|
|
- 健康档案
|
|
|
|
|
- </a-button> -->
|
|
|
|
|
|
|
+ <div class="right-panel flex flex-col overflow-hidden">
|
|
|
|
|
+ <section style="flex: 0 0 auto; max-height: 270px; overflow-y: auto;">
|
|
|
|
|
+ <div style="margin-top: -6px; padding-right: 8px;">
|
|
|
|
|
+ <label>标签:</label>
|
|
|
|
|
+ <a-tag v-for="tag in patientTags" :key="tag.id" :color="tag.color">{{ tag.name }}</a-tag>
|
|
|
|
|
+ <a-button type="link" @click="openPatientTagEdit($event)">
|
|
|
|
|
+ <template #icon>
|
|
|
|
|
+ <EditOutlined />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </a-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </section>
|
|
|
|
|
+ <section style="margin: 8px;">
|
|
|
|
|
+ <a-button type="primary" block @click="openHistoryPreviewHandle()">健康档案</a-button>
|
|
|
|
|
+ </section>
|
|
|
|
|
+ <div class="record-title">报告记录</div>
|
|
|
|
|
+ <section class="overflow-auto" style="flex: 4 4 auto; min-height: 240px;">
|
|
|
|
|
+ <div class="record-list">
|
|
|
|
|
+ <div class="record-item flex justify-between" v-for="item in patientHealthRecords" :key="item.id" @click="openPatientHealthRecord(item, 'analysis')">
|
|
|
|
|
+ {{ item.date }}
|
|
|
|
|
+ <a @click.stop="openPatientHealthRecord(item, 'scheme')">方案</a>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div v-if="!patientRecord.length" style="padding-bottom: 8px; text-align: center; margin-top: 40px">暂无数据</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </section>
|
|
|
<div class="record-title">调养记录</div>
|
|
<div class="record-title">调养记录</div>
|
|
|
- <div class="record-list" v-if="patientRecord.length > 0">
|
|
|
|
|
- <div class="record-item" v-for="item in patientRecord" :key="item.id" @click="openRecord(item)">{{ item.estimatedStartDate }}~{{ item.estimatedEndDate }}</div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div v-else style="padding-bottom: 8px; text-align: center; margin-top: 40px">暂无数据</div>
|
|
|
|
|
|
|
+ <section class="overflow-auto" style="flex: 4 4 auto; min-height: 240px;">
|
|
|
|
|
+ <div class="record-list">
|
|
|
|
|
+ <div class="record-item" v-for="item in patientRecord" :key="item.id" @click="openRecord(item)">{{ item.estimatedStartDate }}~{{ item.estimatedEndDate }}</div>
|
|
|
|
|
+ <div v-if="!patientRecord.length" style="padding-bottom: 8px; text-align: center; margin-top: 40px">暂无数据</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </section>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
-<style scoped>
|
|
|
|
|
|
|
+<style scoped lang="scss">
|
|
|
.issue-service-page {
|
|
.issue-service-page {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
flex-direction: row;
|
|
flex-direction: row;
|
|
@@ -1180,20 +1306,28 @@ watch(showProjectPopover, (val) => {
|
|
|
flex: none;
|
|
flex: none;
|
|
|
width: 190px;
|
|
width: 190px;
|
|
|
border-left: 1px solid #eee;
|
|
border-left: 1px solid #eee;
|
|
|
- padding: 16px 8px 0 8px;
|
|
|
|
|
|
|
+ //padding: 16px 8px;
|
|
|
background: #fafbfc;
|
|
background: #fafbfc;
|
|
|
/* min-height: 100vh; */
|
|
/* min-height: 100vh; */
|
|
|
box-sizing: border-box;
|
|
box-sizing: border-box;
|
|
|
|
|
+ > section {
|
|
|
|
|
+ margin: 16px 0;
|
|
|
|
|
+ padding-left: 8px;
|
|
|
|
|
+
|
|
|
|
|
+ .ant-tag {
|
|
|
|
|
+ margin-top: 6px;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
.record-title {
|
|
.record-title {
|
|
|
font-weight: bold;
|
|
font-weight: bold;
|
|
|
- margin-bottom: 8px;
|
|
|
|
|
text-align: center;
|
|
text-align: center;
|
|
|
}
|
|
}
|
|
|
.record-list {
|
|
.record-list {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
flex-direction: column;
|
|
|
gap: 8px;
|
|
gap: 8px;
|
|
|
|
|
+ padding-right: 8px;
|
|
|
}
|
|
}
|
|
|
.record-item {
|
|
.record-item {
|
|
|
background: #fff;
|
|
background: #fff;
|
|
@@ -1204,6 +1338,9 @@ watch(showProjectPopover, (val) => {
|
|
|
font-size: 12px;
|
|
font-size: 12px;
|
|
|
font-weight: bold;
|
|
font-weight: bold;
|
|
|
cursor: pointer;
|
|
cursor: pointer;
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ color: #1890ff;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
.suggest-cw {
|
|
.suggest-cw {
|
|
|
color: #1890ff;
|
|
color: #1890ff;
|