浏览代码

电子病历新增创建文件夹的功能

xiaochan 11 月之前
父节点
当前提交
49163b78a3

+ 6 - 0
package-lock.json

@@ -10,6 +10,7 @@
       "dependencies": {
         "@babel/standalone": "7.24.5",
         "@element-plus/icons-vue": "2.3.1",
+        "@imengyu/vue3-context-menu": "^1.4.2",
         "@kjgl77/datav-vue3": "1.7.2",
         "@vitejs/plugin-legacy": "5.4.0",
         "@vueuse/core": "10.9.0",
@@ -2466,6 +2467,11 @@
         "mlly": "^1.6.1"
       }
     },
+    "node_modules/@imengyu/vue3-context-menu": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmmirror.com/@imengyu/vue3-context-menu/-/vue3-context-menu-1.4.3.tgz",
+      "integrity": "sha512-W2rT+xllLSg+u/Z36jE+mrjzO8gCIw0YDDyBxywuASmwrBotU4deftW8Zz9GK/QEHBRNyV5nBINZJo2J257Wlg=="
+    },
     "node_modules/@jiaminghi/bezier-curve": {
       "version": "0.0.9",
       "resolved": "https://registry.npmmirror.com/@jiaminghi/bezier-curve/-/bezier-curve-0.0.9.tgz",

+ 2 - 1
package.json

@@ -49,7 +49,8 @@
     "xe-utils": "3.5.26",
     "xlsx": "0.17.0",
     "qs": "^6.13.0",
-    "jsencrypt": "^3.3.2"
+    "jsencrypt": "^3.3.2",
+    "@imengyu/vue3-context-menu": "^1.4.2"
   },
   "devDependencies": {
     "@types/qs": "^6.9.15",

+ 29 - 0
src/api/archive/archive-api.ts

@@ -0,0 +1,29 @@
+import requestV2 from "@/utils/request-v2";
+
+export enum Type {
+  EMR = 1,
+}
+
+export interface PatientArchive {
+  id: string;
+  patNo: string;
+  times: number;
+  documentId: string;
+  createId: string;
+  name: string;
+  isDir: boolean;
+  parentId: string;
+  path: string;
+  type: number;
+  sort: number;
+  info: string;
+  children?: PatientArchive[];
+}
+
+export function getPatientArchives(patNo: string, times = 0) {
+  return requestV2<PatientArchive[]>({
+    url: "/thyy/archive/getPatientArchives",
+    method: "GET",
+    params: { patNo, times },
+  });
+}

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

@@ -315,3 +315,32 @@ export function getEmrToken() {
     sessionStorage.setItem("emr-token", res);
   });
 }
+
+export function newDir(value: {
+  name: string;
+  parent: string;
+  patNo: string;
+  times: number;
+}) {
+  return requestV2({
+    url: URL + "/newDir",
+    method: "post",
+    data: value,
+  });
+}
+
+export function delDir(id: string) {
+  return requestV2({
+    url: URL + "/delDir",
+    method: "get",
+    params: { id },
+  });
+}
+
+export function rename(name: string, documentId: string) {
+  return requestV2({
+    url: URL + "/rename",
+    method: "get",
+    params: { name, documentId },
+  });
+}

+ 20 - 4
src/components/cy/CyDialog/index.vue

@@ -58,17 +58,27 @@ const ConfigProvider = defineComponent({
     item: Object,
   },
   setup(props, { slots }) {
-    provide(dialogKeyType, props.item);
+    provide(dialogKeyType, props.item as DialogState);
     return () => renderSlot(slots, "default");
   },
 });
+
+const style = (item: DialogState) => {
+  if (item.dialogProps.fullscreen) {
+    return {};
+  }
+  return {
+    "--el-dialog-border-radius": "14px",
+  };
+};
 </script>
 
 <template>
   <el-dialog
     v-for="(item, index) in dialogStore"
-    :key="`Cy-dialog_${item.dialogKey}`"
-    :style="{ '--el-dialog-border-radius': '14px' }"
+    :key="`cy-dialog_${item.dialogKey}`"
+    :style="style"
+    class="cy_dialog-v2"
     v-model="item.visible"
     draggable
     v-bind="item.dialogProps"
@@ -111,7 +121,13 @@ const ConfigProvider = defineComponent({
 </template>
 
 <style lang="scss">
-.el-dialog.is-fullscreen {
+.cy_dialog-v2 {
+  .el-dialog__title {
+    font-weight: 600;
+  }
+}
+
+.cy_dialog-v2.el-dialog.is-fullscreen {
   display: flex;
   flex-direction: column;
 

+ 17 - 18
src/components/cy/tree-input/CyTreeInputTest.vue

@@ -1,14 +1,17 @@
 <template>
   <CyTreeInput
-      width="220px"
-      v-model:data="jc"
-      :remote-method="getJyJcZdTree"
-      :tree-ref="treeRef">
-    <template #default="{handelFilter , treeProps }">
-      <el-tree ref="treeRef"
-               :data="jc.jc"
-               :props="treeProps('name')"
-               :filter-node-method="handelFilter">
+    width="220px"
+    v-model:data="jc"
+    :remote-method="getJyJcZdTree"
+    :tree-ref="treeRef"
+  >
+    <template #default="{ handelFilter, treeProps }">
+      <el-tree
+        ref="treeRef"
+        :data="jc.jc"
+        :props="treeProps('name')"
+        :filter-node-method="handelFilter"
+      >
       </el-tree>
     </template>
   </CyTreeInput>
@@ -16,15 +19,11 @@
 
 <script setup lang="ts">
 import CyTreeInput from "@/components/cy/tree-input/src/CyTreeInput.vue";
-import {ElTree} from "element-plus";
-import {getJyJcZdTree} from "@/api/zhu-yuan-yi-sheng/jian-yan-jian-cha-shen-qing";
-
-const treeRef = ref(null)
-const jc = ref({})
-
+import { ElTree } from "element-plus";
+import { getJyJcZdTree } from "@/api/zhu-yuan-yi-sheng/jian-yan-jian-cha-shen-qing";
 
+const treeRef = ref(null);
+const jc = ref({});
 </script>
 
-<style scoped>
-
-</style>
+<style scoped></style>

+ 134 - 77
src/components/zhu-yuan-yi-sheng/emr/emr-template/comp/PatientEmrData.vue

@@ -1,19 +1,25 @@
 <script setup lang="ts">
 import { useCompRef } from "@/utils/useCompRef";
-import { ElIcon, ElInput, ElTree } from "element-plus";
+import { ElIcon, ElInput, ElMessageBox, ElTree } from "element-plus";
 import { h, ref } from "vue";
 import { Document, Folder, Lock, Open, Sort } from "@element-plus/icons-vue";
 import { stringIsBlank } from "@/utils/blank-utils";
-import RightClickMenu from "@/components/menu-item/RightClickMenu.vue";
 import { xcMessage } from "@/utils/xiaochan-element-plus";
 import {
   emrMitt,
   isCourse,
+  patientInfo,
 } from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init";
-import { electronicMedicalRecordSequencing } from "@/api/zhu-yuan-yi-sheng/emr-patient";
+import {
+  delDir,
+  electronicMedicalRecordSequencing,
+  newDir,
+  rename,
+} from "@/api/zhu-yuan-yi-sheng/emr-patient";
 import { useDialog } from "@/components/cy/CyDialog/index";
 import AddEmrDialog from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/components/add-emr-dialog/AddEmrDialog.vue";
 import { emrRootContextKey } from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-func/useEmrStore";
+import ContextMenu from "@imengyu/vue3-context-menu";
 
 const props = defineProps<{
   treeData: any[];
@@ -21,11 +27,10 @@ const props = defineProps<{
 
 const root = inject(emrRootContextKey);
 
-const emits = defineEmits(["nodeClick"]);
+const emits = defineEmits(["nodeClick", "refresh"]);
 
 const inputValue = ref("");
 const treeRef = useCompRef(ElTree);
-const mousePosition = ref();
 
 const defaultProps = {
   children: "children",
@@ -58,7 +63,7 @@ let drag = new Map();
 const dragEnd = (moveNode, inNode, type, event) => {
   if (type === "none") return;
   let temp = {
-    newParent: inNode.data._id,
+    newParent: inNode.data.emrDocumentId,
     oldParent: moveNode.data.parent,
   };
   drag.set(moveNode.data.id, temp);
@@ -66,8 +71,8 @@ const dragEnd = (moveNode, inNode, type, event) => {
 
 const dragLimit = (moveNode, inNode, type) => {
   if (moveNode.data.jump) return false;
-  if (inNode.data._id && type === "inner") {
-    return true;
+  if (inNode.data.emrDocumentId && type === "inner") {
+    return inNode.data.type !== "category";
   }
 };
 
@@ -94,69 +99,126 @@ function isFiler(data) {
   return data.type !== "group-category";
 }
 
-const opt = [
-  {
-    name: "新建病历",
-    click: data => {
-      useDialog<any>(AddEmrDialog, {
-        dialogProps: {
-          title: `在【${data.name}】文件夹下面创建病历`,
-          top: "2%",
+const getDirName = async (title: string): Promise<string> => {
+  return ElMessageBox.prompt("文件夹名称", title, {
+    type: "info",
+    inputErrorMessage: "名称不能为空",
+    inputPattern: /\S/,
+  }).then(({ value }) => {
+    return value;
+  });
+};
+
+const contextmenuItemV2 = (e, data) => {
+  e.preventDefault();
+  e.stopPropagation();
+
+  function createVerification() {
+    if (isCourse(data.code)) {
+      return false;
+    }
+    return !isFiler(data);
+  }
+
+  const disabledChangeDir = data.data.parent === null;
+
+  ContextMenu.showContextMenu({
+    x: e.x,
+    y: e.y,
+    items: [
+      {
+        disabled: !createVerification(),
+        label: "新建文件夹",
+        onClick: async () => {
+          const name = await getDirName("新建文件夹");
+          await newDir({
+            parent: data.folderId,
+            patNo: patientInfo.value.inpatientNo,
+            times: patientInfo.value.admissTimes,
+            name: name,
+          });
+          emits("refresh");
         },
-        showConfirm: false,
-        params: {
-          templateData: [
-            ...root.store.emrTemplate.value.emrTree,
-            ...root.store.emrTemplate.value.deptTree,
-          ],
+      },
+      {
+        disabled: !createVerification(),
+        label: "新建病历",
+        onClick: () => {
+          useDialog<any>(AddEmrDialog, {
+            dialogProps: {
+              title: `在【${data.name}】文件夹下面创建病历`,
+              top: "2%",
+            },
+            showConfirm: false,
+            params: {
+              templateData: [
+                ...root.store.emrTemplate.value.emrTree,
+                ...root.store.emrTemplate.value.deptTree,
+              ],
+            },
+          }).then(res => {
+            // @ts-ignore
+            emrMitt.emit("loadTemplate", { ...res, parent: data.folderId });
+          });
         },
-      }).then(res => {
-        // @ts-ignore
-        emrMitt.emit("loadTemplate", { ...res, parent: data.folderId });
-      });
-    },
-    validator(data) {
-      if (isCourse(data.code)) {
-        return false;
-      }
-      return !isFiler(data);
-    },
-  },
-  {
-    name: "打开(只读)",
-    click: data => {
-      if (!data.id) {
-        xcMessage.error("请选中保存的病历。");
-        return;
-      }
-      emrMitt.emit("只读病历", data.id);
-    },
-    icon: h(ElIcon, {}, () => h(Open)),
-    validator: isFiler,
-  },
-  {
-    name: "确认排序",
-    click: () => {
-      let temp = [];
-      drag.forEach((value, key) => {
-        if (value.newParent !== value.oldParent) {
-          temp.push({ id: key, parent: value.newParent });
-        }
-      });
-      if (temp.length === 0) {
-        drag.clear();
-        return xcMessage.error("文件夹没有变化,无需点击。");
-      }
-      electronicMedicalRecordSequencing(temp).then(() => {
-        drag.clear();
-      });
-    },
-    validator: () => {
-      return drag.size > 0;
-    },
-    icon: h(ElIcon, {}, () => h(Sort)),
-  },
-];
+      },
+      {
+        label: "打开(只读)",
+        onClick: () => {
+          if (!data.id) {
+            xcMessage.error("请选中保存的病历。");
+            return;
+          }
+          emrMitt.emit("只读病历", data.id);
+        },
+        icon: h(ElIcon, {}, () => h(Open)),
+        disabled: !isFiler(data),
+      },
+      {
+        label: "确认排序",
+        onClick: () => {
+          let temp = [];
+          drag.forEach((value, key) => {
+            if (value.newParent !== value.oldParent) {
+              temp.push({ id: key, parent: value.newParent });
+            }
+          });
+          if (temp.length === 0) {
+            drag.clear();
+            return xcMessage.error("文件夹没有变化,无需点击。");
+          }
+          electronicMedicalRecordSequencing(temp).then(() => {
+            drag.clear();
+          });
+        },
+        disabled: drag.size === 0,
+        icon: h(ElIcon, {}, () => h(Sort)),
+      },
+      {
+        label: "修改文件夹名称",
+        onClick: async () => {
+          const name = await getDirName("重命名");
+          await rename(name, data.id);
+          emits("refresh");
+        },
+        disabled: disabledChangeDir,
+      },
+      {
+        label: "删除文件夹",
+        onClick: async () => {
+          await ElMessageBox.confirm(
+            "是否删除该文件夹,里面的病历并不会删除",
+            "删除",
+            { type: "error" }
+          );
+          await delDir(data.id);
+          emits("refresh");
+        },
+        disabled: disabledChangeDir,
+      },
+    ],
+  });
+};
 
 const contextmenuItem = (event, data) => {
   let tempData = {
@@ -167,14 +229,10 @@ const contextmenuItem = (event, data) => {
     name: data.name ? data.name : data.emrName,
     parent: data.parent,
     type: data.type,
-    folderId: data.id,
+    folderId: data.emrDocumentId,
     data: data,
   };
-  mousePosition.value = {
-    event,
-    index: 0,
-    data: tempData,
-  };
+  contextmenuItemV2(event, tempData);
 };
 
 const nullToEmpty = val => {
@@ -187,7 +245,6 @@ const fileName = val => {
 </script>
 
 <template>
-  <right-click-menu :mouse-position="mousePosition" :config="opt" />
   <div class="layout_container">
     <div>
       <el-input
@@ -203,7 +260,7 @@ const fileName = val => {
         :data="props.treeData"
         :props="defaultProps"
         @node-click="handleNodeClick"
-        node-key="_id"
+        node-key="emrDocumentId"
         ref="treeRef"
         draggable
         @node-drag-end="dragEnd"

+ 47 - 44
src/main.js

@@ -1,63 +1,66 @@
-import {createApp} from 'vue'
-import ElementPlus, {useZIndex, ClickOutside, TrapFocus} from 'element-plus'
-import 'element-plus/dist/index.css'
-import 'element-plus/theme-chalk/dark/css-vars.css'
-import 'normalize.css' // css初始化
-import '../src/css/app.scss' // 公共css
-import App from './App.vue'
-import router from './router'
-import * as ElementPlusIconsVue from '@element-plus/icons-vue'
-import zhCn from 'element-plus/es/locale/lang/zh-cn'
+import { createApp } from "vue";
+import ElementPlus, { useZIndex, ClickOutside, TrapFocus } from "element-plus";
+import "element-plus/dist/index.css";
+import "element-plus/theme-chalk/dark/css-vars.css";
+import "normalize.css"; // css初始化
+import "../src/css/app.scss"; // 公共css
+import App from "./App.vue";
+import router from "./router";
+import * as ElementPlusIconsVue from "@element-plus/icons-vue";
+import zhCn from "element-plus/es/locale/lang/zh-cn";
 import JsonViewer from "vue3-json-viewer";
 import "vue3-json-viewer/dist/index.css";
-import DataVVue3 from '@kjgl77/datav-vue3'
-import VXETable from 'vxe-table'
-import 'vxe-table/lib/style.css'
-import print from 'vue3-print-nb'
+import DataVVue3 from "@kjgl77/datav-vue3";
+import VXETable from "vxe-table";
+import "vxe-table/lib/style.css";
+import print from "vue3-print-nb";
 import VElBtn from "@/directives/v-el-btn";
 import VTitle from "@/directives/v-title";
 import "driver.js/dist/driver.css";
-import DomZIndex from 'dom-zindex'
+import DomZIndex from "dom-zindex";
 import initVxeConfig from "@/utils/xe-utils-enhance/vxe-formatter";
 import VWaves from "@/directives/v-waves";
 import piniaInstall from "@/pinia/pinia-install";
-import VxeUIPluginRenderChart from '@vxe-ui/plugin-render-chart'
-import '@vxe-ui/plugin-render-chart/dist/style.css'
-import VxeUI from 'vxe-pc-ui'
-import 'vxe-pc-ui/lib/style.css'
-import VxeUIPluginExportXLSX from '@vxe-ui/plugin-export-xlsx'
-import ExcelJS from 'exceljs'
+import VxeUIPluginRenderChart from "@vxe-ui/plugin-render-chart";
+import "@vxe-ui/plugin-render-chart/dist/style.css";
+import VxeUI from "vxe-pc-ui";
+import "vxe-pc-ui/lib/style.css";
+import VxeUIPluginExportXLSX from "@vxe-ui/plugin-export-xlsx";
+import ExcelJS from "exceljs";
+import "@imengyu/vue3-context-menu/lib/vue3-context-menu.css";
+import ContextMenu from "@imengyu/vue3-context-menu";
 
 DomZIndex.getNext = () => {
-    return useZIndex().nextZIndex()
-}
+  return useZIndex().nextZIndex();
+};
 
 DomZIndex.getCurrent = () => {
-    return useZIndex().currentZIndex.value
-}
+  return useZIndex().currentZIndex.value;
+};
 
-initVxeConfig()
+initVxeConfig();
 
-const app = createApp(App)
+const app = createApp(App);
 for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
-    app.component(key, component)
+  app.component(key, component);
 }
 
-piniaInstall(app)
-app.use(ElementPlus, {locale: zhCn, size: 'small'})
-app.use(DataVVue3)
-app.directive('el-btn', VElBtn)
-app.directive('title', VTitle)
-app.directive('ClickOutside', ClickOutside)
-app.directive('Waves', VWaves)
-app.directive('TrapFocus', TrapFocus)
-app.use(print)
-app.use(VxeUI)
-app.use(VXETable)
-VxeUI.use(VxeUIPluginRenderChart)
+piniaInstall(app);
+app.use(ElementPlus, { locale: zhCn, size: "small" });
+app.use(DataVVue3);
+app.directive("el-btn", VElBtn);
+app.directive("title", VTitle);
+app.directive("ClickOutside", ClickOutside);
+app.directive("Waves", VWaves);
+app.directive("TrapFocus", TrapFocus);
+app.use(print);
+app.use(VxeUI);
+app.use(VXETable);
+VxeUI.use(VxeUIPluginRenderChart);
 VxeUI.use(VxeUIPluginExportXLSX, {
-    ExcelJS
-})
+  ExcelJS,
+});
+app.use(ContextMenu);
 app.use(JsonViewer);
-app.use(router)
-app.mount('#app')
+app.use(router);
+app.mount("#app");

+ 94 - 0
src/views/archive/ArchiveAside.vue

@@ -0,0 +1,94 @@
+<script setup lang="tsx">
+import { Document, Files } from "@element-plus/icons-vue";
+import { useArchiveKey } from "@/views/archive/index";
+import { ElTree } from "element-plus";
+import MagicResizer from "@/components/cy/magic-resizer.vue";
+import { PatientArchive } from "@/api/archive/archive-api";
+import CyTreeInput from "@/components/cy/tree-input/src/CyTreeInput.vue";
+import ContextMenu from "@imengyu/vue3-context-menu";
+
+const root = inject(useArchiveKey);
+const treeRef = ref(ElTree);
+
+const defaultProps = {
+  children: "children",
+  label: "name",
+};
+
+function handleNodeClick(node: PatientArchive) {
+  root.mutation.setPdfUrl(node.path);
+}
+
+function allowDrop(draggingNode, dropNode, type) {
+  return !(type === "inner" && dropNode.data.isDir === false);
+}
+
+function contextmenu(e: any, data: PatientArchive, _node: any, _n: any) {
+  e.preventDefault();
+  ContextMenu.showContextMenu({
+    x: e.x,
+    y: e.y,
+    items: [
+      {
+        label: "新增文件夹",
+        disabled: !data.isDir,
+        onClick: () => {
+          console.log(data);
+        },
+      },
+    ],
+  });
+}
+</script>
+
+<template>
+  <div style="padding: 10px">
+    <magic-resizer
+      :value="300"
+      :max="600"
+      :min="300"
+      direction="x"
+      class="archive-resizer"
+      @contextmenu="contextmenu($event, { isDir: true, id: null }, null, null)"
+    >
+      <cy-tree-input :tree-ref="treeRef" :remote-method="root.mutation.getData">
+        <template #default="{ handelFilter, treeProps }">
+          <el-tree
+            ref="treeRef"
+            class="archive_aside"
+            :data="root.store.treeList"
+            highlight-current
+            draggable
+            :allow-drop="allowDrop"
+            :filter-node-method="handelFilter"
+            node-key="id"
+            :props="defaultProps"
+            @node-contextmenu="contextmenu"
+            @node-click="handleNodeClick"
+          >
+            <template #default="{ data }">
+              <el-icon>
+                <Files v-if="data.isDir" />
+                <Document v-else />
+              </el-icon>
+              &nbsp;&nbsp;{{ data.name }}
+            </template>
+          </el-tree>
+        </template>
+      </cy-tree-input>
+    </magic-resizer>
+  </div>
+</template>
+
+<style lang="scss">
+.archive-resizer {
+  height: 100%;
+  background: white;
+}
+
+.archive_aside {
+  padding: 10px;
+  background: white;
+  width: 100%;
+}
+</style>

+ 24 - 0
src/views/archive/ArchiveMain.vue

@@ -0,0 +1,24 @@
+<script setup lang="ts">
+import { useArchiveKey } from "@/views/archive/index";
+
+const root = inject(useArchiveKey);
+</script>
+
+<template>
+  <div class="archive_main">
+    <iframe :src="root.store.pdfUrl" />
+  </div>
+</template>
+
+<style lang="scss">
+.archive_main {
+  background: white;
+  width: 100%;
+  height: 100%;
+
+  iframe {
+    width: 100%;
+    height: 100%;
+  }
+}
+</style>

+ 0 - 29
src/views/archive/aside.vue

@@ -1,29 +0,0 @@
-<script setup lang="ts">
-import { useArchiveKey } from "@/views/archive/index";
-import Tree from "./no-archive/index.vue";
-
-const root = inject(useArchiveKey);
-</script>
-
-<template>
-  <aside style="width: 220px">
-    <el-tabs
-      v-model="root.store.leftTreeModel"
-      class="el-tabs__fill emr-archive-tabs"
-      type="border-card"
-    >
-      <el-tab-pane label="当前" name="current">
-        <Tree />
-      </el-tab-pane>
-      <el-tab-pane label="归档" name="archive"></el-tab-pane>
-    </el-tabs>
-  </aside>
-</template>
-
-<style lang="scss">
-.emr-archive-tabs {
-  > .el-tabs__content {
-    padding: 5px;
-  }
-}
-</style>

+ 0 - 56
src/views/archive/components/JianYan.vue

@@ -1,56 +0,0 @@
-<script setup lang="tsx">
-import { useArchiveKey } from "@/views/archive/index";
-import { magicApi } from "@/utils/database/magic-api-request";
-
-const root = inject(useArchiveKey);
-
-async function handleClick(data) {
-  const res = await magicApi({
-    url: "/intergration/jyjc/getJyImage",
-    method: "get",
-    params: {
-      reportId: data.reportId,
-    },
-  });
-
-  root.store.mainComponent = (
-    <div>
-      {...res.items.map(item => {
-        return (
-          <img
-            src={`data:image/png;base64,${item.imgData}`}
-            style={{ width: "100%" }}
-            alt="null"
-          />
-        );
-      })}
-    </div>
-  );
-}
-
-const Table = props => {
-  return (
-    <div style={{ height: "50%" }}>
-      <el-table data={props.data} height="100%" onRowClick={handleClick}>
-        <el-table-column label={props.name}>
-          <el-table-column prop="trscDate" label="日期" />
-          <el-table-column
-            prop="examPurpose"
-            label="名称"
-            show-overflow-tooltip
-          />
-        </el-table-column>
-      </el-table>
-    </div>
-  );
-};
-</script>
-
-<template>
-  <div style="width: 220px">
-    <Table name="常规" :data="root.cache.jianYan.biochemicalSingle" />
-    <Table name="生化单" :data="root.cache.jianYan.routine" />
-  </div>
-</template>
-
-<style lang="scss"></style>

+ 33 - 32
src/views/archive/index.ts

@@ -1,8 +1,6 @@
 import type { InjectionKey } from "vue";
-import {
-  getNormal,
-  SidebarData,
-} from "@/api/jian-yan-jie-kou/jian-yan-jie-kou";
+import { getPatientAll } from "@/api/inpatient/patient";
+import { getPatientArchives, PatientArchive } from "@/api/archive/archive-api";
 import XEUtils from "xe-utils";
 
 type PatInfo = {
@@ -12,43 +10,46 @@ type PatInfo = {
 
 export const useArchive = () => {
   const store = reactive({
-    leftTreeModel: "current",
-    mainComponent: null,
-    leftComponent: null,
     patNo: "",
     times: 0,
     patInfo: {} as PatInfo,
+    treeList: [] as PatientArchive[],
+    pdfUrl: "",
   });
 
-  const cache = reactive({
-    jianYan: null as {
-      routine: SidebarData[];
-      biochemicalSingle: SidebarData[];
+  const mutation = {
+    async getData() {
+      store.treeList = await getPatientArchives(store.patNo, store.times);
     },
-  });
+    setPatInfo(patInfo: string) {
+      const split = patInfo.split("_");
+      store.patNo = split[0];
+      store.times = XEUtils.toNumber(split[1]);
+      getPatientAll(store.patNo, store.times).then(res => {
+        store.patInfo = res as any;
+        this.getData();
+      });
+    },
+    setPdfUrl(url: string) {
+      store.pdfUrl = url;
+    },
+    sort() {
+      function forEach(data: PatientArchive[]) {
+        data.forEach((item, index) => {
+          item.sort = index;
+          if (item.children !== null && item.children.length > 0) {
+            forEach(item.children);
+          }
+        });
+      }
+
+      forEach(store.treeList);
+    },
+  };
 
-  return { store, cache };
+  return { store, mutation };
 };
 
 type UseArchive = ReturnType<typeof useArchive>;
 
 export const useArchiveKey: InjectionKey<UseArchive> = Symbol("useArchiveKey");
-
-export async function queryJianYan(data) {
-  const 常规 = [];
-  const 生化单 = [];
-  const 生化名称 = ["血细胞分析(五分类)", "尿液分析"];
-  const res = await getNormal(data);
-  XEUtils.arrayEach(res, item => {
-    if (生化名称.includes(item.examPurpose)) {
-      生化单.push(item);
-    } else {
-      常规.push(item);
-    }
-  });
-
-  return {
-    routine: XEUtils.orderBy(常规, [["trscDate", "asc"]]),
-    biochemicalSingle: XEUtils.orderBy(生化单, [["trscDate", "asc"]]),
-  };
-}

+ 17 - 29
src/views/archive/index.vue

@@ -1,40 +1,21 @@
 <script setup lang="tsx">
 import { useArchive, useArchiveKey } from "@/views/archive/index";
-import Aside from "./aside.vue";
+import ArchiveAside from "./ArchiveAside.vue";
 import router from "@/router";
 import XEUtils from "xe-utils";
 import { stringNotBlank } from "@/utils/blank-utils";
-import { getPatientAll } from "@/api/inpatient/patient";
+import ArchiveMain from "@/views/archive/ArchiveMain.vue";
 
-const store = useArchive();
+const root = useArchive();
 
-provide(useArchiveKey, store);
-
-const mainComp = computed(() => {
-  if (store.store.mainComponent) {
-    return store.store.mainComponent;
-  }
-  return <div></div>;
-});
-
-const leftComp = computed(() => {
-  if (store.store.leftComponent) {
-    return store.store.leftComponent;
-  }
-  return <div></div>;
-});
+provide(useArchiveKey, root);
 
 watch(
   () => router.currentRoute.value,
   newValue => {
     const patInfo = XEUtils.get(newValue, "params.patInfo") as string;
     if (stringNotBlank(patInfo)) {
-      const split = patInfo.split("_");
-      store.store.patNo = split[0];
-      store.store.times = split[1];
-      getPatientAll(store.store.patNo, store.store.times).then(res => {
-        store.store.patInfo = res;
-      });
+      root.mutation.setPatInfo(patInfo);
     }
   },
   { immediate: true }
@@ -43,13 +24,20 @@ watch(
 
 <template>
   <div class="layout_container">
-    <header>asdasd</header>
+    <header class="archive_header">
+      <el-button @click="root.mutation.sort">确认排序</el-button>
+    </header>
     <div class="layout_main layout_container layout-horizontal">
-      <Aside />
-      <div class="layout_main">
-        <Component :is="mainComp" />
+      <ArchiveAside />
+      <div class="layout_main" style="padding: 10px">
+        <ArchiveMain />
       </div>
-      <Component :is="leftComp" style="margin-left: 10px" />
     </div>
   </div>
 </template>
+
+<style lang="scss">
+.archive_header {
+  padding: 10px 10px 0 10px;
+}
+</style>

+ 0 - 93
src/views/archive/no-archive/index.vue

@@ -1,93 +0,0 @@
-<script setup lang="tsx">
-import { Document, Files } from "@element-plus/icons-vue";
-import { queryJianYan, useArchiveKey } from "@/views/archive/index";
-import EmrFirstPageOfMedicalRecord from "@/components/zhu-yuan-yi-sheng/emr/EmrFirstPageOfMedicalRecord.vue";
-import { defineAsyncComponent } from "vue";
-import XEUtils from "xe-utils";
-import { ElTree } from "element-plus";
-
-const JianYan = defineAsyncComponent(() => import("../components/JianYan.vue"));
-
-type Tree = {
-  id: string;
-  name: string;
-  children: Tree[];
-  isDir: boolean;
-  components?: any;
-  callback?: () => void;
-};
-
-const root = inject(useArchiveKey);
-
-const dataTree = ref<Tree[]>([
-  {
-    id: "病案首页",
-    name: "病案首页",
-    children: [],
-    isDir: false,
-    components: (
-      <EmrFirstPageOfMedicalRecord
-        queryData={{
-          bah: root.store.patNo,
-          times: root.store.times,
-          inOutFlag: 2,
-        }}
-      />
-    ),
-  },
-  {
-    id: "入院",
-    name: "待开发",
-    children: [],
-    isDir: false,
-  },
-  {
-    id: "检验结果单",
-    name: "检验结果单",
-    isDir: true,
-    children: [],
-    callback: async () => {
-      if (XEUtils.isEmpty(root.cache.jianYan)) {
-        const data = await queryJianYan({
-          patientNum: root.store.patNo,
-          startDate: root.store.patInfo.admissDate,
-          endDate: root.store.patInfo.disDate,
-        });
-        root.cache.jianYan = data;
-      }
-      root.store.leftComponent = shallowRef(JianYan);
-    },
-  },
-]);
-
-const defaultProps = {
-  children: "children",
-  label: "name",
-};
-
-function handleNodeClick(node: Tree) {
-  root.store.mainComponent = node.components;
-  root.store.leftComponent = null;
-  node?.callback?.();
-}
-</script>
-
-<template>
-  <el-tree
-    :data="dataTree"
-    highlight-current
-    node-key="id"
-    :props="defaultProps"
-    @node-click="handleNodeClick"
-  >
-    <template #default="{ data }">
-      <el-icon>
-        <Files v-if="data.isDir" />
-        <Document v-else />
-      </el-icon>
-      &nbsp;&nbsp;{{ data.name }}
-    </template>
-  </el-tree>
-</template>
-
-<style lang="scss"></style>

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

@@ -1663,14 +1663,14 @@ function beforeRevisionAccept(evt, data) {
     const values = parsingFragmentDataElements(editor, area.model);
     const { code } = getBcjlUserInfo(values);
     if (code === userInfo.code) {
-      return true;
+      return false;
     } else {
-      xcMessage.error("片段你创建的无法使用此功能。");
+      xcMessage.error("片段不是你创建的无法使用此功能。");
       return false;
     }
   } else {
     if (createId.value === userInfo.code) {
-      return true;
+      return false;
     } else {
       xcMessage.error("病历不是你创建的无法使用此功能。");
       return false;

+ 1 - 0
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/components/EmrSidebar.tsx

@@ -383,6 +383,7 @@ const EmrSidebar = defineComponent({
           </TabPaneResizer>
           <TabPaneResizer label="当前" name={2}>
             <PatientEmrData
+              onRefresh={queryData}
               onNodeClick={saveEmr}
               treeData={returnData.value.patientTree}
             />

+ 7 - 0
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/components/emr-function/EmrFunctionList.vue

@@ -148,6 +148,13 @@ const emrFunction: { [key: string]: FunctionList } = {
     name: "审阅",
     iconfontName: "shenyue",
     dropdown: [
+      {
+        name: "关闭",
+        title: "关闭审阅模式",
+        click() {
+          setRevisionShowMode(RevisionShowMode.不显示);
+        },
+      },
       {
         name: "嵌入模式",
         title: "开启后会在病历中会有其他医生的修改痕迹,默认开启",

+ 4 - 1
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/plugins/opinion/useEmrAudit.ts

@@ -8,6 +8,7 @@ import {
   EmrRightTabs,
 } from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init";
 import { emrRootContextKey } from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-func/useEmrStore";
+import sleep from "@/utils/sleep";
 
 export enum AuditType {
   记录,
@@ -37,7 +38,9 @@ export function useEmrAuditV2() {
         for (let i = 0; i < res.length; i++) {
           const item = res[i];
           if (item.remediationStatus == null) {
-            root.store.store.right = EmrRightTabs.opinion;
+            sleep(1000).then(() => {
+              root.store.store.right = EmrRightTabs.opinion;
+            });
             return;
           }
         }

+ 6 - 1
vite.config.js

@@ -60,7 +60,12 @@ export default defineConfig({
         target: "http://172.16.32.167:8077",
         secure: false, //如果运行时服务是https,此处配置为true
         changeOrigin: true, //支持跨域调用,这里配置为true
-        rewrite: path => path.replace(/^\/emr/, ""),
+      },
+      "/thyyemrpdfserver": {
+        target: "http://172.16.32.197:9202/archive-test/emr",
+        secure: false,
+        changeOrigin: true,
+        rewrite: path => path.replace(/^\/thyyemrpdfserver/, ""),
       },
     },
   },