Преглед на файлове

电子病历医生CA认证完成

xiaochan преди 10 месеца
родител
ревизия
f089a62cad

+ 166 - 50
package-lock.json

@@ -36,6 +36,7 @@
         "nprogress": "0.2.0",
         "pinia": "2.1.7",
         "qrcanvas": "3.1.2",
+        "qs": "^6.13.0",
         "sortablejs": "1.15.2",
         "vue": "^3.5.6",
         "vue-cropper": "^1.1.2",
@@ -50,6 +51,7 @@
       },
       "devDependencies": {
         "@types/node": "20.11.0",
+        "@types/qs": "^6.9.15",
         "@types/sortablejs": "^1.15.8",
         "@vitejs/plugin-vue": "5.0.4",
         "@vitejs/plugin-vue-jsx": "^4.0.1",
@@ -3135,9 +3137,9 @@
       "dev": true
     },
     "node_modules/@types/qs": {
-      "version": "6.9.9",
-      "resolved": "https://registry.npmmirror.com/@types/qs/-/qs-6.9.9.tgz",
-      "integrity": "sha512-wYLxw35euwqGvTDx6zfY1vokBFnsK0HNrzc6xNHchxfO2hpuRg74GbkEW7e3sSmPvj0TjCDT1VCa6OtHXnubsg==",
+      "version": "6.9.16",
+      "resolved": "https://registry.npmmirror.com/@types/qs/-/qs-6.9.16.tgz",
+      "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==",
       "dev": true
     },
     "node_modules/@types/range-parser": {
@@ -4692,6 +4694,21 @@
         "node": ">= 0.8"
       }
     },
+    "node_modules/body-parser/node_modules/qs": {
+      "version": "6.11.0",
+      "resolved": "https://registry.npmmirror.com/qs/-/qs-6.11.0.tgz",
+      "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+      "dev": true,
+      "dependencies": {
+        "side-channel": "^1.0.4"
+      },
+      "engines": {
+        "node": ">=0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/bonjour-service": {
       "version": "1.1.1",
       "resolved": "https://registry.npmmirror.com/bonjour-service/-/bonjour-service-1.1.1.tgz",
@@ -4842,14 +4859,21 @@
       }
     },
     "node_modules/call-bind": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.4.tgz",
-      "integrity": "sha512-e68w37XfAb5fL5M3NTxqKLcXRUkL2/kFlQjQjE/8jvPMBKmO5ZDycRkS/DrZRXjegOzwWzEwW88m+8r+D0PUUA==",
-      "dev": true,
+      "version": "1.0.7",
+      "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.7.tgz",
+      "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
       "dependencies": {
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
         "function-bind": "^1.1.2",
-        "get-intrinsic": "^1.2.1",
-        "set-function-length": "^1.1.0"
+        "get-intrinsic": "^1.2.4",
+        "set-function-length": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/call-me-maybe": {
@@ -6298,6 +6322,22 @@
         "clone": "^1.0.2"
       }
     },
+    "node_modules/define-data-property": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz",
+      "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+      "dependencies": {
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/define-lazy-prop": {
       "version": "2.0.0",
       "resolved": "https://registry.npmmirror.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
@@ -6705,6 +6745,25 @@
         "stackframe": "^1.3.4"
       }
     },
+    "node_modules/es-define-property": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.0.tgz",
+      "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+      "dependencies": {
+        "get-intrinsic": "^1.2.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-errors": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz",
+      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
     "node_modules/es-module-lexer": {
       "version": "1.3.1",
       "resolved": "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-1.3.1.tgz",
@@ -7004,6 +7063,21 @@
       "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
       "dev": true
     },
+    "node_modules/express/node_modules/qs": {
+      "version": "6.11.0",
+      "resolved": "https://registry.npmmirror.com/qs/-/qs-6.11.0.tgz",
+      "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+      "dev": true,
+      "dependencies": {
+        "side-channel": "^1.0.4"
+      },
+      "engines": {
+        "node": ">=0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/express/node_modules/statuses": {
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz",
@@ -7309,7 +7383,9 @@
       "version": "1.1.2",
       "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
       "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
-      "dev": true
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
     },
     "node_modules/gensync": {
       "version": "1.0.0-beta.2",
@@ -7329,15 +7405,21 @@
       }
     },
     "node_modules/get-intrinsic": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
-      "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
-      "dev": true,
+      "version": "1.2.4",
+      "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+      "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
       "dependencies": {
-        "function-bind": "^1.1.1",
-        "has": "^1.0.3",
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
         "has-proto": "^1.0.1",
-        "has-symbols": "^1.0.3"
+        "has-symbols": "^1.0.3",
+        "hasown": "^2.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/get-stream": {
@@ -7423,9 +7505,11 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.0.1.tgz",
       "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
-      "dev": true,
       "dependencies": {
         "get-intrinsic": "^1.1.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/graceful-fs": {
@@ -7469,30 +7553,36 @@
       }
     },
     "node_modules/has-property-descriptors": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
-      "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
-      "dev": true,
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+      "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
       "dependencies": {
-        "get-intrinsic": "^1.1.1"
+        "es-define-property": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/has-proto": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.1.tgz",
-      "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
-      "dev": true,
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.3.tgz",
+      "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
       "engines": {
         "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/has-symbols": {
       "version": "1.0.3",
       "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz",
       "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
-      "dev": true,
       "engines": {
         "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/hash-sum": {
@@ -7501,6 +7591,17 @@
       "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==",
       "dev": true
     },
+    "node_modules/hasown": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
+      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+      "dependencies": {
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
     "node_modules/he": {
       "version": "1.2.0",
       "resolved": "https://registry.npmmirror.com/he/-/he-1.2.0.tgz",
@@ -9118,10 +9219,15 @@
       }
     },
     "node_modules/object-inspect": {
-      "version": "1.13.1",
-      "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.1.tgz",
-      "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
-      "dev": true
+      "version": "1.13.2",
+      "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.2.tgz",
+      "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
     },
     "node_modules/obuf": {
       "version": "1.1.2",
@@ -10261,15 +10367,17 @@
       "integrity": "sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw=="
     },
     "node_modules/qs": {
-      "version": "6.11.0",
-      "resolved": "https://registry.npmmirror.com/qs/-/qs-6.11.0.tgz",
-      "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
-      "dev": true,
+      "version": "6.13.0",
+      "resolved": "https://registry.npmmirror.com/qs/-/qs-6.13.0.tgz",
+      "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
       "dependencies": {
-        "side-channel": "^1.0.4"
+        "side-channel": "^1.0.6"
       },
       "engines": {
         "node": ">=0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/queue-microtask": {
@@ -10900,14 +11008,16 @@
       }
     },
     "node_modules/set-function-length": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.1.0.tgz",
-      "integrity": "sha512-hgkUy8z3HKKNm3TXf9bqmqgokEeHW/ZvKA9AgNRHVOkbpDmikYotztW74QkoOdiQROLrYEjwDvuPydsBs6fDXQ==",
-      "dev": true,
+      "version": "1.2.2",
+      "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz",
+      "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
       "dependencies": {
-        "get-intrinsic": "^1.2.1",
+        "define-data-property": "^1.1.4",
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
         "gopd": "^1.0.1",
-        "has-property-descriptors": "^1.0.0"
+        "has-property-descriptors": "^1.0.2"
       },
       "engines": {
         "node": ">= 0.4"
@@ -10964,14 +11074,20 @@
       "dev": true
     },
     "node_modules/side-channel": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz",
-      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
-      "dev": true,
+      "version": "1.0.6",
+      "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.6.tgz",
+      "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
       "dependencies": {
-        "call-bind": "^1.0.0",
-        "get-intrinsic": "^1.0.2",
-        "object-inspect": "^1.9.0"
+        "call-bind": "^1.0.7",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.4",
+        "object-inspect": "^1.13.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/signal-exit": {

+ 3 - 1
package.json

@@ -46,9 +46,11 @@
     "vxe-table": "^4.7.50",
     "vxe-table-plugin-export-xlsx": "4.0.1",
     "xe-utils": "3.5.26",
-    "xlsx": "0.17.0"
+    "xlsx": "0.17.0",
+    "qs": "^6.13.0"
   },
   "devDependencies": {
+    "@types/qs": "^6.9.15",
     "@types/node": "20.11.0",
     "@types/sortablejs": "^1.15.8",
     "@vitejs/plugin-vue": "5.0.4",

+ 39 - 0
src/api/ca/ca-api.ts

@@ -0,0 +1,39 @@
+import requestV2 from "@/utils/request-v2";
+
+export type CaSendParams = {
+  id: string;
+  msg: string;
+  desc: string;
+
+  /**
+   * 同一份病历有几个需要签名的地方
+   */
+  count?: number;
+};
+
+export type CaResult = {
+  isTrust: number | null; // 使用 number 表示 Integer
+  cert: string;
+  signAlg: string;
+  signValue: string;
+  certSn: string;
+  timeStamp: string;
+  bizSn: string;
+};
+
+export function sendByCode(data: CaSendParams) {
+  return requestV2<CaResult>({
+    url: "/thyyca/sendByCode",
+    method: "POST",
+    data,
+  });
+}
+
+export function sendBatchByCode(data: CaSendParams) {
+  return requestV2<CaResult[]>({
+    url: "/thyyca/sendBatchByCode",
+    showLoading: false,
+    method: "POST",
+    data,
+  });
+}

+ 21 - 1
src/components/cy/CyDialog/index.ts

@@ -6,6 +6,7 @@ interface DialogProps {
   fullscreen?: boolean;
   width?: number | string;
   top?: string | number;
+  showClose?: boolean;
 }
 
 type CloseValue = "close" | "confirm" | "cancel";
@@ -46,6 +47,7 @@ export interface DialogOptions<P = Component> {
   visible?: boolean;
   component?: any;
   componentRef?: DialogExpose;
+  manuallyClose?: (cb: (value: CloseValue, data: any) => void) => void;
 }
 
 export interface DialogState extends DialogOptions {
@@ -71,8 +73,9 @@ export function useDialog<R = any, C = Component>(
       showConfirm: true,
       ...props,
     };
+
     dialogKey.value++;
-    dialogStore.value.push({
+    const pushIndex = dialogStore.value.push({
       ...props,
       resolve: XEUtils.once(value => {
         resolve(value);
@@ -83,5 +86,22 @@ export function useDialog<R = any, C = Component>(
       dialogKey: dialogKey.value,
       closeValue: "close",
     });
+
+    if (props.manuallyClose) {
+      const currentItem = dialogStore.value[pushIndex - 1];
+      currentItem.dialogProps.showClose = true;
+      currentItem.showCancel = false;
+      currentItem.showConfirm = false;
+
+      props.manuallyClose((value: CloseValue, data: any) => {
+        const item = dialogStore.value[pushIndex - 1];
+        if (value === "confirm") {
+          item.resolve(data);
+        } else {
+          item.reject({ value: item.closeValue, data });
+        }
+        item.visible = false;
+      });
+    }
   });
 }

+ 6 - 2
src/components/cy/CyDialog/index.vue

@@ -67,8 +67,12 @@ function setRef(el, item) {
       :is="item.component"
       :ref="el => setRef(el, item)"
       v-bind="item.params"
-      @cyDialogCancel="value => handleCancel(item, true, value)"
-      @cyDialogConfirm="value => handleConfirm(item, true, value)"
+      @cyDialogCancel="
+        (value: any, isEmits = true) => handleCancel(item, isEmits, value)
+      "
+      @cyDialogConfirm="
+        (value: any, isEmits = true) => handleConfirm(item, isEmits, value)
+      "
     />
 
     <template v-if="item.showCancel || item.showConfirm" #footer>

+ 13 - 11
src/utils/emr/edit.ts

@@ -18,19 +18,21 @@ interface Validator {
 export type EditorMode = "form" | "free" | "readonly" | "design";
 
 export interface DataElements {
-  [key: string]: {
+  [key: string]: DataElementItem | DataElementItem[];
+}
+
+export type DataElementItem = {
+  id: string;
+  value: any | null;
+  element: {
     id: string;
-    value: any | null;
-    element: {
-      id: string;
-      type: string;
-      name: string;
-      code: { internal: string; dataElement: string };
-      labels: null;
-      attributes: [];
-    };
+    type: string;
+    name: string;
+    code: { internal: string; dataElement: string };
+    labels: null;
+    attributes: [];
   };
-}
+};
 
 type CursorPlace =
   | "PARAGRAPH_START"

+ 213 - 267
src/utils/emr/emr-init-v2.ts

@@ -4,316 +4,262 @@ import { UnwrapRef } from "vue";
 import { BizException, ExceptionEnum } from "../BizException";
 import { ElMessageBox } from "element-plus";
 import XEUtils from "xe-utils";
-import useDialogToJs from "@/components/js-dialog-comp/useDialogToJs";
-import { magicApi } from "@/utils/database/magic-api-request";
-
-const GenerateSignature = defineAsyncComponent(() =>
-    import("@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/components/GenerateSignature.vue"))
-const DialogDMT = defineAsyncComponent(() => import('@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/components/DialogMDT.vue'))
 
 type AppContext =
-    | any
-    | (() => {
-    [key: string]: any
-})
+  | any
+  | (() => {
+      [key: string]: any;
+    });
 
 interface Options {
-    appContext?: AppContext
-    event?: {
-        [key: string]: (...val: any[]) => void
-    }
-    tabletMode?: boolean,
+  appContext?: AppContext;
+  event?: {
+    [key: string]: (...val: any[]) => void;
+  };
+  tabletMode?: boolean;
 }
 
 function changeRatio() {
-    let ratio = 0;
-    const screen = window.screen;
-    const ua = navigator.userAgent.toLowerCase();
-
-    if (window.devicePixelRatio !== undefined) {
-        ratio = window.devicePixelRatio;
-    } else if (~ua.indexOf('msie')) {
-        // @ts-ignore
-        if (screen.deviceXDPI && screen.logicalXDPI) {
-            // @ts-ignore
-            ratio = screen.deviceXDPI / screen.logicalXDPI;
-        }
-
-    } else if (window.outerWidth !== undefined && window.innerWidth !== undefined) {
-        ratio = window.outerWidth / window.innerWidth;
+  let ratio = 0;
+  const screen = window.screen;
+  const ua = navigator.userAgent.toLowerCase();
+
+  if (window.devicePixelRatio !== undefined) {
+    ratio = window.devicePixelRatio;
+  } else if (~ua.indexOf("msie")) {
+    // @ts-ignore
+    if (screen.deviceXDPI && screen.logicalXDPI) {
+      // @ts-ignore
+      ratio = screen.deviceXDPI / screen.logicalXDPI;
     }
-
-    if (ratio) {
-        ratio = Math.round(ratio * 100);
-    }
-    return ratio;
+  } else if (
+    window.outerWidth !== undefined &&
+    window.innerWidth !== undefined
+  ) {
+    ratio = window.outerWidth / window.innerWidth;
+  }
+
+  if (ratio) {
+    ratio = Math.round(ratio * 100);
+  }
+  return ratio;
 }
 
 const pageIsZoom = () => {
-    const rate = changeRatio();
-    if (rate !== 100) {
-        ElMessageBox.alert("当前页面不是100%显示,请按键盘ctrl+0恢复100%显示标准,如果页面是100%缩放请检查系统缩放(可自行百度),设置=》屏幕缩放(选择100%),以防页面显示错乱,以及续打对不准!", '提示', {
-            type: "warning"
-        }).then(() => {
-        }).catch(() => {
-        })
-    }
-}
-
+  const rate = changeRatio();
+  if (rate !== 100) {
+    ElMessageBox.alert(
+      "当前页面不是100%显示,请按键盘ctrl+0恢复100%显示标准,如果页面是100%缩放请检查系统缩放(可自行百度),设置=》屏幕缩放(选择100%),以防页面显示错乱,以及续打对不准!",
+      "提示",
+      {
+        type: "warning",
+      }
+    )
+      .then(() => {})
+      .catch(() => {});
+  }
+};
 
 export interface UseEmrInitReturn {
-    editor: EditType
-    runtime: Runtime
-    iframe: HTMLIFrameElement
-    delElementByName: (name: string) => void
-    loadDocument: (loadParams: LoadParams) => Promise<any>
-    loadAndSetDocument: (loadParams: LoadParams) => Promise<any>,
-    print: (value?: 'html' | 'server') => void
+  editor: EditType;
+  runtime: Runtime;
+  iframe: HTMLIFrameElement;
+  delElementByName: (name: string) => void;
+  loadDocument: (loadParams: LoadParams) => Promise<any>;
+  loadAndSetDocument: (loadParams: LoadParams) => Promise<any>;
+  print: (value?: "html" | "server") => void;
 }
 
 export interface LoadParams {
-    //文档id
-    documentId: string | null
-    // 文档类型
-    categoryCode?: string
-    // 患者id
-    patientId?: string
-    //病历类型id
-    categoryId?: string
-    // 文档版本号
-    version?: string
+  //文档id
+  documentId: string | null;
+  // 文档类型
+  categoryCode?: string;
+  // 患者id
+  patientId?: string;
+  //病历类型id
+  categoryId?: string;
+  // 文档版本号
+  version?: string;
 }
 
 function delElementByName(this: any, name: string, editor: EditType) {
-    editor.execute('execFn', {
-        value: {
-            fn: function () {
-                const EMR = editor.getScriptRuntime().EMR
-                const emrDoc = EMR.getDocument()
-                const components = emrDoc.getComponentsByCode(name)
-                components.forEach((component) => {
-                    const view = component.target
-                    const viewDom = view.el
-                    const viewParagraphDom = viewDom.parentElement
-                    viewDom.remove()
-                    if (viewParagraphDom.textContent === '') {
-                        viewParagraphDom.remove()
-                    }
-                })
-            },
-            persist: true,
-            scope: this,
-            params: name
-        }
-    })
+  editor.execute("execFn", {
+    value: {
+      fn: function () {
+        const EMR = editor.getScriptRuntime().EMR;
+        const emrDoc = EMR.getDocument();
+        const components = emrDoc.getComponentsByCode(name);
+        components.forEach(component => {
+          const view = component.target;
+          const viewDom = view.el;
+          const viewParagraphDom = viewDom.parentElement;
+          viewDom.remove();
+          if (viewParagraphDom.textContent === "") {
+            viewParagraphDom.remove();
+          }
+        });
+      },
+      persist: true,
+      scope: this,
+      params: name,
+    },
+  });
 }
 
 export function useEmrInit(
-    div: UnwrapRef<HTMLElement | null>,
-    options?: Options
+  div: UnwrapRef<HTMLElement | null>,
+  options?: Options
 ): Promise<UseEmrInitReturn> {
-    return new Promise((resolve, reject) => {
-        // @ts-ignore
-        if (div['emr']) {
-            // @ts-ignore
-            div.querySelector('iframe').remove()
-        }
-
-        const iframe: HTMLIFrameElement = document.createElement('iframe')
-        let editor: EditType, runtime: Runtime
-
-        iframe.style.width = '100%'
-        iframe.style.height = '100%'
-
-        let additionalParameters: string = ''
-        if (options && options.tabletMode) {
-            additionalParameters += '?layout=mobile-zoom'
-        }
-
-        iframe.src = '/emr/runtime/#/editor' + additionalParameters
-        iframe.style.border = '0'
-        iframe.style.display = 'block'
-
-
-        function loadDocument(loadParams: LoadParams): Promise<any> {
-            return new Promise((resolve, reject) => {
-                runtime.loadDocument(
-                    (res) => {
-                        resolve(res)
-                    },
-                    (err) => {
-                        reject(err)
-                    },
-                    loadParams
-                )
-            })
-        }
-
-        function backToTop() {
-            iframe?.contentWindow?.document?.getElementById('editorEl')?.scroll({top: 0})
-        }
-
-        function loadAndSetDocument(loadParams: LoadParams): Promise<void> {
-            return new Promise((resolve, reject) => {
-                loadDocument(loadParams)
-                    .then((res) => {
-                        backToTop()
-                        editor.setDocument(res, true)
-                        resolve(res)
-                    })
-                    .catch((err) => {
-                        reject(err)
-                    })
-            })
-        }
-
-        async function print(value: 'html' | 'server' = 'html') {
-            const documentId = editor.documentData._id
-            if (documentId == null) {
-                BizException(ExceptionEnum.MESSAGE_ERROR, "请先保存病历。");
-            }
-            const document = await loadDocument({documentId}).catch(e => {
-                BizException(ExceptionEnum.MESSAGE_ERROR, "网络错误无法保存。");
-            })
-
-            if (value === 'html') {
-                pageIsZoom()
-            }
-            editor.execute("print", {
-                value: {
-                    showPreview: true,
-                    document,
-                    mode: value === 'server' ? 'backend' : ''
-                }
-            })
-        }
-
-        // @ts-ignore
-        div['emr'] = {
-            setEditor: (e: EditType, r: any): void => {
-                editor = e
-                runtime = r
-
-                // @ts-ignore
-                div['myEmr'] = {
-                    editor: e,
-                    runtime: r
-                }
-
-                if (options && options.event) {
-                    for (const key in options.event) {
-                        editor.on(key, options.event[key])
-                    }
-                }
+  return new Promise((resolve, reject) => {
+    // @ts-ignore
+    if (div["emr"]) {
+      // @ts-ignore
+      div.querySelector("iframe").remove();
+    }
 
-                resolve({
-                    editor,
-                    runtime,
-                    iframe,
-                    delElementByName: (name: string) => delElementByName(name, editor),
-                    loadDocument,
-                    loadAndSetDocument,
-                    print
-                })
-            },
-            getAppContext: (): any => {
-                if (options && options.appContext) {
-                    if (typeof options.appContext === 'function') {
-                        return options.appContext()
-                    }
-                    return options.appContext
-                }
-                return {}
-            }
-        }
+    const iframe: HTMLIFrameElement = document.createElement("iframe");
+    let editor: EditType, runtime: Runtime;
 
-        // @ts-ignore
-        div.appendChild(iframe)
-    })
-}
+    iframe.style.width = "100%";
+    iframe.style.height = "100%";
 
-export function componentClick(evt, view, patientData): void {
-    const componentType = view.componentType;
-    const eleInfo = view.getAttribute('element')
-    if (componentType === 'sign') {
-        if (eleInfo.code.internal === '授权签名') {
-            useDialogToJs(GenerateSignature, {
-                usersign: patientData['自动签名'][0]
-            }).then(res => {
-                res.signature = "http://172.16.32.167:8077/doctorSignatureImage/" + res.id + '.png'
-                view.sign([res])
-            })
-        }
-
-        if (eleInfo.code.business === '自动签名') {
-            view.sign(patientData['自动签名'])
-        }
+    let additionalParameters: string = "";
+    if (options && options.tabletMode) {
+      additionalParameters += "?layout=mobile-zoom";
     }
 
-    if (eleInfo?.code?.internal === 'MDT') {
-        useHandleMdt(evt, view, patientData)
+    iframe.src = "/emr/runtime/#/editor" + additionalParameters;
+    iframe.style.border = "0";
+    iframe.style.display = "block";
+
+    function loadDocument(loadParams: LoadParams): Promise<any> {
+      return new Promise((resolve, reject) => {
+        runtime.loadDocument(
+          res => {
+            resolve(res);
+          },
+          err => {
+            reject(err);
+          },
+          loadParams
+        );
+      });
     }
-}
-
-let mdtData = []
 
-async function useHandleMdt(evt, view, patientData) {
-    if (mdtData.length === 0) {
-        mdtData = await magicApi({
-            url: '/dataEmr/comp/mdtData',
-            method: 'get',
-        })
+    function backToTop() {
+      iframe?.contentWindow?.document
+        ?.getElementById("editorEl")
+        ?.scroll({ top: 0 });
     }
 
-    let value = view.value
-
-    if (XEUtils.isArray(value)) {
-        value = XEUtils.map(value, (item) => {
-            return item.cascader
-        })
-    } else {
-        value = []
+    function loadAndSetDocument(loadParams: LoadParams): Promise<void> {
+      return new Promise((resolve, reject) => {
+        loadDocument(loadParams)
+          .then(res => {
+            backToTop();
+            editor.setDocument(res, true);
+            resolve(res);
+          })
+          .catch(err => {
+            reject(err);
+          });
+      });
     }
 
-    useDialogToJs(DialogDMT, {
-        options: mdtData,
-        value: value
-    }).then(res => {
-        view.setValue(res)
-        view.value = res
-    });
-}
+    async function print(value: "html" | "server" = "html") {
+      const documentId = editor.documentData._id;
+      if (documentId == null) {
+        BizException(ExceptionEnum.MESSAGE_ERROR, "请先保存病历。");
+      }
+      const document = await loadDocument({ documentId }).catch(e => {
+        BizException(ExceptionEnum.MESSAGE_ERROR, "网络错误无法保存。");
+      });
+
+      if (value === "html") {
+        pageIsZoom();
+      }
+      editor.execute("print", {
+        value: {
+          showPreview: true,
+          document,
+          mode: value === "server" ? "backend" : "",
+        },
+      });
+    }
 
-export function getBcjlUserInfo(value: any):
-    {
-        code: string, name: string
-    } {
+    // @ts-ignore
+    div["emr"] = {
+      setEditor: (e: EditType, r: any): void => {
+        editor = e;
+        runtime = r;
 
-    if (XEUtils.has(value, '编辑者')) {
-        return {
-            code: XEUtils.get(value, '编辑者.value[0].code', ''),
-            name: XEUtils.get(value, '编辑者.value[0].name', '')
+        // @ts-ignore
+        div["myEmr"] = {
+          editor: e,
+          runtime: r,
+        };
+
+        if (options && options.event) {
+          for (const key in options.event) {
+            editor.on(key, options.event[key]);
+          }
         }
-    } else {
-        return {
-            code: XEUtils.get(value, '自动签名.value[0].code', ''),
-            name: XEUtils.get(value, '自动签名.value[0].name', '')
+
+        resolve({
+          editor,
+          runtime,
+          iframe,
+          delElementByName: (name: string) => delElementByName(name, editor),
+          loadDocument,
+          loadAndSetDocument,
+          print,
+        });
+      },
+      getAppContext: (): any => {
+        if (options && options.appContext) {
+          if (typeof options.appContext === "function") {
+            return options.appContext();
+          }
+          return options.appContext;
         }
-    }
+        return {};
+      },
+    };
+
+    // @ts-ignore
+    div.appendChild(iframe);
+  });
 }
 
+export function getBcjlUserInfo(value: any): {
+  code: string;
+  name: string;
+} {
+  if (XEUtils.has(value, "编辑者")) {
+    return {
+      code: XEUtils.get(value, "编辑者.value[0].code", ""),
+      name: XEUtils.get(value, "编辑者.value[0].name", ""),
+    };
+  } else {
+    return {
+      code: XEUtils.get(value, "自动签名.value[0].code", ""),
+      name: XEUtils.get(value, "自动签名.value[0].name", ""),
+    };
+  }
+}
 
 export function parsingFragmentDataElements(editor: EditType | null, node) {
-    if (editor == null || node === null) {
-        return {}
-    }
-    const modelService = editor!.ModelService;
-    const walker = modelService.createTreeWalker(node);
-    return modelService.getElementsDataFromWalker(walker)
+  if (editor == null || node === null) {
+    return {};
+  }
+  const modelService = editor!.ModelService;
+  const walker = modelService.createTreeWalker(node);
+  return modelService.getElementsDataFromWalker(walker);
 }
 
 export enum RevisionShowMode {
-    不显示,
-    卡片,
-    嵌入
+  不显示,
+  卡片,
+  嵌入,
 }

+ 169 - 163
src/utils/request.js

@@ -1,178 +1,184 @@
-import axios from 'axios'
-import {ElMessage, ElNotification} from 'element-plus'
-import router from '@/router'
-import {startLoading, endLoading} from './loading'
-import {CyMessageBox} from "@/components/cy/message-box";
-import {useProgressBarStore} from "@/pinia/progress-bar-store";
-import XEUtils from 'xe-utils'
+import axios from "axios";
+import { ElMessage, ElNotification } from "element-plus";
+import router from "@/router";
+import { endLoading, startLoading } from "./loading";
+import { CyMessageBox } from "@/components/cy/message-box";
+import { useProgressBarStore } from "@/pinia/progress-bar-store";
+import XEUtils from "xe-utils";
+import { stringify } from "qs";
 
 const service = axios.create({
-    baseURL: import.meta.env.VITE_BASE_URL,
-    withCredentials: true,
-    timeout: 0,
-    showLoading: true
-})
+  baseURL: import.meta.env.VITE_BASE_URL,
+  withCredentials: true,
+  timeout: 0,
+  showLoading: true,
+  paramsSerializer: {
+    serialize: stringify,
+  },
+});
 
 /*axios请求拦截*/
 service.interceptors.request.use(
-    (config) => {
-        if (typeof config.jdtTitle !== 'undefined') {
-            useProgressBarStore().initialize({
-                title:
-                config.jdtTitle,
-                isOpen: true,
-                closeButton: false
-            })
-        } else {
-            if (config.url !== '/caseFrontSheet/printVerify' && !config.url.startsWith('/mixLabelPrint')) {
-                if (config.showLoading) {
-                    startLoading()
-                }
-            }
+  config => {
+    if (typeof config.jdtTitle !== "undefined") {
+      useProgressBarStore().initialize({
+        title: config.jdtTitle,
+        isOpen: true,
+        closeButton: false,
+      });
+    } else {
+      if (
+        config.url !== "/caseFrontSheet/printVerify" &&
+        !config.url.startsWith("/mixLabelPrint")
+      ) {
+        if (config.showLoading) {
+          startLoading();
         }
-        config.headers['token'] = localStorage.token
-        return config
-    },
-    (error) => {
-        endLoading()
-        return Promise.reject(error)
+      }
     }
-)
+    config.headers["token"] = localStorage.token;
+    return config;
+  },
+  error => {
+    endLoading();
+    return Promise.reject(error);
+  }
+);
 
 service.interceptors.response.use(
-    (response) => {
-        endLoading()
-        if (response.data.code === 200 || response.data.code === 0) {
-            return response.data.data
-        }
-        if (response.data.code === 2002) {
-            return response.data
-        }
-        if (response.data.code === 201) {
-            ElMessage({
-                type: 'success',
-                title: '成功',
-                duration: 3500,
-                dangerouslyUseHTMLString: true,
-                message: response.data.message,
-            })
-            return response.data.data
-        }
-        if (response.data.code === 202) {
-            CyMessageBox.alert({
-                type: "success",
-                message: response.data.message,
-                dangerouslyUseHTMLString: true,
-            }).then(XEUtils.noop)
-            return response.data.data
-        }
-        if (response.data.code === 203) {
-            ElNotification({
-                type: 'success',
-                message: response.data.message,
-                duration: 3000,
-                title: "成功"
-            })
-            return response.data.data
-        }
+  response => {
+    endLoading();
+    if (response.data.code === 200 || response.data.code === 0) {
+      return response.data.data;
+    }
+    if (response.data.code === 2002) {
+      return response.data;
+    }
+    if (response.data.code === 201) {
+      ElMessage({
+        type: "success",
+        title: "成功",
+        duration: 3500,
+        dangerouslyUseHTMLString: true,
+        message: response.data.message,
+      });
+      return response.data.data;
+    }
+    if (response.data.code === 202) {
+      CyMessageBox.alert({
+        type: "success",
+        message: response.data.message,
+        dangerouslyUseHTMLString: true,
+      }).then(XEUtils.noop);
+      return response.data.data;
+    }
+    if (response.data.code === 203) {
+      ElNotification({
+        type: "success",
+        message: response.data.message,
+        duration: 3000,
+        title: "成功",
+      });
+      return response.data.data;
+    }
 
-        if (response.data.code > 1000 && response.data.code < 2000) {
-            ElMessage({
-                type: 'error',
-                message: response.data.message,
-                duration: 3500,
-                grouping: true,
-            })
-        } else if (response.data.code > 2000 && response.data.code < 3000) {
-            if (response.data.code === 2003) {
-                CyMessageBox.alert({
-                    type: 'error',
-                    message: response.data.message,
-                    title: '提示',
-                    dangerouslyUseHTMLString: true
-                }).then(XEUtils.noop)
-            } else {
-                CyMessageBox.alert({
-                    type: 'error',
-                    message: response.data.message,
-                    title: '提示',
-                }).then(XEUtils.noop)
-            }
-        } else if (response.data.code > 3000 && response.data.code < 4000) {
-            CyMessageBox.alert({
-                type: 'error',
-                message: response.data.message,
-                title: '提示',
-                showIcon: false
-            }).then(() => {
-                router.push('/login').then(XEUtils.noop)
-            })
-        } else if (response.data.code === 5001) {
-            CyMessageBox.alert({
-                type: 'error',
-                message: response.data.message,
-                title: '提示',
-            }).then(XEUtils.noop)
-        }
-        if (response.data.code === 6001) {
-            ElMessage({
-                message: response.data.message,
-                type: 'error',
-                duration: 2500,
-                grouping: true,
-            })
-            return {
-                error: true,
-                data: response.data.data
-            }
-        } else if (response.data.code === 6002) {
-            CyMessageBox.alert({
-                type: 'error',
-                message: response.data.message,
-                title: '提示',
-            }).then(XEUtils.noop)
-            return Promise.reject(response.data.data)
-        }
+    if (response.data.code > 1000 && response.data.code < 2000) {
+      ElMessage({
+        type: "error",
+        message: response.data.message,
+        duration: 3500,
+        grouping: true,
+      });
+    } else if (response.data.code > 2000 && response.data.code < 3000) {
+      if (response.data.code === 2003) {
+        CyMessageBox.alert({
+          type: "error",
+          message: response.data.message,
+          title: "提示",
+          dangerouslyUseHTMLString: true,
+        }).then(XEUtils.noop);
+      } else {
+        CyMessageBox.alert({
+          type: "error",
+          message: response.data.message,
+          title: "提示",
+        }).then(XEUtils.noop);
+      }
+    } else if (response.data.code > 3000 && response.data.code < 4000) {
+      CyMessageBox.alert({
+        type: "error",
+        message: response.data.message,
+        title: "提示",
+        showIcon: false,
+      }).then(() => {
+        router.push("/login").then(XEUtils.noop);
+      });
+    } else if (response.data.code === 5001) {
+      CyMessageBox.alert({
+        type: "error",
+        message: response.data.message,
+        title: "提示",
+      }).then(XEUtils.noop);
+    }
+    if (response.data.code === 6001) {
+      ElMessage({
+        message: response.data.message,
+        type: "error",
+        duration: 2500,
+        grouping: true,
+      });
+      return {
+        error: true,
+        data: response.data.data,
+      };
+    } else if (response.data.code === 6002) {
+      CyMessageBox.alert({
+        type: "error",
+        message: response.data.message,
+        title: "提示",
+      }).then(XEUtils.noop);
+      return Promise.reject(response.data.data);
+    }
 
-        if (response.data.code > 7000 && response.data.code < 8000) {
-            CyMessageBox.alert({
-                type: 'error',
-                message: response.data.message,
-                title: '提示',
-            }).then(XEUtils.noop)
-            return Promise.reject(response.data)
-        }
+    if (response.data.code > 7000 && response.data.code < 8000) {
+      CyMessageBox.alert({
+        type: "error",
+        message: response.data.message,
+        title: "提示",
+      }).then(XEUtils.noop);
+      return Promise.reject(response.data);
+    }
 
-        if (response.data.data) {
-            return Promise.reject(response.data)
-        }
+    if (response.data.data) {
+      return Promise.reject(response.data);
+    }
 
-        return Promise.reject(response.data.message || '服务器内部错误')
-    },
-    (error) => {
-        endLoading()
-        // 取消请求,不显示 message
-        if (error.code && error.code === 'ERR_CANCELED') {
-            useProgressBarStore().initialize({
-                title: '',
-                isOpen: false,
-                closeButton: true
-            })
-            return Promise.reject(error)
-        }
-        ElMessage({
-            message: error,
-            type: 'error',
-            duration: 3500,
-            grouping: true,
-        })
-        useProgressBarStore().initialize({
-            title: '',
-            isOpen: false,
-            closeButton: true
-        })
-        return Promise.reject(error)
+    return Promise.reject(response.data.message || "服务器内部错误");
+  },
+  error => {
+    endLoading();
+    // 取消请求,不显示 message
+    if (error.code && error.code === "ERR_CANCELED") {
+      useProgressBarStore().initialize({
+        title: "",
+        isOpen: false,
+        closeButton: true,
+      });
+      return Promise.reject(error);
     }
-)
+    ElMessage({
+      message: error,
+      type: "error",
+      duration: 3500,
+      grouping: true,
+    });
+    useProgressBarStore().initialize({
+      title: "",
+      isOpen: false,
+      closeButton: true,
+    });
+    return Promise.reject(error);
+  }
+);
 
-export default service
+export default service;

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

@@ -186,7 +186,6 @@ import {
 import warning from "../../../../../assets/warning.png";
 import { DataElements, EditorMode, EditType, Runtime } from "@/utils/emr/edit";
 import {
-  componentClick,
   getBcjlUserInfo,
   parsingFragmentDataElements,
   RevisionShowMode,
@@ -209,6 +208,11 @@ import useCompRef from "@/utils/useCompRef";
 import { useHistoricalData } from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/components/emr-function/useEmrFunction";
 import PatientInfoView from "@/components/zhu-yuan-yi-sheng/public/PatientInfoView.vue";
 import { useSystemStore } from "@/pinia/system-store";
+import { emrCa } from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-func/emr-ca";
+import {
+  setEmrComponentClick,
+  useComponentClick,
+} from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-func/emr-component-click";
 
 const EmrWebSocket = defineAsyncComponent(
   () => import("@/components/zhu-yuan-yi-sheng/emr/web-socket/EmrWebSocket.vue")
@@ -308,6 +312,8 @@ const { magicScript, triggerScript } = useEmrScript({
 });
 
 const emrSocketRef = useCompRef(EmrWebSocket);
+const useEmrCa = emrCa();
+setEmrComponentClick(useEmrCa.componentClick);
 
 const categoryCode = ref("");
 const templateName = ref("");
@@ -412,6 +418,7 @@ const emrEvent = {
         editor?.setValues(patientData.value, true, true);
       }
     }
+    useEmrCa.testFunc(editor);
   },
   contentchange: (e, op) => {
     triggerScript("contentchange", e, op);
@@ -473,7 +480,11 @@ const emrEvent = {
     }
     return copy;
   },
-  componentClick: (evt, comp) => componentClick(evt, comp, patientData.value),
+  componentClick: (evt, comp) =>
+    useComponentClick(evt, comp, {
+      patientInfo: patientInfo.value,
+      emrName: templateName.value,
+    }),
   beforeRevisionAccept: (evt, data) => {
     try {
       return beforeRevisionAccept(evt, data);
@@ -721,6 +732,11 @@ const clickSaveData = async () => {
     documentData: null,
   };
 
+  await useEmrCa.pushSign(editor, {
+    emrName: templateName.value,
+    ...patientInfo.value,
+  });
+
   if (!isCourse()) {
     data.emrDataElement = editor.getDataElements("business", false, true);
   }
@@ -1467,16 +1483,6 @@ const refreshSaveEmr = (): Promise<boolean> => {
 
 let isEmpty = true;
 
-const fragmentJump = (param: EmrParam) => {
-  const id = getId();
-  jumpPositioning = param.trueCreationTime;
-  if (id === param.documentId) {
-    setTheProgressAnchor();
-  } else {
-    loadDocument(param);
-  }
-};
-
 const restoreDefaultSettings = () => {
   try {
     editor!.setCursor("DOCUMENT_START");
@@ -1666,7 +1672,7 @@ const initEdit = () => {
   useEmrInit(editRef.value, {
     event: emrEventProxy,
     appContext: tempData,
-  }).then(res => {
+  }).then(async res => {
     emrMitt.emit("closeProgress");
     emrStore.mutation.setEditor(res.editor);
     editor = res.editor;
@@ -1677,6 +1683,16 @@ const initEdit = () => {
     emrStore.cache.open();
     setRevisionShowMode(userConfig.emr_review_mode);
     if (isDev) {
+      await sleep(500);
+      // @ts-ignore
+      loadDocument({
+        categoryCode: "ruyuanjiluzhuanyong",
+        categoryId: "e6723e80ed6511ed85a9691047891ea7",
+        patientId: "019699_51",
+        templateName: "入院记录",
+        createId: null,
+        parent: "4959e2c054fd11edb28ac955a5f5cad1",
+      });
       // emrStore.mutation.installPlugins(res);
     }
   });

+ 23 - 29
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/components/DialogMDT.vue

@@ -1,29 +1,26 @@
 <script setup lang="ts">
-import CyDialog from "@/components/cy/dialog/src/CyDialog.vue";
-
 const props = defineProps<{
-  options: any[],
-  value: string[]
-}>()
+  options: any[];
+  value: string[];
+}>();
 
-const modelValue = ref(props.value)
+const modelValue = ref(props.value);
 
-function confirmClick(next) {
-  const reslut = []
+function confirmClick() {
+  const reslut = [];
   modelValue.value.forEach(item => {
-    const {value, label} = getLastLevelData(props.options, item)
+    const { value, label } = getLastLevelData(props.options, item);
     const tmp = {
       cascader: item,
       code: value,
       name: label,
-      showExtraDisplay: label
-    }
-    reslut.push(tmp)
-  })
-  next(reslut)
+      showExtraDisplay: label,
+    };
+    reslut.push(tmp);
+  });
+  return reslut;
 }
 
-
 function getLastLevelData(treeData, valueArray) {
   let currentNode = treeData;
   for (let i = 0; i < valueArray.length; i++) {
@@ -40,22 +37,19 @@ function getLastLevelData(treeData, valueArray) {
   return null; // 如果遍历完整个数组仍然找不到最后一级节点,返回null
 }
 
-
+defineExpose({
+  confirm: confirmClick,
+});
 </script>
 
 <template>
-  <CyDialog title="MDT人员"
-            :confirm-click="confirmClick">
-    <el-cascader
-        style="width: 100%"
-        :options="options"
-        :props="{multiple: true}"
-        v-model="modelValue"
-        :show-all-levels="false"
-    />
-  </CyDialog>
+  <el-cascader
+    style="width: 100%"
+    :options="options"
+    :props="{ multiple: true }"
+    v-model="modelValue"
+    :show-all-levels="false"
+  />
 </template>
 
-<style lang="scss">
-
-</style>
+<style lang="scss"></style>

+ 63 - 41
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/components/GenerateSignature.vue

@@ -1,54 +1,76 @@
 <template>
-  <CyDialog title="授权"
-            :confirm-click="confirmClick"
-            ref="dialogRef"
-            body-height="max-conent">
-    <el-form label-width="80px" label-position="top">
-      <el-form-item label="工号:">
-        <SystemStaffSelect
-            style="width: 100%"
-            v-model="code"/>
-      </el-form-item>
-      <el-form-item label="密码:">
-        <el-input v-model="password"/>
-      </el-form-item>
-      <el-form-item>
-        <div style="text-align: right" class="layout_h-w_max">
-          <el-button size="default" type="primary" @click="signUser">生成自己签名</el-button>
-        </div>
-      </el-form-item>
-    </el-form>
-  </CyDialog>
+  <el-form label-width="80px" label-position="top">
+    <el-form-item label="工号:">
+      <SystemStaffSelect style="width: 100%" v-model="code" />
+    </el-form-item>
+    <el-form-item label="密码:">
+      <el-input
+        v-model="password"
+        @keyup.enter.stop.prevent="emits('cyDialogConfirm', null, false)"
+      />
+    </el-form-item>
+    <el-form-item>
+      <div style="text-align: right" class="layout_h-w_max">
+        <el-button
+          size="default"
+          type="primary"
+          @click="signUser(props.patientInfo.referPhysician)"
+          >管床医生
+        </el-button>
+        <el-button
+          size="default"
+          type="primary"
+          @click="signUser(props.patientInfo.consultPhysician)"
+          >主治医生
+        </el-button>
+        <el-button
+          size="default"
+          type="primary"
+          @click="signUser(props.patientInfo.deptDirector)"
+          >主任/副主任
+        </el-button>
+        <el-button
+          size="default"
+          type="primary"
+          @click="signUser(props.currentCode)"
+          >生成自己签名
+        </el-button>
+      </div>
+    </el-form-item>
+  </el-form>
 </template>
 <script setup lang="ts">
-import CyDialog from "@/components/cy/dialog/src/CyDialog.vue";
-import SystemStaffSelect from '@/components/system/staff-select/SystemStaffSelect.vue'
-import {magicApi} from "@/utils/database/magic-api-request";
-import {useCompRef} from "@/utils/useCompRef";
-import {ClosingMethod} from "@/components/js-dialog-comp/useDialogToJs";
+import SystemStaffSelect from "@/components/system/staff-select/SystemStaffSelect.vue";
+import { magicApi } from "@/utils/database/magic-api-request";
 
 const props = defineProps<{
-  usersign: any
-}>()
+  currentCode: string;
+  patientInfo: any;
+}>();
 
-const code = ref('')
-const password = ref('')
-const dialogRef = useCompRef(CyDialog)
+const emits = defineEmits(["cyDialogConfirm"]);
 
-function signUser() {
-  dialogRef.value!.closed(ClosingMethod.CONFIRM, props.usersign)
+const code = ref("");
+const password = ref("");
+
+function signUser(code: string) {
+  emits("cyDialogConfirm", {
+    code,
+  });
 }
 
-function confirmClick(next) {
-  magicApi({
-    url: '/dataEmr/DoctorAuthSignature',
-    method: 'post',
+async function confirmClick() {
+  return await magicApi({
+    url: "/dataEmr/DoctorAuthSignature",
+    method: "post",
     data: {
       code: code.value,
-      password: password.value
-    }
-  }).then(res => {
-    next(res)
-  })
+      password: password.value,
+    },
+  });
 }
+
+defineExpose({
+  confirm: confirmClick,
+});
 </script>

+ 251 - 0
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-func/emr-ca.tsx

@@ -0,0 +1,251 @@
+import { DataElementItem, EditType } from "@/utils/emr/edit";
+import { CaSendParams, sendBatchByCode, sendByCode } from "@/api/ca/ca-api";
+import { isDev } from "@/utils/public";
+import { useUserStore } from "@/pinia/user-store";
+import XEUtils from "xe-utils";
+import { useDialog } from "@/components/cy/CyDialog/index";
+
+const GenerateSignature = defineAsyncComponent(
+  () =>
+    import(
+      "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/components/GenerateSignature.vue"
+    )
+);
+
+const testInput = {
+  required: false,
+  readonly: false,
+  deletable: true,
+  privacy: false,
+  script: {
+    content: null,
+    dynamicScript: "2154eae0167611ef8717efceee160e36",
+  },
+  format: {
+    dataType: null,
+    showType: null,
+    minLength: null,
+    maxLength: null,
+    minRows: null,
+    maxRows: null,
+    scale: null,
+    enums: null,
+    dictionary: null,
+  },
+  element: {
+    id: "552c4a60167711ef8717efceee160e36",
+    type: "element",
+    name: "医生签名",
+    code: {
+      business: "自动签名",
+      internal: "编辑者CA签名",
+      dataElement: "",
+    },
+  },
+  tips: "医生签名",
+  borderStyle: "none",
+  style: {
+    id: "e6aRxaE7OLt",
+  },
+  picker: {
+    type: null,
+    propertiesConfig: {
+      signCount: {
+        name: "签名数量",
+        code: "signCount",
+        category: "extend",
+        categoryName: "扩展",
+        value: 1,
+        editor: {
+          type: "numberfield",
+          minvalue: 1,
+        },
+      },
+      maxHeight: {
+        name: "最大高度",
+        code: "maxHeight",
+        category: "extend",
+        categoryName: "扩展",
+        editor: {
+          type: "numberfield",
+        },
+      },
+      valign: {
+        name: "对齐方式",
+        code: "valign",
+        category: "extend",
+        categoryName: "扩展",
+        editor: {
+          type: "select",
+          valueField: "code",
+          displayField: "name",
+          store: {
+            type: "store",
+            fields: ["code", "name"],
+            data: [
+              {
+                code: "top",
+                name: "上对齐",
+              },
+              {
+                code: "middle",
+                name: "中对齐",
+              },
+              {
+                code: "bottom",
+                name: "下对齐",
+              },
+            ],
+          },
+        },
+      },
+    },
+  },
+  editable: false,
+  contentWrap: true,
+  signCount: 1,
+  type: "smarttext",
+};
+
+function testFunc(editor: EditType) {
+  if (!isDev) return;
+  editor.setCursor("DOCUMENT_START");
+  editor.execute("insertContents", {
+    value: [XEUtils.cloneDeep(testInput)],
+  });
+  editor.setCursor("DOCUMENT_START");
+  editor.execute("insertContents", {
+    value: [XEUtils.cloneDeep(testInput)],
+  });
+  editor.setCursor("DOCUMENT_START");
+  const tmp = XEUtils.cloneDeep(testInput);
+  tmp.element.code.internal = "授权CA签名";
+  editor.execute("insertContents", {
+    value: [tmp],
+  });
+}
+
+type saveType =
+  | {
+      // 病历的名称
+      emrName: string;
+      // 患者名称
+      patientName: string;
+      // 患者年龄
+      age: string;
+    }
+  | any;
+
+function getInternalByCode(editor: EditType, name: string): DataElementItem[] {
+  const signatureControl = editor.getDataElements("internal", false, true);
+  // @ts-ignore
+  let data: DataElementItem[] = signatureControl[name];
+  if (!data) {
+    return null;
+  }
+  if (!XEUtils.isArray(data)) {
+    data = [data];
+  }
+  XEUtils.remove(data, item => {
+    return item.value != null;
+  });
+
+  return data;
+}
+
+function getViewById(editor: EditType, id: string) {
+  const find = editor.view.container.find(`#${id}`);
+  if (XEUtils.isEmpty(find)) {
+    return;
+  }
+  return find[0];
+}
+
+function dialog() {
+  let tmpClose = (value, data) => {};
+
+  useDialog(<div>正在生成您的签名请稍后。。。</div>, {
+    dialogProps: {
+      title: "生成签名中",
+    },
+    manuallyClose: cb => {
+      tmpClose = cb;
+    },
+  }).then(XEUtils.noop);
+
+  return {
+    closed() {
+      tmpClose("confirm", null);
+    },
+  };
+}
+
+export function emrCa() {
+  return {
+    pushSign(editor: EditType, value: saveType) {
+      return new Promise<number>(async (resolve, reject) => {
+        const signatureControl = getInternalByCode(editor, "编辑者CA签名");
+        // 如果没有这个数据源就不
+        if (
+          !XEUtils.isArray(signatureControl) ||
+          (signatureControl as any[]).length === 0
+        ) {
+          return resolve(0);
+        }
+
+        const tmpDialog = dialog();
+
+        const data: CaSendParams = {
+          msg: "电子病历系统签名",
+          desc: `该信息由病历系统发送,患者:【${value.name}】,性别:【${value.sexName}】,病区:【${value.zkWardName}】,签名病历【${value.emrName}】`,
+          id: isDev ? "00026" : useUserStore().userInfo.code,
+          count: signatureControl?.length ?? 0,
+        };
+
+        const result = await sendBatchByCode(data)
+          .catch(() => {
+            resolve(0);
+            return [];
+          })
+          .finally(() => {
+            tmpDialog.closed();
+          });
+
+        if (result.length === 0) {
+          return resolve(0);
+        }
+
+        signatureControl.forEach((signature, index) => {
+          const element = getViewById(editor, signature.id);
+          const emrData = result[index];
+          element.view.sign([emrData]);
+        });
+        return resolve(0);
+      });
+    },
+    async componentClick(evt, view, eleInfo, { patientInfo, emrName }) {
+      if (eleInfo?.code?.internal !== "授权CA签名") {
+        return;
+      }
+      const us = useUserStore().userInfo;
+      console.log(patientInfo);
+      const res = await useDialog(GenerateSignature, {
+        dialogProps: {
+          title: "授权签名",
+        },
+        params: {
+          currentCode: us.code,
+          patientInfo,
+        },
+      });
+      const code = res.code;
+      const caData = await sendByCode({
+        id: isDev ? "00026" : code,
+        msg: "电子病历系统签名",
+        desc: `由${us.name}发起签名,患者:【${patientInfo.name}】,性别:【${patientInfo.sexName}】,病区:【${patientInfo.zkWardName}】,签名病历【${emrName}】`,
+      });
+      view.sign([caData]);
+    },
+    testFunc,
+  };
+}

+ 62 - 0
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-func/emr-component-click.ts

@@ -0,0 +1,62 @@
+import { magicApi } from "@/utils/database/magic-api-request";
+import XEUtils from "xe-utils";
+import { useDialog } from "@/components/cy/CyDialog/index";
+
+const click = [];
+let mdtData = [];
+
+export function setEmrComponentClick(cb) {
+  click.push(cb);
+}
+
+export function useComponentClick(evt, view, data) {
+  click.forEach(item => {
+    const eleInfo = view.getAttribute("element");
+    item(evt, view, eleInfo, data);
+  });
+}
+
+const DialogDMT = defineAsyncComponent(
+  () =>
+    import(
+      "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/components/DialogMDT.vue"
+    )
+);
+
+async function useHandleMdt(evt, view, eleInfo, patientData) {
+  if (eleInfo?.code?.internal !== "MDT") {
+    return;
+  }
+  if (mdtData.length === 0) {
+    mdtData = await magicApi({
+      url: "/dataEmr/comp/mdtData",
+      method: "get",
+    });
+  }
+
+  let value = view.value;
+
+  if (XEUtils.isArray(value)) {
+    value = XEUtils.map(value, item => {
+      return item.cascader;
+    });
+  } else {
+    value = [];
+  }
+
+  useDialog(DialogDMT, {
+    dialogProps: {
+      title: "MDT人员",
+    },
+    // @ts-ignore
+    params: {
+      options: mdtData,
+      value: value,
+    },
+  }).then(res => {
+    view.setValue(res);
+    view.value = res;
+  });
+}
+
+setEmrComponentClick(useHandleMdt);