|
@@ -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()
|