Browse Source

电子病历踢人和自动保存

xiaochan 1 year ago
parent
commit
d647ed804a

+ 11 - 4
src/api/public-api.js

@@ -1,4 +1,5 @@
 import request from '@/utils/request'
+import axios from "axios";
 
 export function getRoleCode() {
     return request({
@@ -173,10 +174,16 @@ export function getUuid() {
 }
 
 export function getOperationGuide(folderName) {
-    return request({
-        url: '/publicApi/getOperationGuide',
-        method: 'get',
-        params: {folderName}
+    return new Promise((resolve, reject) => {
+        axios({
+            url: 'http://172.16.32.160:8706/publicApi/getOperationGuide',
+            method: 'get',
+            params: {folderName}
+        }).then(res => {
+            resolve(res.data.data)
+        }).catch(err => {
+            reject(err)
+        })
     })
 }
 

BIN
src/assets/warning.png


+ 0 - 1
src/components/medical-insurance/medicine-return-order/GenerateMedicineReturnOrder.vue

@@ -162,7 +162,6 @@ const generateClick = async () => {
   try {
     let res = await generateMedicationList(startTime, endTime, groupNo, refundReason)
     fillTheMedicineList(res)
-
   } catch (e) {
     data.notGenerated = []
   }

+ 10 - 1
src/components/zhu-yuan-yi-sheng/emr/web-socket/EmrWebSocket.vue

@@ -40,6 +40,9 @@ import {
   emrMitt
 } from '@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init'
 import {userInfoStore} from "@/utils/store-public";
+import {
+  forceRefreshDialog
+} from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/force-refresh-func";
 
 const props = defineProps({
   patInfo: {
@@ -123,7 +126,13 @@ const onmessageFunc = {
     }
   },
   "forceRefresh": (val) => {
-    emrMitt.emit('forceRefresh')
+    emrMitt.emit('forceRefresh', val)
+  },
+  "receivedMessage": (val) => {
+    forceRefreshDialog.value.message.push(val.message)
+    if (val.flag && val.flag === 1) {
+      emrMitt.emit('closeForceRefreshDialog')
+    }
   }
 }
 

+ 108 - 107
src/store/modules/user.js

@@ -1,130 +1,131 @@
-import { fetchMenusApi, getWardsApi, loginApi } from '@/api/login'
+import {fetchMenusApi, getWardsApi, loginApi} from '@/api/login'
 import router from '@/router'
 
 const state = () => ({
-  token: '', // 登录token
-  sid: '', // 用户websocket id
-  info: {}, // 用户信息
-  wards: {}, // 病房列表
-  menus: [], // 用户菜单
-  routes: [], // 用户所以可访问路由
-  ward: '', // 用户当前选择的病房
-  paths: [], // 装载path的string数组
-  flatRoutes: [] // 用户可访问路由的扁平列表
+    token: '', // 登录token
+    sid: '', // 用户websocket id
+    info: {}, // 用户信息
+    wards: {}, // 病房列表
+    menus: [], // 用户菜单
+    routes: [], // 用户所以可访问路由
+    ward: '', // 用户当前选择的病房
+    paths: [], // 装载path的string数组
+    flatRoutes: [] // 用户可访问路由的扁平列表
 })
 
 // getters
 const getters = {
-  token(state) {
-    return state.token
-  },
-  sid(state) {
-    return state.sid
-  },
-  info(state) {
-    return state.info
-  },
-  wards(state) {
-    return state.wards
-  },
-  menus(state) {
-    return state.menus
-  },
-  routes(state) {
-    return state.routes
-  },
-  ward(state) {
-    return state.ward
-  },
-  pahts(state) {
-    return state.paths
-  },
+    token(state) {
+        return state.token
+    },
+    sid(state) {
+        return state.sid
+    },
+    info(state) {
+        return state.info
+    },
+    wards(state) {
+        return state.wards
+    },
+    menus(state) {
+        return state.menus
+    },
+    routes(state) {
+        return state.routes
+    },
+    ward(state) {
+        return state.ward
+    },
+    pahts(state) {
+        return state.paths
+    },
 }
 
 // mutations
 const mutations = {
-  tokenChange(state, token) {
-    state.token = token
-  },
-  closeSid(state, sid) {
-    state.sid = ''
-  },
-  sidChange(state, sid) {
-    state.sid = sid
-  },
-  infoChange(state, info) {
-    state.info = info
-  },
-  wardsChange(state, wards) {
-    state.wards = wards
-  },
-  menusChange(state, menus) {
-    state.menus = menus
-  },
-  routesChange(state, routes) {
-    state.routes = routes
-  },
-  wardChange(state, ward) {
-    state.ward = ward
-  },
-  pathsChange(state, paths) {
-    state.paths = paths
-  },
-  flatRoutesChange(state, flatRoutes) {
-    state.flatRoutes = flatRoutes
-  },
+    tokenChange(state, token) {
+        state.token = token
+    },
+    closeSid(state, sid) {
+        state.sid = ''
+    },
+    sidChange(state, sid) {
+        state.sid = sid
+    },
+    infoChange(state, info) {
+        state.info = info
+    },
+    wardsChange(state, wards) {
+        state.wards = wards
+    },
+    menusChange(state, menus) {
+        state.menus = menus
+    },
+    routesChange(state, routes) {
+        state.routes = routes
+    },
+    wardChange(state, ward) {
+        state.ward = ward
+    },
+    pathsChange(state, paths) {
+        state.paths = paths
+    },
+    flatRoutesChange(state, flatRoutes) {
+        state.flatRoutes = flatRoutes
+    },
 }
 
 // actions
 const actions = {
-  // login by login.vue
-  login({ commit, dispatch }, params) {
-    return new Promise((resolve, reject) => {
-      loginApi(params).then((res) => {
-        commit('tokenChange', res.token)
-        commit('sidChange', res.sid)
-        commit('infoChange', res)
-        dispatch('getWards').then((infoRes) => {
-          resolve(res)
+    // login by login.vue
+    login({commit, dispatch}, params) {
+        return new Promise((resolve, reject) => {
+            loginApi(params).then((res) => {
+                console.log(res)
+                commit('tokenChange', res.token)
+                commit('sidChange', res.sid)
+                commit('infoChange', res)
+                dispatch('getWards').then((infoRes) => {
+                    resolve(res)
+                })
+            })
         })
-      })
-    })
-  },
-  // get user info after user logined
-  getWards({ commit, dispatch }) {
-    return new Promise((resolve, reject) => {
-      getWardsApi().then((res) => {
-        commit('wardsChange', res)
-        dispatch('getMenus').then((menusRes) => {
-          resolve(res)
+    },
+    // get user info after user logined
+    getWards({commit, dispatch}) {
+        return new Promise((resolve, reject) => {
+            getWardsApi().then((res) => {
+                commit('wardsChange', res)
+                dispatch('getMenus').then((menusRes) => {
+                    resolve(res)
+                })
+            })
         })
-      })
-    })
-  },
+    },
 
-  getMenus({ commit }) {
-    return new Promise((resolve, reject) => {
-      fetchMenusApi().then((res) => {
-        commit('menusChange', res.routes)
-        commit('routesChange', res.routes)
-        commit('pathsChange', res.paths)
-        commit('flatRoutesChange', res.flatRoutes)
-        resolve(res)
-      })
-    })
-  },
+    getMenus({commit}) {
+        return new Promise((resolve, reject) => {
+            fetchMenusApi().then((res) => {
+                commit('menusChange', res.routes)
+                commit('routesChange', res.routes)
+                commit('pathsChange', res.paths)
+                commit('flatRoutesChange', res.flatRoutes)
+                resolve(res)
+            })
+        })
+    },
 
-  // login out the system after user click the loginOut button
-  loginOut({ commit }) {
-    localStorage.clear()
-    router.push('/login')
-  },
+    // login out the system after user click the loginOut button
+    loginOut({commit}) {
+        localStorage.clear()
+        router.push('/login')
+    },
 }
 
 export default {
-  namespaced: true,
-  state,
-  actions,
-  getters,
-  mutations,
+    namespaced: true,
+    state,
+    actions,
+    getters,
+    mutations,
 }

+ 5 - 1
src/utils/request-v2.ts

@@ -1,7 +1,11 @@
 import request from './request'
 import {AxiosRequestConfig} from "axios";
 
-const requestV2 = (options: AxiosRequestConfig): Promise<any> => {
+interface AxiosRequestConfigV2 extends AxiosRequestConfig {
+    showLoading?: boolean
+}
+
+const requestV2 = (options: AxiosRequestConfigV2): Promise<any> => {
     return request(options)
 }
 export default requestV2

+ 5 - 2
src/utils/request.js

@@ -13,7 +13,7 @@ const createAPopup = (message = '错误信息') => {
     }
     popUps = ElMessageBox.alert(message, '提示', {
         type: "error",
-    }).finally(()=>{
+    }).finally(() => {
         popUps = null
     })
 }
@@ -22,6 +22,7 @@ const service = axios.create({
     baseURL: import.meta.env.VITE_BASE_URL,
     withCredentials: true,
     timeout: 0,
+    showLoading: true
 })
 
 /*axios请求拦截*/
@@ -31,7 +32,9 @@ service.interceptors.request.use(
             store.commit('app/setJdt', {title: config.jdtTitle, isOpen: true, closeButton: false})
         } else {
             if (config.url !== '/caseFrontSheet/printVerify' && !config.url.startsWith('/mixLabelPrint')) {
-                startLoading()
+                if (config.showLoading) {
+                    startLoading()
+                }
             }
         }
         if (store.getters['user/token']) {

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

@@ -115,7 +115,6 @@
     <el-checkbox v-model="autoSave" label="自动保存" @change="autoSaveChange"/>
     <el-checkbox v-model="isOpenPage" label="分页线" @change="openOrClosePage"/>
   </div>
-
   <div style="display: flex">
     <div class="modLeftRef" v-show="completeModeSwitch">
       <div ref="modLeftRef" class="refDiv"/>
@@ -209,7 +208,6 @@
           </div>
 
         </div>
-
       </div>
     </div>
     <div class="modRightRef" v-show="completeModeSwitch">
@@ -265,6 +263,7 @@
 
 
   </div>
+  <EmrRefreshDialog/>
 </template>
 
 <script setup lang="ts">
@@ -320,9 +319,18 @@ import {saveEmr} from "@/api/emr-control/emr-control";
 import {ref, onMounted, nextTick, watch, computed} from 'vue'
 import {useCompRef} from "@/utils/useCompRef";
 import {ElInput} from "element-plus";
-import {appStore} from "@/utils/store-public";
+import {appStore, userInfoStore} from "@/utils/store-public";
 import emrEditorMounted
   from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-editor-mounted";
+import {
+  getCurrentDocumentUserCode,
+  openRefreshDialog,
+  sendEmrSocketMessage
+} from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/force-refresh-func";
+import EmrRefreshDialog
+  from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/components/EmrRefreshDialog.vue";
+import warning from '../../../../../assets/warning.png'
+import {VXETable} from "vxe-table";
 
 const props = defineProps({
   huanZheXinXi: {
@@ -390,12 +398,10 @@ let emrCodeEnum = {
 
 const autoSave = ref(true)
 
-
 const isCourse = () => {
   return categoryCode.value === 'shoucibingchengjilu' || categoryCode.value === 'xinshengerjianhujilu';
 }
 
-
 const emrMainWidth = () => {
   if (showIframe.value === 3) {
     return {
@@ -414,7 +420,7 @@ const emrMainWidth = () => {
 
 const emrEvent = {
   'loaded': async (event) => {
-    setEditor()
+    setEditor();
     loaded.value = false
     // 获取医生等级
     doctorLevelFunc()
@@ -596,7 +602,14 @@ const editJudgment = async () => {
       editor.setEditorMode('readonly')
     }).catch(async (value) => {
       if (value === 'cancel') {
-        await forcedKickingOutOfPersonnelByDocumentId(documentId.value)
+        try {
+          await forcedKickingOutOfPersonnelByDocumentId(documentId.value)
+          await openRefreshDialog()
+          emrSocket.value.documentChange(documentId.value);
+        } catch (e) {
+          editor.setEditorMode('readonly')
+          xcMessage.error('踢出失败', e)
+        }
       } else {
         editor.setEditorMode('readonly')
       }
@@ -605,6 +618,95 @@ const editJudgment = async () => {
   readonlyPattern()
 }
 
+enum EditorMode {
+  /**
+   * 该模式下只允许编辑smarttext 、checkfield等form表单相关组件的值,可用于门诊病历
+   */
+  FORM = 'from',
+  /**
+   * 该模式下可以对文档任何文本、组件进行操作,一般用于电子病历书写
+   */
+  FREE = 'free',
+  /**
+   * 该模式只能对文档进行查看,不可操作
+   */
+  READONLY = 'readonly',
+  /**
+   * 设计模式,用于模版的编辑 此模式下组件的可删除属性约束无效
+   */
+  DESIGN = 'design'
+}
+
+const setEditorModel = (val: EditorMode = EditorMode.FREE) => {
+  try {
+    editor.setEditorMode(val)
+    readonlyPattern()
+  } catch {
+
+  }
+}
+
+const sendEmrSocketMessageAndHighlight = (message, flag, userInfo) => {
+  sendEmrSocketMessage({
+    sid: 'emr_' + props.huanZheXinXi.inpatientNo.trim() + "_" + props.huanZheXinXi.admissTimes,
+    userInfo,
+    message: JSON.stringify({"receivedMessage": {message, flag}})
+  })
+  highlightIcon(message)
+}
+
+const oldHighlightConfig = {
+  icon: '',
+  title: '',
+  interval: 0,
+  toggleTitle: true
+}
+
+const highlightIcon = (message) => {
+  const link = document.querySelector("link[rel~='icon']") as HTMLLinkElement
+  oldHighlightConfig.title = document.title
+  oldHighlightConfig.icon = link.href
+
+  link.href = warning
+
+  clearInterval(oldHighlightConfig.interval)
+
+  oldHighlightConfig.interval = setInterval(() => {
+    oldHighlightConfig.toggleTitle = !oldHighlightConfig.toggleTitle
+    document.title = oldHighlightConfig.toggleTitle ? message : '\u200E\u200E'
+  }, 1000)
+
+}
+
+const clearHighlightIcon = () => {
+  const link = document.querySelector("link[rel~='icon']") as HTMLLinkElement
+  link.href = oldHighlightConfig.icon
+  document.title = oldHighlightConfig.title
+  clearInterval(oldHighlightConfig.interval)
+}
+
+
+/**
+ * 强制踢出接收方
+ * @param forceRefreshUserInfo 踢人方的用户信息
+ */
+const forceTheRecipientToBeKickedOut = (forceRefreshUserInfo: string) => {
+
+  let tempForceRefreshData = {
+    userInfo: forceRefreshUserInfo,
+    saveSuccess: false
+  }
+  sendEmrSocketMessageAndHighlight('收到消息,正在保存病历中...', 0, forceRefreshUserInfo)
+  setEditorModel(EditorMode.READONLY)
+  refreshSaveEmr().then((val) => {
+    sendEmrSocketMessageAndHighlight('病历保存成功。', 1, forceRefreshUserInfo)
+    tempForceRefreshData.saveSuccess = val
+    localStorage.setItem("强制刷新", JSON.stringify(tempForceRefreshData))
+    window.removeEventListener('beforeunload', monitorPageRefresh, {capture: true})
+    location.reload();
+  })
+}
+
 
 // 点击保存病历
 const clickSaveData = async () => {
@@ -616,11 +718,13 @@ const clickSaveData = async () => {
   if (editor === null) return
   waitForLoadingToComplete()
   // 判断是否有必填项目
+
   try {
-    let validator = editor.getValidator();
-    let valid = validator.valid();
+    const validator = editor.getValidator();
+    const valid = validator.valid();
     if (valid) {
-      BizException(ExceptionEnum.MESSAGE_ERROR, "有必填项不能为空,请仔细检查,红色输入框.")
+      xcMessage.error("有必填项不能为空,请仔细检查,红色输入框。")
+      return
     }
   } catch {
   }
@@ -1306,7 +1410,7 @@ const zoomFunc = (val) => {
 }
 
 let interval = null
-let intervalTime = 1000 * 60 * 5
+let intervalTime = isDev ? 7000 : 1000 * 60 * 5
 const autoSaveChange = () => {
   store.commit('app/setEmrAutoSave', autoSave.value)
   if (interval != null) {
@@ -1322,12 +1426,35 @@ const autoSaveChange = () => {
 }
 
 const autoSaveFunc = () => {
-  if (saveDialog.value.dialog) {
-    saveDialog.value.close()
-    clickSaveData()
-  } else {
-    clickSaveData()
+  if (readonlyPattern()) {
+    return
   }
+
+  if (documentId.value !== null && documentId.value.trim() !== '') {
+
+    VXETable.modal.message({
+      status: 'loading',
+      content: '正在自动保存中...',
+      id: 'autoSave',
+    })
+
+    refreshSaveEmr().then(res => {
+      setTimeout(() => {
+        VXETable.modal.close('autoSave')
+
+        setTimeout(() => {
+          if (res) {
+            xcMessage.success(`自动保存:【成功】`)
+          } else {
+            xcMessage.error(`自动保存:【失败】`)
+          }
+        }, 1000)
+
+      }, 2000)
+    })
+  }
+
+
 }
 
 /**
@@ -1398,6 +1525,26 @@ const visibility = useDocumentVisibility()
 // 创建和编辑病历
 let emrEditCreateLimit = new EmrEditCreateLimit(props.huanZheXinXi, userData)
 
+const currentEditorFunc = XEUtils.debounce(() => {
+  // 再看病历并且现在是编辑的状态,就执行这一步
+  if (documentId.value && !readonlyPattern()) {
+    getCurrentDocumentUserCode(documentId.value).then(res => {
+      console.log('当前连接的人', res)
+      if (res && userInfoStore.value.code !== res.code) {
+        const str = `当前编辑人员:【${res.name}】,科室:【${res.deptName}】<br /><span style="color: red">一份病历只能一个人编辑,当前病历已被锁定。</span>`
+        ElMessageBox.alert(str, '提示', {
+          dangerouslyUseHTMLString: true,
+          type: "warning"
+        }).then(() => {
+
+        }).catch(() => {
+
+        })
+        setEditorModel(EditorMode.READONLY)
+      }
+    })
+  }
+}, 1000)
 
 const watchVisibility = () => {
   watch(() => visibility.value, () => {
@@ -1408,12 +1555,31 @@ const watchVisibility = () => {
       }
       document.title = `患者【${props.huanZheXinXi.name}】,未保存数据`
     } else {
+      currentEditorFunc()
       autoSaveChange()
       document.title = `电子病历-正在编辑【${props.huanZheXinXi.name}】`
     }
   }, {immediate: true})
 }
 
+
+const refreshSaveEmr = (): Promise<boolean> => {
+  return new Promise((resolve, reject) => {
+    const runtime = currentEmr.value.getRuntime()
+    const document = editor.getDocument();
+    document._id = editor.documentData._id
+    runtime.saveDocument(document,
+        (res) => {
+          resolve(true)
+        },
+        (err) => {
+          reject(false)
+        }
+    )
+  })
+}
+
+
 const emrMittInit = () => {
   emrMitt.on('editor', () => {
     return editor
@@ -1426,20 +1592,27 @@ const emrMittInit = () => {
     }
   })
 
-  emrMitt.on("forceRefresh", () => {
-    try {
-      editor.setEditorMode('readonly')
-    } catch {
-    }
-    isEditorChange.value = false
-    location.reload();
-  })
-
+  emrMitt.on("forceRefresh", forceTheRecipientToBeKickedOut)
   emrMitt.on('queryHistoryFunc', queryHistoryFunc)
-
+  emrMitt.on('loadDocument', () => {
+    return new Promise(resolve => {
+      const runtime = currentEmr.value.getRuntime();
+      const param = {
+        documentId: documentId.value
+      }
+      runtime.loadDocument(res => {
+            editor.setDocument(res, true);
+            resolve()
+          },
+          (err) => {
+            resolve()
+          },
+          param
+      )
+    })
+  })
 }
 
-
 onMounted(async () => {
   autoSave.value = isDev ? false : appStore.value.emrAutoSave;
   extractData.value = await getExtractDataElement(props.huanZheXinXi.inpatientNo, props.huanZheXinXi.admissTimes)
@@ -1452,9 +1625,7 @@ onMounted(async () => {
   }
   doctorLevelFunc()
   emrRef.value.parentElement.emr = currentEmr.value
-
   window.addEventListener('beforeunload', monitorPageRefresh, {capture: true})
-
   autoSaveFunc()
   emrMittInit()
   watchVisibility()

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

@@ -266,20 +266,34 @@ const emrSocketUnlock = async () => {
   await routerFunc()
 }
 
-onMounted(async () => {
+const whetherKickedOut = () => {
+  const data = localStorage.getItem("强制刷新")
+  console.log('强制刷新的人', data)
+  if (data) {
+    const {userInfo, saveSuccess} = JSON.parse(data)
+    ElMessageBox.alert(`您已经被强制踢出,操作人:【${userInfo.name}】,您的病历保存【${saveSuccess ? '成功' : '失败'}】。`, '提示', {
+      type: 'warning',
+    }).then(() => {
+    }).catch(() => {
+    })
+
+    localStorage.removeItem("强制刷新")
+  }
+}
 
-  emrMitt.on('getPatInfo', () => patientInfo)
+onMounted(async () => {
+  whetherKickedOut()
+  emrMitt.on('getPatInfo', () => patientInfo);
   emrMitt.on('setPatInfo', (name, data) => {
     patientInfo[name] = data
-  })
-
+  });
 
-  let temp = localStorage.getItem("电子病历限制")
+  let temp = localStorage.getItem("电子病历限制");
   if (temp !== null) {
-    dialog = false
+    dialog = false;
   }
   await nextTick();
-  await routerFunc()
+  await routerFunc();
 })
 
 

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

@@ -120,7 +120,7 @@
 
 </template>
 
-<script setup name='EmrAudit'>
+<script setup>
 import {emrMitt} from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init";
 import {
   getAuditMessages,

+ 85 - 0
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/components/EmrRefreshDialog.vue

@@ -0,0 +1,85 @@
+<script setup lang="ts">
+import {
+  forceRefreshDialog
+} from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/force-refresh-func";
+import {emrMitt} from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init";
+import {onMounted} from "vue";
+
+let countdown = null
+const opened = () => {
+  countdown = setInterval(() => {
+    forceRefreshDialog.value.waitForSeconds -= 1
+    if (forceRefreshDialog.value.waitForSeconds === 0) {
+      closeForceRefreshDialog()
+    }
+  }, 1000)
+}
+
+const closeForceRefreshDialog = () => {
+  clearInterval(countdown)
+  forceRefreshDialog.value.message.push('正在更新病历文档。')
+  const loadDocument = emrMitt.emit('loadDocument')
+  loadDocument.then(res => {
+    forceRefreshDialog.value.resolve(null)
+    forceRefreshDialog.value.dialog = false
+  })
+}
+
+onMounted(() => {
+  emrMitt.on('closeForceRefreshDialog', closeForceRefreshDialog)
+})
+
+
+</script>
+
+<template>
+  <el-dialog v-model="forceRefreshDialog.dialog"
+             title="对方状态"
+             @opened="opened"
+             :close-on-click-modal="false"
+             :show-close="false"
+             :close-on-press-escape="false">
+
+    <div class="refresh_countdown">
+      倒计时结束未响应,强制同意,剩余【{{ forceRefreshDialog.waitForSeconds }}】 秒
+    </div>
+
+    <div>
+      <ul class="refresh_infinite-list" style="overflow: auto">
+        <li v-for="i in forceRefreshDialog.message" :key="i" class="refresh_infinite-list-item">{{ i }}</li>
+      </ul>
+
+    </div>
+
+  </el-dialog>
+</template>
+
+<style lang="scss">
+
+.refresh_countdown {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  height: 30px;
+  background: var(--el-color-error-light-9);
+  margin: 10px;
+  color: var(--el-color-error);
+}
+
+.refresh_infinite-list {
+  height: 300px;
+  padding: 0;
+  margin: 0;
+  list-style: none;
+
+  .refresh_infinite-list-item {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    height: 30px;
+    background: var(--el-color-primary-light-9);
+    margin: 10px;
+    color: var(--el-color-primary);
+  }
+}
+</style>

+ 4 - 0
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init.js

@@ -22,6 +22,10 @@ export function EMRInteractive(data, editorEvent) {
         return this.editor
     }
 
+    this.getRuntime = () => {
+        return this.runtime
+    }
+
     this.deleteElement = (params) => {
         this.editor.execute('execFn', {
             value: {

+ 70 - 0
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/force-refresh-func.ts

@@ -0,0 +1,70 @@
+import {isDev} from "../../../../../utils/public";
+import {ref} from "vue";
+import requestV2 from "../../../../../utils/request-v2";
+
+const api: string = isDev ? 'http://localhost:8707/socketApi' : 'http://172.16.32.160:8707/socketApi'
+
+export interface SendEmrSocketParam {
+    /**
+     * 房间的id
+     */
+    sid: string;
+    /**
+     * 接收人
+     */
+    userInfo: string;
+    /**
+     * 发送的消息
+     */
+    message: string;
+}
+
+export function sendEmrSocketMessage(data: SendEmrSocketParam): void {
+    requestV2({
+        url: '/emrSocket/sendEmrSocketMessage',
+        method: 'post',
+        data,
+        showLoading: false
+    }).then(r => {
+    })
+}
+
+export function getCurrentDocumentUserCode(documentId: string) {
+    return requestV2({
+        url: '/emrSocket/getCurrentDocumentUserCode',
+        method: 'get',
+        showLoading: false,
+        params: {documentId},
+    })
+}
+
+export const forceRefreshDialog = ref<{
+    // 对话框
+    dialog: boolean,
+    // 接收到的消息体
+    message: string[],
+    // 被体方的状态
+    flag: number,
+    // 等待秒数
+    waitForSeconds: number
+    resolve: (value: unknown) => void
+}>({
+    dialog: false,
+    message: [],
+    flag: 0,
+    waitForSeconds: 10,
+    resolve: null
+})
+
+export const openRefreshDialog = () => {
+    return new Promise(resolve => {
+        forceRefreshDialog.value = {
+            dialog: true,
+            message: [],
+            flag: 0,
+            waitForSeconds: 15,
+            resolve
+        }
+    })
+}
+