Browse Source

完成电子病历的优化

xiaochan 2 năm trước cách đây
mục cha
commit
bc4ada37cd

+ 19 - 0
src/api/zhu-yuan-yi-sheng/emr-patient.ts

@@ -1,4 +1,5 @@
 import requestV2 from "../../utils/request-v2";
+import Patient from "../../ts-type/patient";
 
 let URL = 'Emr'
 
@@ -23,6 +24,7 @@ export function getEmrTree(type: 'all' | 'dept' | 'hosp' = 'all') {
     return requestV2<{ all?: any[], dept?: any[] }>({
         url: URL + '/getEmrTree',
         method: 'get',
+        showLoading: false,
         params: {type}
     })
 }
@@ -35,6 +37,7 @@ export function getSnippetTree() {
     return requestV2({
         url: URL + '/getSnippetTree',
         method: 'get',
+        showLoading: false,
     })
 }
 
@@ -221,3 +224,19 @@ export function getOpRecordList(patNo, times) {
         params: {patNo, times}
     })
 }
+
+export function getPatientInfo(inpatientNo: string) {
+    return requestV2<Patient>({
+        url: '/patient/getInfo',
+        method: 'get',
+        params: {inpatientNo},
+    })
+}
+
+export function getDisPatient(patNo: string, times: number) {
+    return requestV2<Patient>({
+        url: '/patient/getDisPatient',
+        method: 'get',
+        params: {patNo, times},
+    })
+}

+ 161 - 0
src/components/loading-progress/LoadingProgress.vue

@@ -0,0 +1,161 @@
+<script setup lang="ts">
+import {onDeactivated, onMounted, ref} from "vue";
+import {ElProgress, useZIndex} from "element-plus";
+import sleep from "@/utils/sleep";
+
+const props = defineProps<{ loadingName: string, describes: string[] }>()
+
+const percentage = ref(0)
+const progressRef = ref(null)
+const isShow = ref(false)
+const describe = ref('')
+
+let timerId = null
+
+const colors = [
+  {color: '#f56c6c', percentage: 20},
+  {color: '#e6a23c', percentage: 40},
+  {color: '#5cb87a', percentage: 60},
+  {color: '#1989fa', percentage: 80},
+  {color: '#6f7ad3', percentage: 100},
+]
+
+const close = () => {
+  percentage.value = 100
+
+  sleep(100).then(() => {
+    isShow.value = false
+    clearInterval(timerId)
+  })
+}
+
+const divRef = ref<HTMLDivElement>()
+const divBody = document.createElement('div')
+document.body.appendChild(divBody)
+
+function getRandomNumber(min: number, max: number): number {
+  return Math.floor(Math.random() * (max - min + 1)) + min;
+}
+
+function getRandomFloat(min: number, max: number): number {
+  return Math.random() * (max - min) + min;
+}
+
+function getRandomElement<T>(list: T[]): T {
+  const randomIndex = Math.floor(Math.random() * list.length);
+  return list[randomIndex];
+}
+
+const updateProgress = () => {
+  let temp = percentage.value + getRandomNumber(1, 10);
+  if (temp > 80) {
+    percentage.value = 80
+  } else {
+    percentage.value = temp
+  }
+}
+
+const slowlyIncreasing = () => {
+  let temp = percentage.value + getRandomFloat(0.1, 0.9);
+  if (temp >= 98) {
+    clearInterval(timerId)
+  }
+  percentage.value = temp
+}
+
+const start = () => {
+  divRef.value.style.zIndex = String(useZIndex().nextZIndex())
+  document.body.className = '.el-loading-parent--relative .el-loading-parent--hidden'
+  sleep(200).then(() => {
+    isShow.value = true
+  })
+  describe.value = getRandomElement(props.describes)
+
+  timerId = setInterval(() => {
+    if (percentage.value >= 80) {
+      slowlyIncreasing()
+    } else {
+      updateProgress()
+    }
+  }, 100)
+}
+
+onMounted(() => {
+  divBody.appendChild(divRef.value)
+})
+
+onDeactivated(() => {
+  document.body.className = ''
+  document.removeChild(divBody)
+})
+
+defineExpose({
+  close,
+  start,
+})
+
+</script>
+
+<template>
+  <transition name="el-fade-in-linear">
+    <div class="loading_progress" ref="divRef" v-show="isShow">
+      <div class="progress_main" style="width: 100%">
+        <div class="result">
+          <el-progress type="dashboard" :percentage="parseInt(percentage)" :color="colors" ref="progressRef">
+            <template #default="{ percentage }">
+              <span class="percentage-value">{{ percentage }}%</span>
+              <span class="percentage-label">{{ props.loadingName }}</span>
+            </template>
+          </el-progress>
+          <div class="el-result__title" style="width: 180px">
+            <p>
+              “{{ describe }}”
+            </p>
+          </div>
+        </div>
+      </div>
+    </div>
+  </transition>
+</template>
+
+<style lang="scss">
+.loading_progress {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: white;
+  display: flex;
+
+  .progress_main {
+    display: flex;
+    width: 100%;
+    margin-top: 15%;
+    height: max-content;
+    justify-content: center;
+
+    .result {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      flex-direction: column;
+      text-align: center;
+      box-sizing: border-box;
+    }
+
+    .percentage-value {
+      display: block;
+      margin-top: 10px;
+      font-size: 28px;
+    }
+
+    .percentage-label {
+      display: block;
+      margin-top: 10px;
+      font-size: 12px;
+    }
+
+  }
+}
+</style>

+ 9 - 18
src/components/zhu-yuan-yi-sheng/EmrSelectPat.vue

@@ -1,7 +1,7 @@
 <template>
   <div style="display: inline-block"
        :id="emrTutorialGetId('patInfo')">
-    <el-select v-model="props.patInfo.inpatientNo"
+    <el-select v-model="patientInfo.inpatientNo"
                title="快速搜索患者,可以根据床号快速搜索,仅针对患者同病房有用。"
                :filterable="true"
                @change="change"
@@ -26,16 +26,13 @@
 
 <script setup name='EmrSelectPat'>
 import {getOverView} from "@/api/inpatient/patient";
-import {defineProps, ref, watch} from 'vue'
+import {ref} from 'vue'
 import {
   emrTutorialGetId
 } from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-tutorial";
-
-const props = defineProps({
-  patInfo: {
-    type: Object
-  }
-})
+import {
+  patientInfo
+} from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init";
 
 const emits = defineEmits(['selected'])
 
@@ -50,16 +47,10 @@ const change = (val) => {
   }
 }
 
-watch(() => props.patInfo.ward, () => {
-  if (props.patInfo.ward) {
-    getOverView(props.patInfo.ward).then((res) => {
-      list.value = res
-    })
-  }
+watch(() => patientInfo.value.inpatientNo, () => {
+  getOverView(patientInfo.value.ward).then((res) => {
+    list.value = res
+  })
 })
 
 </script>
-
-<style scoped lang="scss">
-
-</style>

+ 25 - 21
src/components/zhu-yuan-yi-sheng/emr/EmrFirstPageOfMedicalRecord.vue

@@ -4,41 +4,45 @@
                                 :sheet-data="sheetData"/>
 </template>
 
-<script setup name="EmrFirstPageOfMedicalRecord">
+<script setup name="EmrFirstPageOfMedicalRecord" lang="ts">
 import FirstPageOfMedicalRecord from "@/components/pat-info-list/FirstPageOfMedicalRecord.vue";
 import {getAllDictionary, getSheetInfo} from "@/api/case-front-sheet";
 import {operations} from "@/data";
 import {autopsies, haveOrNot, yesOrNo} from "@/views/hospitalization/case-front-sheet/common";
+import {
+  patientInfo,
+} from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init";
+import requestV2 from "@/utils/request-v2";
+import {ref, onMounted} from 'vue'
 
 const dics = ref([])
 const sheetData = ref({})
 
 const isShow = ref(false)
 
-const props = defineProps({
-  patInfo: Object
-})
-
 
 onMounted(async () => {
-
-  let res = await getAllDictionary()
-  res.getOperations = operations;
-  res.getYesOrNo = yesOrNo;
-  res.getHaveOrNot = haveOrNot;
-  res.getAutopsies = autopsies;
-  dics.value = res
-
-  sheetData.value = await getSheetInfo({
-    bah: props.patInfo.inpatientNo,
-    times: props.patInfo.admissTimes,
-    inOutFlag: props.patInfo.$inOutFlag
+  let dictionary = await getAllDictionary()
+  dictionary.getOperations = operations;
+  dictionary.getYesOrNo = yesOrNo;
+  dictionary.getHaveOrNot = haveOrNot;
+  dictionary.getAutopsies = autopsies;
+  dics.value = dictionary
+
+  requestV2({
+    url: '/caseFrontSheet/getSheetInfo',
+    method: 'post',
+    data: {
+      bah: patientInfo.value.inpatientNo,
+      times: patientInfo.value.admissTimes,
+      inOutFlag: patientInfo.value.$inOutFlag
+    },
+    showLoading: false
+  }).then(res => {
+    sheetData.value = res
+    isShow.value = true
   })
-
-  isShow.value = true
-
 })
-
 </script>
 
 <style scoped lang="scss">

+ 11 - 14
src/components/zhu-yuan-yi-sheng/emr/emr-template/EmrSidebar.vue

@@ -50,7 +50,7 @@ import {BizException, ExceptionEnum} from "@/utils/BizException";
 import {
   canIUnlockIt,
   emrConfig,
-  emrMitt,
+  emrMitt, patientInfo,
   unlockEnum
 } from '@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init'
 import {getAllWards} from "@/api/zhu-yuan-yi-sheng/resident-doctor";
@@ -65,9 +65,6 @@ const props = defineProps({
   maxHeight: {
     type: Number
   },
-  huanZheXinXi: {
-    type: Object
-  },
   patientData: {
     type: Object
   },
@@ -128,7 +125,7 @@ const template = async (val) => {
   emrMitt.emit('loadDocument', {
     categoryCode: val.code,
     categoryId: val._id,
-    patientId: props.huanZheXinXi.inpatientNo + '_' + props.huanZheXinXi.admissTimes,
+    patientId: patientInfo.value.inpatientNo + '_' + patientInfo.value.admissTimes,
     templateName: val.name,
     createId: null
   })
@@ -138,7 +135,7 @@ const saveEmr = (val) => {
   const data = {
     categoryCode: val.emrCategoryCode,
     categoryId: val._id,
-    patientId: props.huanZheXinXi.inpatientNo + '_' + props.huanZheXinXi.admissTimes,
+    patientId: patientInfo.value.inpatientNo + '_' + patientInfo.value.admissTimes,
     documentId: val.emrDocumentId,
     code: val.code,
     templateName: val.name,
@@ -155,9 +152,9 @@ const saveEmr = (val) => {
       id: val.id,
       code: val.emrCategoryCode,
       createId: val.createId,
-      referPhysician: props.huanZheXinXi.referPhysician,
-      patNo: props.huanZheXinXi.inpatientNo,
-      times: props.huanZheXinXi.admissTimes
+      referPhysician: patientInfo.value.referPhysician,
+      patNo: patientInfo.value.inpatientNo,
+      times: patientInfo.value.admissTimes
     });
     emrMitt.emit('loadDocument', data)
   }
@@ -167,11 +164,11 @@ const determineWhetherItCanBeCreated = () => {
   if (userInfoStore.value.code === props.patientData['管床医生编码'] || props.doctorGrade > 1) {
     return true;
   }
-  return wardList.includes(props.huanZheXinXi.ward);
+  return wardList.includes(patientInfo.value.ward);
 }
 
 const judgeTheCreationOfTransfer = async () => {
-  let res = await whetherItExistsInTheDepartment(props.huanZheXinXi.inpatientNo, props.huanZheXinXi.admissTimes) as any;
+  let res = await whetherItExistsInTheDepartment(patientInfo.value.inpatientNo, patientInfo.value.admissTimes) as any;
   if (res === null) {
     return false;
   }
@@ -234,7 +231,7 @@ const findMedicalRecordById = (id, roundTimes, list) => {
 }
 
 const queryData = () => {
-  getPatientDataTree(props.huanZheXinXi.inpatientNo, props.huanZheXinXi.admissTimes).then((res) => {
+  getPatientDataTree(patientInfo.value.inpatientNo, patientInfo.value.admissTimes).then((res) => {
     if (res?.length > 0) {
       templateType.value = 2
       emit('patientMedicalRecord')
@@ -245,7 +242,7 @@ const queryData = () => {
 
 const hisData = ref([])
 const pastHistory = () => {
-  getPastHistory(props.huanZheXinXi.inpatientNo, props.huanZheXinXi.admissTimes).then((res) => {
+  getPastHistory(patientInfo.value.inpatientNo, patientInfo.value.admissTimes).then((res) => {
     let temp = []
     for (let key in res) {
       temp.push({
@@ -264,8 +261,8 @@ onMounted(() => {
     return determineWhetherItCanBeCreated()
   })
   emrMitt.on('querySidebar', queryData)
-  pastHistory()
   queryData()
+  pastHistory()
   if (editor) {
     getAllWards().then((res) => {
       if (res.length > 0) {

+ 8 - 5
src/components/zhu-yuan-yi-sheng/emr/web-socket/EmrWebSocket.vue

@@ -54,7 +54,7 @@ const props = defineProps<{
 const roomRef = ref<HTMLElement | null>(null)
 
 const dialog = ref<boolean>(false)
-const errDialog = ref<any>(true)
+const errDialog = ref<boolean>(false)
 const userMap = ref<any>({})
 const dialogRef = ref(null)
 
@@ -171,7 +171,13 @@ function initWebSocket(patNo, times) {
     }
   }
 
-  webSocket.onclose = () => {
+  webSocket.onclose = (e) => {
+    if (e.code === 1000 && e.reason === '服务器主动断开连接') {
+      documentSocket = null
+      webSocket = null
+      onmessageFunc.closeSoctek(e.reason)
+      return
+    }
     errDialog.value = true
     initWebSocket(props.patInfo.inpatientNo, props.patInfo.admissTimes)
   }
@@ -226,7 +232,6 @@ const initDocumentSocket = () => {
       }).then(() => {
       }).catch(() => {
       })
-
       return
     }
     initDocumentSocket()
@@ -294,9 +299,7 @@ defineExpose({
     line-height: 25px;
     background-color: rgba(255, 255, 255, 0.48);
     border-radius: 12px;
-
     position: relative;
-
   }
 
 }

+ 109 - 0
src/ts-type/patient.ts

@@ -0,0 +1,109 @@
+interface Patient {
+    table?: string;
+    inpatientNo?: string;
+    inOutStatusFlag?: string;
+    admissTimes?: number;
+    disDate?: Date;
+    ledgerSn?: number;
+    staffId?: string;
+    psnCertType?: string;
+    socialNo?: string;
+    mzNo?: string;
+    name?: string;
+    sex?: number;
+    birthDate?: string;
+    homeTel?: string;
+    icdCode?: string;
+    icdText?: string;
+    admissPhysician?: string;
+    admissPhysicianName?: string;
+    referPhysician?: string;
+    referPhysicianName?: string;
+    acctUsedFlag?: string;
+    dutyNurse?: string;
+    dutyNurseName?: string;
+    country?: string;
+    nation?: string;
+    contactName?: string;
+    contactRelation?: string;
+    contactAddrName?: string;
+    contactPhone?: string;
+    admissDiagStr?: string;
+    clinicDiagStr?: string;
+    admissWard?: string;
+    admissWardName?: string;
+    admissDept?: string;
+    smallDept?: string;
+    smallDeptName?: string;
+    deptCode?: string;
+    admissDate?: Date;
+    ybRegisterDate?: Date;
+    responceType?: string;
+    responceName?: string;
+    dismissOrder?: number;
+    zkWard?: string;
+    zkWardName?: string;
+    bedNo?: string;
+    statusFlag?: string;
+    totalCharge?: string;
+    indiId?: string;
+    zySerialNo?: string;
+    centerId?: string;
+    ward?: string;
+    sid?: string;
+    disDiagStatus?: string;
+    operation?: string;
+    chargeYb?: string;
+    midSetl?: boolean;
+    zjdzDatetime?: Date;
+    dismissOrderDate?: Date;
+    medType?: string;
+    medTypeName?: string;
+    insutype?: string;
+    insutypeName?: string;
+    admdvs?: number;
+    admdvsCascader?: number[];
+    matnType?: string;
+    latechbFlag?: string;
+    pretFlag?: string;
+    mdtrtId?: string;
+    injuryArea?: number;
+    injurySerialNo?: string;
+    actIptDays?: string;
+    revokeRemark?: string;
+    homeStreet?: string;
+    age?: number;
+    latitude?: number;
+    longitude?: number;
+    addrTransedFlag?: number;
+    numberOfPeopleInTheSameArea?: number;
+    timesBilled?: number;
+    yp?: string;
+    jyjc?: string;
+    yb?: string;
+    balance?: string;
+    begntime?: Date;
+    endtime?: Date;
+    diseCode?: string;
+    diseName?: string;
+    expContent?: string;
+    deathFlag?: boolean;
+    drgGrouping?: any;
+    groupInfoWeight?: string;
+    groupInfoName?: string;
+    groupInfoBl?: string;
+    groupInfoProfit?: string;
+    groupInfoFeeStand?: string;
+    criticallyIllStatus?: string;
+    nursingLevel?: string;
+    oprtStatus?: string;
+    emrAudit?: number;
+    zkys?: string;
+    consultPhysician?: string;
+    consultPhysicianName?: string;
+    deptDirector?: string;
+    deptDirectorName?: string;
+    finalControl?: number;
+}
+
+export default Patient;

+ 26 - 21
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/EmrMain.vue

@@ -35,7 +35,7 @@
     <el-divider direction="vertical"/>
     <el-button-group>
       <!--  工具   -->
-      <emr-auxiliary-tools :pat-info="props.huanZheXinXi"
+      <emr-auxiliary-tools :pat-info="patientInfo"
                            @to-fill-in-data="clickToFillInData"
                            :emr-data="patientData"/>
       <el-button @click="drgIntelligentGrouping"
@@ -149,8 +149,7 @@
             :doctor-grade="doctorLevel"
             :extract-data="extractData"
             :patientData="patientData"
-            :max-height="maxHeight"
-            :huan-zhe-xin-xi="props.huanZheXinXi"/>
+            :max-height="maxHeight"/>
       </div>
     </div>
     <div class="emr-editor"
@@ -186,7 +185,7 @@
             <div style="position: relative">
               <emr-popup ref="popupRef"
                          @fill-data="popupFunc.fillData"/>
-              <emr-web-socket :pat-info="props.huanZheXinXi"
+              <emr-web-socket :pat-info="patientInfo"
                               :current-editor-user="currentEditorUser"
                               ref="emrSocket"/>
               <div class="creator_prompt" v-loading="emrConfig.loadDocument">
@@ -231,7 +230,7 @@
                style="width: 100%;overflow-y:auto"
                :style="{height : iframeHeight() }">
             <!--             病案首页           -->
-            <emr-first-page-of-medical-record :pat-info="huanZheXinXi"/>
+            <emr-first-page-of-medical-record/>
           </div>
 
         </div>
@@ -301,7 +300,7 @@ import {
   delEmrCopy,
   emrConfig,
   emrMitt, EmrParam,
-  getEmrCopy,
+  getEmrCopy, loadingTime, patientInfo,
   query
 } from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init";
 import {ElInput, ElMessage, ElMessageBox} from "element-plus";
@@ -371,11 +370,10 @@ import {
   useEmrInit,
   UseEmrInitReturn
 } from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init-v2";
+import moment from "moment";
+import {formatDateToStr} from "@/utils/moment-utils";
 
 const props = defineProps({
-  huanZheXinXi: {
-    type: Object,
-  },
   maxHeight: {
     type: Number
   },
@@ -681,7 +679,7 @@ const setEditorModel = (val: EditorMode = 'free') => {
 
 const sendEmrSocketMessageAndHighlight = (message, flag, userInfo) => {
   sendEmrSocketMessage({
-    sid: 'emr_' + props.huanZheXinXi.inpatientNo.trim() + "_" + props.huanZheXinXi.admissTimes,
+    sid: 'emr_' + patientInfo.value.inpatientNo.trim() + "_" + patientInfo.value.admissTimes,
     userInfo,
     message: JSON.stringify({"receivedMessage": {message, flag}})
   })
@@ -786,8 +784,8 @@ const clickSaveData = async () => {
     name: '',
     emrDocumentId: id,
     emrCategoryCode: categoryCode.value,
-    patNo: props.huanZheXinXi.inpatientNo,
-    times: props.huanZheXinXi.admissTimes,
+    patNo: patientInfo.value.inpatientNo,
+    times: patientInfo.value.admissTimes,
     emrName: templateName.value,
     fragment: [],
     parent: parent,
@@ -1235,8 +1233,8 @@ const clickToSubmitTheMedicalRecord = async () => {
  */
 const queryingBasicPatientInformation = async () => {
   patientData.value = await getEmrInpatientData({
-    patNo: props.huanZheXinXi.inpatientNo,
-    times: props.huanZheXinXi.admissTimes
+    patNo: patientInfo.value.inpatientNo,
+    times: patientInfo.value.admissTimes
   })
   getCurrentPersonnelInformation()
 }
@@ -1249,7 +1247,7 @@ const drgData = ref({
 
 // 点击查看 drg 分组 通过打开 dialog 的方式, 后续可以使用打开新的页面
 const drgIntelligentGrouping = () => {
-  getDrgIntelligentGrouping(props.huanZheXinXi.inpatientNo, props.huanZheXinXi.admissTimes).then(async (res) => {
+  getDrgIntelligentGrouping(patientInfo.value.inpatientNo, patientInfo.value.admissTimes).then(async (res) => {
     drgData.value.dialog = true
     drgData.value.url = res as string
   })
@@ -1481,7 +1479,7 @@ const showIframe = ref(1)
 const visibility = useDocumentVisibility()
 
 // 创建和编辑病历
-const emrEditCreateLimit = new EmrEditCreateLimit(props.huanZheXinXi, userInfoStore.value)
+const emrEditCreateLimit = new EmrEditCreateLimit(patientInfo.value, userInfoStore.value)
 
 const currentEditorFunc = XEUtils.debounce(() => {
   // 再看病历并且现在是编辑的状态,就执行这一步
@@ -1508,10 +1506,10 @@ const watchVisibility = () => {
   watch(() => visibility.value, () => {
     // 离开页面的时候清空定时器
     if (visibility.value === 'hidden' && isEditorChange.value) {
-      document.title = `患者【${props.huanZheXinXi.name}】,未保存数据`
+      document.title = `患者【${patientInfo.value.name}】,未保存数据`
     } else {
       currentEditorFunc()
-      document.title = `电子病历-正在编辑【${props.huanZheXinXi.name}】`
+      document.title = `电子病历-正在编辑【${patientInfo.value.name}】`
     }
   }, {immediate: true})
 }
@@ -1646,8 +1644,12 @@ const initEdit = () => {
     },
     data: patientData.value
   }
-  emrConfig.value.loading = true
+  // emrConfig.value.loading = true
   useEmrInit(editRef.value, {appContext, event: emrEvent}).then((res) => {
+    emrMitt.emit('closeProgress')
+    const end = moment(new Date())
+    const start = formatDateToStr(loadingTime.value)
+    xcMessage.success(`加载完成耗时${end.diff(start, 'seconds')}秒`)
     editor = res.editor
     runtime = res.runtime
     editMain = res
@@ -1669,11 +1671,14 @@ const hisSaveEmrInit = () => {
 let hisSaveEmr: UseEmrInitReturn = {}
 
 onMounted(async () => {
-  extractData.value = await getExtractDataElement(props.huanZheXinXi.inpatientNo, props.huanZheXinXi.admissTimes)
+  doctorLevelFunc()
   await nextTick()
   await queryingBasicPatientInformation()
+  await nextTick()
   initEdit()
-  doctorLevelFunc()
+  getExtractDataElement(patientInfo.value.inpatientNo, patientInfo.value.admissTimes).then(res => {
+    extractData.value = res
+  })
   window.addEventListener('beforeunload', monitorPageRefresh, {capture: true})
   emrMittInit()
   watchVisibility()

+ 33 - 31
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/Home.vue

@@ -12,7 +12,6 @@
                     style="width: 120px"
                     @blur="query.patNo = $event.target.value.trim()"/>
         </label>
-
         次数 ({{ query.times }})
         <el-button-group>
           <emr-leave-hospital-patient @rowClick="disPatients"/>
@@ -53,17 +52,19 @@
       <div v-loading="emrConfig.loading">
         <emr-main
             ref="emrMainRef"
-            :huan-zhe-xin-xi="patientInfo"
             :max-height="maxHeight"/>
       </div>
     </div>
   </div>
   <emr-patient-list @rowClick="listRowClick" v-model="patientListDrawer"/>
+  <LoadingProgress :describes="describes"
+                   loading-name="病历加载中"
+                   ref="progressRef"/>
 </template>
 
 <script setup name='Home'>
 import EmrMain from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/EmrMain.vue";
-import {getDisPatient, getPatientInfo} from "@/api/inpatient/patient";
+import {getDisPatient, getPatientInfo} from "@/api/zhu-yuan-yi-sheng/emr-patient";
 import router from "@/router";
 import HuanZheXinXi from "@/components/zhu-yuan-yi-sheng/HuanZheXinXi.vue";
 import {BizException, ExceptionEnum} from "@/utils/BizException";
@@ -77,7 +78,9 @@ import {
   emrConfig,
   emrMitt,
   query,
-  resolveRoute, unlockEnum
+  resolveRoute,
+  unlockEnum,
+  patientInfo, loadingTime
 } from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init";
 import EmrPatientList from "@/components/zhu-yuan-yi-sheng/emr/EmrPatientList.vue";
 import EmrLeaveHospitalPatient from "@/components/zhu-yuan-yi-sheng/emr/EmrLeaveHospitalPatient.vue";
@@ -93,6 +96,7 @@ import {
   emrTutorialFunc,
   emrTutorialGetId
 } from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-tutorial";
+import LoadingProgress from "@/components/loading-progress/LoadingProgress.vue";
 
 const patInfoRef = ref(null)
 const patInfoRefOld = ref(null)
@@ -106,8 +110,6 @@ const emrMainRef = ref(null)
 let maxHeight = $ref()
 // 是否显示页面
 let show = $ref(false)
-// 获取患者信息
-let patientInfo = $ref({})
 // 距离今天的出院天数
 let dischargeDays = $ref(0)
 // 患者列表 list
@@ -143,17 +145,6 @@ const routerFunc = async () => {
     return
   }
   resolveRoute(router.currentRoute.value.params.pat)
-  let sid = 'emr_' + query.value.patNo.trim() + "_" + query.value.times
-  let res = await repeatedlyOpenTheSamePatient(sid)
-  console.log('重复打开病历 %o 连接 %s', res, sid);
-  if (res) {
-    show = false
-    await ElMessageBox.confirm('病历重复打开,请检查确认没有重复打开的病历,点击解锁后原患者病历会被关闭。', '提示', {
-      type: 'warning',
-      confirmButtonText: '解锁',
-    })
-    await emrSocketUnlock()
-  }
   console.log('查询数据 %o', query.value)
   let reqUnlock = await getMyUnlockByPatNo(query.value.patNo, query.value.times)
   console.log('申请数据 %o', reqUnlock)
@@ -165,16 +156,20 @@ const routerFunc = async () => {
   }
   // 在院编辑病历
   if (query.value.state === 1) {
-    patientInfo = await getPatientInfo(query.value.patNo);
-    patientInfo.$inOutFlag = 1;
-    show = true
+    await getPatientInfo(query.value.patNo).then(res => {
+      patientInfo.value.$inOutFlag = 1;
+      patientInfo.value = res
+      show = true
+    }).catch(() => {
+      progressRef.value.close()
+    });
   } else if (query.value.state === 2) {
     // 出院编辑病历,
     await queryDisPatient()
   } else if (query.value.state === 4) {
     // 在院只读病历
-    patientInfo = await getPatientInfo(query.value.patNo);
-    patientInfo.$inOutFlag = 1;
+    patientInfo.value = await getPatientInfo(query.value.patNo);
+    patientInfo.value.$inOutFlag = 1;
     await queryAllPatients(false)
   } else if (query.value.state === 5) {
     // 出院只读病历
@@ -186,12 +181,12 @@ const routerFunc = async () => {
 
 // 查询出院患者信息
 const queryDisPatient = async () => {
-  patientInfo = await getDisPatient(query.value.patNo, query.value.times)
-  patientInfo.$inOutFlag = 2
-  patientInfo.dischargeDays = subtractTime(await getServerDateApi(), patientInfo.disDate)
+  patientInfo.value = await getDisPatient(query.value.patNo, query.value.times)
+  patientInfo.value.$inOutFlag = 2
+  patientInfo.value.dischargeDays = subtractTime(await getServerDateApi(), patientInfo.value.disDate)
 
   // 如果患者的出院时间大于 7 天就只能看病历和打印病历了
-  emrConfig.value.editor = patientInfo.dischargeDays <= 7;
+  emrConfig.value.editor = patientInfo.value.dischargeDays <= 7;
 
   // 如果超过了七天就去查看是否有申请编辑
   if (!emrConfig.value.editor) {
@@ -214,8 +209,8 @@ const allPatientsInTheHospital = async () => {
 
 
 const queryAllPatients = async (flag) => {
-  query.value.times = patientInfo.admissTimes
-  query.value.maxTimes = patientInfo.admissTimes
+  query.value.times = patientInfo.value.admissTimes
+  query.value.maxTimes = patientInfo.value.admissTimes
   show = true
   emrConfig.value.editor = flag
 }
@@ -311,17 +306,24 @@ const whetherKickedOut = () => {
   }
 }
 
+const progressRef = ref()
+const describes = ['被删除的病历可在回收站恢复', '粘贴内容时,鼠标右键文本粘贴(ctrl + shift + v)', '如果写错了可以使用(ctrl + z / ctrl + y)']
+
 onMounted(async () => {
   whetherKickedOut()
-  emrMitt.on('getPatInfo', () => patientInfo);
+  emrMitt.on('getPatInfo', () => patientInfo.value);
   emrMitt.on('setPatInfo', (name, data) => {
-    patientInfo[name] = data
+    patientInfo.value[name] = data
   });
-
+  emrMitt.on('closeProgress', () => {
+    progressRef.value.close()
+  })
   let temp = localStorage.getItem("电子病历限制");
   if (temp !== null) {
     dialog = false;
   }
+  loadingTime.value = new Date()
+  progressRef.value.start()
   await nextTick();
   await routerFunc();
 })

+ 12 - 11
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/components/EmrAudit.vue

@@ -2,9 +2,9 @@
   <el-button @click="setAuditClick" v-if="permissions()">发送</el-button>
   <el-divider direction="vertical"/>
   <emr-audit-dialog :emr-id="emrInfo.id"
-                    :final-control="patInfo.finalControl"
+                    :final-control="patientInfo.finalControl"
                     :count="historyCount"/>
-  <template v-if="permissions() && patInfo.finalControl === 0">
+  <template v-if="permissions() && patientInfo.finalControl === 0">
     <el-divider direction="vertical"/>
     <el-button @click="finalControl">标记终末质控</el-button>
   </template>
@@ -121,7 +121,11 @@
 </template>
 
 <script setup lang="ts">
-import {Audit, emrMitt} from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init";
+import {
+  Audit,
+  emrMitt,
+  patientInfo
+} from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init";
 import {
   getAuditMessages,
   rectifyMedicalRecords,
@@ -159,8 +163,6 @@ const emrInfo = ref<Audit>({
 
 const historyCount = ref(0)
 
-const patInfo = ref({})
-
 const data = ref([])
 const expandRow = ref([])
 
@@ -175,7 +177,7 @@ const setAuditClick = () => {
     patNo: emrInfo.value.patNo,
     times: emrInfo.value.times,
     list: elTableRef.value.getSelectionRows(),
-    finalControl: patInfo.value.finalControl
+    finalControl: patientInfo.value.finalControl
   }
   setAudit(temp).then(() => {
     queryAudit(emrInfo.value)
@@ -234,7 +236,7 @@ const rowContextmenu = (row, column, event) => {
 
 const queryAudit = (val) => {
   emrInfo.value = val
-  getAuditMessages(emrInfo.value.id, emrInfo.value.code, patInfo.value.finalControl).then(async res => {
+  getAuditMessages(emrInfo.value.id, emrInfo.value.code, patientInfo.value.finalControl).then(async res => {
     expandRow.value = [];
     data.value = res.data;
     historyCount.value = res.historyCount;
@@ -286,7 +288,7 @@ const addAudit = async () => {
 const scoreDialog = ref(false)
 const scoreLevel = ref(1)
 const ratingClick = async () => {
-  let res = await selectControlByPatNo(patInfo.value.inpatientNo, patInfo.value.admissTimes)
+  let res = await selectControlByPatNo(patientInfo.value.inpatientNo, patientInfo.value.admissTimes)
   scoreDialog.value = true
   scoreLevel.value = res.patient[0].score
 }
@@ -295,7 +297,7 @@ const finalControl = () => {
   ElMessageBox.confirm('是否标记此患者为终末质控。', '提示', {
     type: 'warning'
   }).then(() => {
-    updateFinalControl(patInfo.value.inpatientNo, patInfo.value.admissTimes).then(res => {
+    updateFinalControl(patientInfo.value.inpatientNo, patientInfo.value.admissTimes).then(res => {
       emrMitt.emit('setPatInfo', 'finalControl', 1)
       queryAudit(emrInfo.value)
     })
@@ -307,12 +309,11 @@ const confirmTheQuality = async () => {
   await ElMessageBox.alert('是否改变病案质量,点击后病案首页会改变。', '提示', {
     type: "warning"
   })
-  updateControlLevel(patInfo.value.inpatientNo, patInfo.value.admissTimes, scoreLevel.value)
+  updateControlLevel(patientInfo.value.inpatientNo, patientInfo.value.admissTimes, scoreLevel.value)
   scoreDialog.value = false
 }
 
 onMounted(() => {
-  patInfo.value = emrMitt.emit('getPatInfo')
   emrMitt.on('audit', queryAudit)
 })
 

+ 2 - 2
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/components/EmrRecycleBin.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import {
   query,
-  emrMitt
+  emrMitt,
 } from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init";
 import {nextTick, onMounted, ref} from "vue";
 import {
@@ -106,7 +106,7 @@ onMounted(() => {
              @click="dialog = true"
              :id="emrTutorialGetId('recycleBin')"
              icon="Discount"
-             >
+  >
     回收站
   </el-button>
 

+ 52 - 9
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init.ts

@@ -1,10 +1,15 @@
-import store from '@/store'
-import {deletePatientEmrByDocumentId, insertEmrData} from "@/api/zhu-yuan-yi-sheng/emr-patient";
-import {xcMessage} from "@/utils/xiaochan-element-plus";
-import EventBus from "@/utils/mitt";
+import store from '../../../../../store'
+import {
+    deletePatientEmrByDocumentId,
+    insertEmrData
+} from "../../../../../api/zhu-yuan-yi-sheng/emr-patient";
+import {xcMessage} from "../../../../../utils/xiaochan-element-plus";
+import EventBus from "../../../../../utils/mitt";
 import {ref} from 'vue'
 import {EditType} from "./edit";
 import {LoadParams} from "./emr-init-v2";
+import XEUtils from "xe-utils";
+import Patient from "../../../../../ts-type/patient";
 
 // 患者数据
 export function EMRInteractive(data, editorEvent) {
@@ -102,7 +107,9 @@ export function EMRInteractive(data, editorEvent) {
 }
 
 export const query = ref({
-    patNo: '', times: 0, maxTimes: 1, state: 0
+    patNo: '',
+    times: 0,
+    state: 0
 })
 
 export const emrStateEnum = {
@@ -148,7 +155,7 @@ export function getEmrUrl(patNo, times, state = 3) {
  */
 export function getInEmrUrl(patNo, times, state = 2) {
     let query = {
-        patNo, times, state: 2, maxTimes: 1
+        patNo, times, state: 2
     }
     let temp = JSON.stringify(query)
     return window.location.origin + '/myEmrEditor/' + window.btoa(temp) + '/refresh'
@@ -435,7 +442,7 @@ export interface Audit {
 
 export interface EmrMitt {
     getDocumentSocket: () => null | WebSocket
-    openTools: () => void
+    openTools: (val: number) => void
     患者病区判断: () => boolean
     querySidebar: () => void
     editor: () => EditType
@@ -445,14 +452,15 @@ export interface EmrMitt {
     只读病历: (id: string) => void
     loadDocument: (param: EmrParam) => void
     clickSaveData: () => Promise<void>
-    forceRefresh: () => void
+    forceRefresh: (val: any) => void
     queryHistoryFunc: () => void
-    reloadDocument: () => Promise<any>
+    reloadDocument: () => void
     setEditorReadonly: () => void
     getPatInfo: () => any
     setPatInfo: (name: string, value: any) => void
     audit: (data: Audit) => void
     closeForceRefreshDialog: () => void
+    closeProgress: () => void
 }
 
 export const emrMitt = new EventBus<EmrMitt>()
@@ -498,3 +506,38 @@ export function canIUnlockIt(val) {
     }
     return applicationData.value.unlockJson.includes(val)
 }
+
+/**
+ * 患者信息填充完成后的操作
+ */
+const patInfoFunc = []
+let isReady = false
+
+export function patInfoMounted(callback: () => void) {
+    if (isReady) {
+        callback()
+        return
+    }
+    patInfoFunc.push(callback)
+}
+
+export function patInfoCallback() {
+    isReady = true
+    XEUtils.remove(patInfoFunc, (item) => {
+        item()
+        return true
+    })
+}
+
+export interface EmrPatient extends Patient {
+    // 1-在院 2-出院
+    $inOutFlag?: number
+    // 出院天数
+    dischargeDays?: number
+}
+
+export const patientInfo = ref<EmrPatient>({
+    finalControl: 0
+})
+
+export const loadingTime = ref<Date>(null)