Browse Source

新增查询整改的页面,现在删除电子病历的质控意见

xiaochan 5 tháng trước cách đây
mục cha
commit
82ab094088
18 tập tin đã thay đổi với 1108 bổ sung791 xóa
  1. 72 66
      src/api/emr-control/request.ts
  2. 9 1
      src/api/zhu-yuan-yi-sheng/emr-audit.ts
  3. 27 27
      src/components/cy/date-range/CyDateRange.vue
  4. 1 1
      src/components/zhu-yuan-yi-sheng/yi-zhu-lu-ru/report-of-infectious-diseases/DialogDiseases.vue
  5. 1 9
      src/directives/v-el-btn.ts
  6. 68 55
      src/layout/MenuV2/MenuV2.vue
  7. 144 144
      src/router/index.ts
  8. 0 11
      src/views/emr-manage/DynamicDataObjects.vue
  9. 115 0
      src/views/emr-manage/query-centre/rectify/index.vue
  10. 47 0
      src/views/emr-manage/query-centre/various-rate/QueryParams.vue
  11. 100 0
      src/views/emr-manage/query-centre/various-rate/index.vue
  12. 313 300
      src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/EmrMain.vue
  13. 98 96
      src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/Home.vue
  14. 6 6
      src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/plugins/opinion/AuditDisplayComponent.vue
  15. 25 5
      src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/plugins/opinion/AuditRecord.vue
  16. 78 70
      src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/plugins/opinion/SendAudit.vue
  17. 2 0
      src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr_control_rule/RuleSift.vue
  18. 2 0
      src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/final-quality-control/FinalQualityControl.vue

+ 72 - 66
src/api/emr-control/request.ts

@@ -1,85 +1,91 @@
-import axios, { AxiosRequestConfig } from "axios";
-import { ElMessage, ElMessageBox } from "element-plus";
+import axios, {AxiosRequestConfig} from "axios";
+import {ElMessage, ElMessageBox} from "element-plus";
 import env from "@/utils/setting";
 
 const service = axios.create({
-  // @ts-ignore
-  baseURL: "http://" + env.VITE_EMR_CONTROL_URL,
-  withCredentials: true,
-  timeout: 0,
+    // @ts-ignore
+    baseURL: "http://" + env.VITE_EMR_CONTROL_URL,
+    withCredentials: true,
+    timeout: 0,
 });
 
 service.interceptors.request.use(
-  config => {
-    if (localStorage.token) {
-      config.headers["token"] = localStorage.token;
+    config => {
+        if (localStorage.token) {
+            config.headers["token"] = localStorage.token;
+        }
+        return config;
+    },
+    error => {
+        return Promise.reject(error);
     }
-    return config;
-  },
-  error => {
-    return Promise.reject(error);
-  }
 );
 
 service.interceptors.response.use(
-  response => {
-    if (response.data.code === 200 || response.data.code === 0) {
-      return response.data.data;
-    }
-    if (response.data.code === 201) {
-      ElMessage({
-        type: "success",
-        duration: 2800,
-        dangerouslyUseHTMLString: true,
-        message: response.data.message,
-        showClose: true,
-      });
-      return response.data.data;
-    }
-    if (response.data.code === 5000) {
-      ElMessage({
-        type: "error",
-        duration: 2800,
-        message: response.data.message,
-        showClose: true,
-      });
-    }
+    response => {
+        if (response.data.code === 200 || response.data.code === 0) {
+            return response.data.data;
+        }
+        if (response.data.code === 201) {
+            ElMessage({
+                type: "success",
+                duration: 2800,
+                dangerouslyUseHTMLString: true,
+                message: response.data.message,
+                showClose: true,
+            });
+            return response.data.data;
+        }
+        if (response.data.code === 5000) {
+            ElMessage({
+                type: "error",
+                duration: 2800,
+                message: response.data.message,
+                showClose: true,
+            });
+        }
 
-    if (response.data.code === 5001) {
-      ElMessageBox.alert(response.data.message, "提示", {
-        type: "warning",
-        confirmButtonText: "确定",
-        showClose: false,
-      })
-        .then(() => {})
-        .catch(() => {});
-    }
+        if (response.data.code === 5001) {
+            ElMessageBox.alert(response.data.message, "提示", {
+                type: "warning",
+                confirmButtonText: "确定",
+                showClose: false,
+            })
+                .then(() => {
+                })
+                .catch(() => {
+                });
+        }
 
-    if (response.data.code === 6001) {
-      ElMessage({
-        message: response.data.message,
-        type: "error",
-        duration: 2500,
-        showClose: true,
-        grouping: true,
-      });
-      return {
-        error: true,
-        data: response.data.data,
-      };
+        if (response.data.code === 6001) {
+            ElMessage({
+                message: response.data.message,
+                type: "error",
+                duration: 2500,
+                showClose: true,
+                grouping: true,
+            });
+            return {
+                error: true,
+                data: response.data.data,
+            };
+        }
+        return Promise.reject(response.data.message || "服务器内部错误");
+    },
+    error => {
+        // 超出 2xx 范围的状态码都会触发该函数。
+        // 对响应错误做点什么
+        return Promise.reject(error);
     }
-    return Promise.reject(response.data.message || "服务器内部错误");
-  },
-  error => {
-    // 超出 2xx 范围的状态码都会触发该函数。
-    // 对响应错误做点什么
-    return Promise.reject(error);
-  }
 );
 
 const request = <D = any>(params: AxiosRequestConfig): Promise<D> => {
-  // @ts-ignore
-  return service(params);
+    // @ts-ignore
+    return service(params);
 };
 
+export {
+    request as emrServerHttp
+}
+
 export default request;

+ 9 - 1
src/api/zhu-yuan-yi-sheng/emr-audit.ts

@@ -44,7 +44,7 @@ export function setAudit(data: any) {
     })
 }
 
-export function rectifyMedicalRecords(id: string, state: number) {
+export function rectifyMedicalRecords(id: number, state: number) {
     return requestV2({
         url: URL + '/rectifyMedicalRecords',
         method: 'get',
@@ -84,3 +84,11 @@ export function getEmrAuditByEmrId(data: any) {
         data
     })
 }
+
+export function deleteEmrAuditByEmrId(id: number) {
+    return requestV2({
+        url: URL + '/deleteEmrAuditByEmrId',
+        method: 'get',
+        params: {id}
+    })
+}

+ 27 - 27
src/components/cy/date-range/CyDateRange.vue

@@ -1,6 +1,6 @@
 <script setup lang="ts">
-import { ElDatePicker } from "element-plus";
-import { listNotBlank } from "@/utils/blank-utils";
+import {ElDatePicker} from "element-plus";
+import {listNotBlank} from "@/utils/blank-utils";
 import {
   DATEFORMAT,
   elDateRangeAddTime,
@@ -8,8 +8,8 @@ import {
 } from "@/utils/moment-utils";
 import moment from "moment/moment";
 import XEUtils from "xe-utils";
-import { WritableComputedRef } from "vue";
-import { useVModel } from "@vueuse/core";
+import {WritableComputedRef} from "vue";
+import {useVModel} from "@vueuse/core";
 
 const shortcuts = [
   {
@@ -47,21 +47,21 @@ const shortcuts = [
 ];
 
 const props = withDefaults(
-  defineProps<{
-    modelValue?: any;
-    start?: string;
-    end?: string;
-    clearable?: boolean;
-    unlinkPanels?: boolean;
-    shortcutsIndex?: number | null;
-  }>(),
-  {
-    start: "startTime",
-    end: "endTime",
-    clearable: true,
-    unlinkPanels: true,
-    shortcutsIndex: null,
-  }
+    defineProps<{
+      modelValue?: any;
+      start?: string;
+      end?: string;
+      clearable?: boolean;
+      unlinkPanels?: boolean;
+      shortcutsIndex?: number | null;
+    }>(),
+    {
+      start: "startTime",
+      end: "endTime",
+      clearable: true,
+      unlinkPanels: true,
+      shortcutsIndex: null,
+    }
 );
 
 const emits = defineEmits(["update:modelValue"]);
@@ -87,9 +87,9 @@ const dateRange: WritableComputedRef<string[]> = computed({
     }
   },
   set(value: string[]) {
-    const { start, end } = elDateRangeAddTime(value);
+    const {start, end} = elDateRangeAddTime(value);
     if (isArr) {
-      model.value = [start, end];
+      model.value = value === null ? null : [start, end];
     } else {
       // @ts-ignore
       model.value[props.start] = start;
@@ -109,12 +109,12 @@ onMounted(() => {
 
 <template>
   <el-date-picker
-    v-model="dateRange"
-    :unlinkPanels
-    :shortcuts
-    :clearable
-    type="daterange"
-    style="display: inline-flex; vertical-align: middle; width: 220px"
+      v-model="dateRange"
+      :unlinkPanels
+      :shortcuts
+      :clearable
+      type="daterange"
+      style="display: inline-flex; vertical-align: middle; width: 220px"
   />
 </template>
 

+ 1 - 1
src/components/zhu-yuan-yi-sheng/yi-zhu-lu-ru/report-of-infectious-diseases/DialogDiseases.vue

@@ -17,7 +17,7 @@
                     formatter="formatDate"/>
         <vxe-column>
           <template #default="{row}">
-            <el-button v-el-btn="{func: deleteClick, value: row}" type="danger">删除</el-button>
+            <el-button v-el-btn="() => deleteClick(row) " type="danger">删除</el-button>
           </template>
         </vxe-column>
       </vxe-table>

+ 1 - 9
src/directives/v-el-btn.ts

@@ -7,15 +7,7 @@ const VElBtn = {
         /**
          * 这里有个 bug 如果使用了 v-loading 的话有问题
          * 这个函数一定要是 promise 函数
-         * 如果这个函数需要参数的话,需要:
-         * <el-button v-el-btn="{
-         *     func : a ,
-         *     value: true
-         *   }">测试 </el-button> 这样写
-         *
-         *   无参函数:
          *   <el-button v-el-btn="a">测试</el-button>
-         *
          * @param ev 事件
          */
         el.addEventListener('click', async (ev: Event) => {
@@ -34,7 +26,7 @@ const VElBtn = {
             vnode.ref.i.props.loading = true
             el.setAttribute(loadingName, 'true')
             try {
-                await binding.value.func ? binding.value.func(binding.value.value) : binding.value()
+                await binding.value()
             } finally {
                 await finallyFunc()
             }

+ 68 - 55
src/layout/MenuV2/MenuV2.vue

@@ -2,29 +2,30 @@
   <div class="floating">
     <div style="height: 30px; padding: 0 8px 8px 8px" @click="expandMenu">
       <el-input
-        ref="searchRef"
-        v-model="menuText"
-        prefix-icon="Search"
-        clearable
-        @input="searchInput"
-        placeholder="菜单太难找?在这里搜索。"
+          ref="searchRef"
+          v-model="menuText"
+          prefix-icon="Search"
+          clearable
+          @input="searchInput"
+          placeholder="菜单太难找?在这里搜索。"
       />
     </div>
 
     <div class="layout_flex_1-y">
       <el-scrollbar>
         <el-menu
-          ref="menuRef"
-          :collapse-transition="false"
-          :collapse="isCollapse"
-          :default-active="isSearch ? '' : activeMenu"
-          :unique-opened="isSearch ? false : expandOneMenu"
+            ref="menuRef"
+            popper-class="pure-scrollbar"
+            :collapse-transition="false"
+            :collapse="isCollapse"
+            :default-active="isSearch ? '' : activeMenu"
+            :unique-opened="isSearch ? false : expandOneMenu"
         >
           <template v-for="item in isSearch ? searchData : menuData">
             <menu-item-v2
-              :data="item"
-              v-if="item?.metaShowMenu"
-              :menuText="menuText"
+                :data="item"
+                v-if="item?.metaShowMenu"
+                :menuText="menuText"
             />
           </template>
         </el-menu>
@@ -35,15 +36,15 @@
 
 <script setup lang="ts">
 import MenuItemV2 from "./MenuItemV2.vue";
-import { computed, nextTick, onMounted, Ref, ref, watch } from "vue";
-import { useRoute } from "vue-router";
+import {computed, nextTick, onMounted, Ref, ref, watch} from "vue";
+import {useRoute} from "vue-router";
 import XEUtils from "xe-utils";
-import router, { routerMenus } from "@/router";
+import router, {routerMenus} from "@/router";
 import sleep from "@/utils/sleep";
-import { useCompRef } from "@/utils/useCompRef";
-import { ElMenu } from "element-plus";
-import { useSystemStore } from "@/pinia/system-store";
-import { stringNotBlank } from "@/utils/blank-utils";
+import {useCompRef} from "@/utils/useCompRef";
+import {ElMenu} from "element-plus";
+import {useSystemStore} from "@/pinia/system-store";
+import {stringNotBlank} from "@/utils/blank-utils";
 
 defineProps<{
   type: "default" | "fillet";
@@ -59,29 +60,29 @@ const searchData = ref([]);
 const searchActives = new Set();
 
 const searchInput: (val: string) => void = XEUtils.debounce(
-  async (val: string) => {
-    menuText.value = val;
-    searchActives.clear();
-
-    if (val) {
-      searchData.value = XEUtils.treeSearch(menuData.value, item => {
-        const { metaTitle } = item;
-        if (stringNotBlank(metaTitle)) {
-          return metaTitle.includes(val);
-        }
-        return false;
-      });
-      isSearch.value = true;
-      await nextTick();
-      expandNodes(searchData.value);
-    } else {
-      searchData.value = [];
-      await nextTick();
-      isSearch.value = false;
-      smoothScrolling();
-    }
-  },
-  500
+    async (val: string) => {
+      menuText.value = val;
+      searchActives.clear();
+
+      if (val) {
+        searchData.value = XEUtils.treeSearch(menuData.value, item => {
+          const {metaTitle} = item;
+          if (stringNotBlank(metaTitle)) {
+            return metaTitle.includes(val);
+          }
+          return false;
+        });
+        isSearch.value = true;
+        await nextTick();
+        expandNodes(searchData.value);
+      } else {
+        searchData.value = [];
+        await nextTick();
+        isSearch.value = false;
+        smoothScrolling();
+      }
+    },
+    500
 );
 
 const expandNodes = treeData => {
@@ -106,7 +107,8 @@ const menuLaunch = async (path: string) => {
     try {
       // @ts-ignore
       div!.click();
-    } catch (e) {}
+    } catch (e) {
+    }
   }
 };
 
@@ -127,7 +129,7 @@ const expandMenu = () => {
 const searchRef: Ref<HTMLHeadElement | null> = ref(null);
 
 const activeMenu = computed<string>(() => {
-  const { meta, path } = route;
+  const {meta, path} = route;
   if (meta["activeMenu"]) {
     return meta["activeMenu"] as string;
   }
@@ -136,7 +138,7 @@ const activeMenu = computed<string>(() => {
 
 const smoothScrolling = () => {
   const routerPath = document.getElementById(
-    <string>router.currentRoute.value.name
+      <string>router.currentRoute.value.name
   );
   if (!routerPath) return;
   routerPath.scrollIntoView({
@@ -147,14 +149,14 @@ const smoothScrolling = () => {
 };
 
 watch(
-  () => router.currentRoute.value,
-  async () => {
-    menuText.value = "";
-    isSearch.value = false;
-    await nextTick();
-    await sleep(200);
-    smoothScrolling();
-  }
+    () => router.currentRoute.value,
+    async () => {
+      menuText.value = "";
+      isSearch.value = false;
+      await nextTick();
+      await sleep(200);
+      smoothScrolling();
+    }
 );
 
 onMounted(async () => {
@@ -185,4 +187,15 @@ onMounted(async () => {
 :deep(.el-sub-menu__title) {
   padding: 0 16px;
 }
+
+</style>
+<style>
+.el-popper.pure-scrollbar {
+  overflow: hidden;
+}
+
+.pure-scrollbar {
+  max-height: calc(100vh - calc(50px * 2.5));
+  overflow: hidden auto;
+}
 </style>

+ 144 - 144
src/router/index.ts

@@ -18,8 +18,8 @@ import {useUserStore} from "@/pinia/user-store";
 import XEUtils from "xe-utils";
 
 const router = createRouter({
-  history: createWebHistory(),
-  routes: [...Dashboard],
+    history: createWebHistory(),
+    routes: [...Dashboard],
 });
 
 const vueFile = import.meta.glob("../views/**/*.{vue,tsx}");
@@ -34,172 +34,172 @@ const appFullscreens = [];
 export const secondLevelRouterKey = new Map<string, string[]>();
 
 function emptyRouter(routers: IntergrationMenu[]) {
-  routers.forEach(item => {
-    const hasChildren = item.children !== null && item.children.length > 0;
-    if (item.fullscreen) {
-      appFullscreens.push(item);
-    } else if (item.component === "Layout" && hasChildren) {
-      item.children?.forEach(child => {
-        child.path = item.path + "/" + child.path;
-        firstLevelRouter.push(child);
-      });
-    } else if (hasChildren) {
-      item.children!.forEach(child => {
-        child.path = child.path.replace(item.path + "/", "");
-      });
-      secondLevelRouter.push(item);
-    } else {
-      firstLevelRouter.push(item);
-    }
-
-    if (item.children !== null && item.children.length > 0) {
-      emptyRouter(item.children);
-    }
-  });
+    routers.forEach(item => {
+        const hasChildren = item.children !== null && item.children.length > 0;
+        if (item.fullscreen) {
+            appFullscreens.push(item);
+        } else if (item.component === "Layout" && hasChildren) {
+            item.children?.forEach(child => {
+                child.path = item.path + "/" + child.path;
+                firstLevelRouter.push(child);
+            });
+        } else if (hasChildren) {
+            item.children!.forEach(child => {
+                child.path = child.path.replace(item.path + "/", "");
+            });
+            secondLevelRouter.push(item);
+        } else {
+            firstLevelRouter.push(item);
+        }
+
+        if (item.children !== null && item.children.length > 0) {
+            emptyRouter(item.children);
+        }
+    });
 }
 
 function convertToRouter(value: IntergrationMenu[]) {
-  const routers: RouteRecordRaw[] = [];
-  value.forEach(item => {
-    const meta: { [key: string]: any } = {};
-    for (let key in item) {
-      if (key.startsWith("meta")) {
-        const metaKey = capitalizeFirstLower(key.replace("meta", ""));
-        meta[metaKey] = item[key];
-      }
-    }
-    let path = item.path;
-    if (item.pathParams?.length > 0) {
-      const paths = item.path.split("/$");
-      path = paths[0];
-    }
-    const data: RouteRecordRaw = {
-      path: path + (item.pathParams === null ? "" : item.pathParams),
-      name: item.name,
-      redirect: item.redirect,
-      meta: meta,
-      componentName: item.component,
-      component: createNameComponent(item),
-    };
-    if (item.children && item.children.length > 0) {
-      data.children = convertToRouter(item.children);
-    }
-    routers.push(data);
-  });
-  return routers;
+    const routers: RouteRecordRaw[] = [];
+    value.forEach(item => {
+        const meta: { [key: string]: any } = {};
+        for (let key in item) {
+            if (key.startsWith("meta")) {
+                const metaKey = capitalizeFirstLower(key.replace("meta", ""));
+                meta[metaKey] = item[key];
+            }
+        }
+        let path = item.path;
+        if (item.pathParams?.length > 0) {
+            const paths = item.path.split("/$");
+            path = paths[0];
+        }
+        const data: RouteRecordRaw = {
+            path: path + (item.pathParams === null ? "" : item.pathParams),
+            name: item.name,
+            redirect: item.redirect,
+            meta: meta,
+            componentName: item.component,
+            component: createNameComponent(item),
+        };
+        if (item.children && item.children.length > 0) {
+            data.children = convertToRouter(item.children);
+        }
+        routers.push(data);
+    });
+    return routers;
 }
 
 async function beforeAddRoutes() {
-  await useUserStore().getUserInfo;
-  routerMenus.value = await getUserMenu();
-  emptyRouter(XEUtils.cloneDeep(routerMenus.value));
+    await useUserStore().getUserInfo;
+    routerMenus.value = await getUserMenu();
+    emptyRouter(XEUtils.cloneDeep(routerMenus.value));
 
-  secondLevelRouter.forEach(item => {
-    const tmp = XEUtils.eachAndReturnList(item.children, i => {
-      return i.name;
+    secondLevelRouter.forEach(item => {
+        const tmp = XEUtils.eachAndReturnList(item.children, i => {
+            return i.name;
+        });
+        secondLevelRouterKey.set(item.name, tmp);
+    });
+
+    router.addRoute({
+        name: "Home",
+        path: "/",
+        redirect: "/dashboard",
+        component: () => import("@/layout/index.vue"),
+        children: [
+            ...convertToRouter(firstLevelRouter),
+            ...convertToRouter(secondLevelRouter),
+        ],
+    });
+    convertToRouter(appFullscreens).forEach(item => {
+        router.addRoute(item);
     });
-    secondLevelRouterKey.set(item.name, tmp);
-  });
-
-  router.addRoute({
-    name: "Home",
-    path: "/",
-    redirect: "/dashboard",
-    component: () => import("@/layout/index.vue"),
-    children: [
-      ...convertToRouter(firstLevelRouter),
-      ...convertToRouter(secondLevelRouter),
-    ],
-  });
-  convertToRouter(appFullscreens).forEach(item => {
-    router.addRoute(item);
-  });
 }
 
 function createNameComponent(item) {
-  return () => {
-    return new Promise((resolve, reject) => {
-      try {
-        vueFile[`${item.component}`]().then(res => {
-          const tmp = defineComponent({
-            name: item.name,
-            render() {
-              let children = [createVNode(res.default)];
-              const style = {
-                height: "100%",
-                width: "100%",
-              };
-              const props = {
-                style,
-              };
-              if (item.mainCard) {
-                props.class = "layout_card";
-              }
-              if (item.mainOverflowAuto) {
-                children = [
-                  h(
-                    "div",
-                    {
-                      style: {
-                        height: "100%",
-                        width: "100%",
-                        overflow: "auto",
-                      },
-                    },
-                    [createVNode(res.default)]
-                  ),
-                ];
-              }
-              return h("div", props, children);
-            },
-          });
-          resolve(tmp);
+    return () => {
+        return new Promise((resolve, reject) => {
+            try {
+                vueFile[`${item.component}`]().then(res => {
+                    const tmp = defineComponent({
+                        name: item.name,
+                        render() {
+                            let children = [createVNode(res.default)];
+                            const style = {
+                                height: "100%",
+                                width: "100%",
+                            };
+                            const props = {
+                                style,
+                            };
+                            if (item.mainCard) {
+                                props.class = "layout_card";
+                            }
+                            if (item.mainOverflowAuto) {
+                                children = [
+                                    h(
+                                        "div",
+                                        {
+                                            style: {
+                                                height: "100%",
+                                                width: "100%",
+                                                overflow: "auto",
+                                            },
+                                        },
+                                        [createVNode(res.default)]
+                                    ),
+                                ];
+                            }
+                            return h("div", props, children);
+                        },
+                    });
+                    resolve(tmp);
+                });
+            } catch (e) {
+                reject("路由错误");
+                router.push("/500");
+            }
         });
-      } catch (e) {
-        reject("路由错误");
-        router.push("/500");
-      }
-    });
-  };
+    };
 }
 
 const capitalizeFirstLower = (word: string) => {
-  return word.charAt(0).toLowerCase() + word.slice(1);
+    return word.charAt(0).toLowerCase() + word.slice(1);
 };
 
 router.beforeEach(async (to, _from, next) => {
-  NProgress.start();
-  const hasToken = stringNotBlank(localStorage.token);
-
-  function tmpNext(...arg) {
-    to.meta.title && changeTitle(to.meta.title);
-    if (!hasToken) {
-      next("/login");
-      return;
+    NProgress.start();
+    const hasToken = stringNotBlank(localStorage.token);
+
+    function tmpNext(...arg) {
+        to.meta.title && changeTitle(to.meta.title);
+        if (!hasToken) {
+            next("/login");
+            return;
+        }
+        next(...arg);
     }
-    next(...arg);
-  }
-
-  if (to.name === "notFound" && hasToken) {
-    if (!asyncFinished) {
-      await beforeAddRoutes();
-      tmpNext({ path: to.path, query: to.query, replace: true });
-      asyncFinished = true;
-    } else {
-      tmpNext();
-    }
-  } else {
-    if (!hasToken && !to.meta.needToken) {
-      to.meta.title && changeTitle(to.meta.title);
-      next();
+
+    if (to.name === "notFound" && hasToken) {
+        if (!asyncFinished) {
+            await beforeAddRoutes();
+            tmpNext({path: to.path, query: to.query, replace: true});
+            asyncFinished = true;
+        } else {
+            tmpNext();
+        }
     } else {
-      tmpNext();
+        if (!hasToken && !to.meta.needToken) {
+            to.meta.title && changeTitle(to.meta.title);
+            next();
+        } else {
+            tmpNext();
+        }
     }
-  }
 });
 
 router.afterEach((to, _from) => {
-  NProgress.done();
+    NProgress.done();
 });
 
 export default router;

+ 0 - 11
src/views/emr-manage/DynamicDataObjects.vue

@@ -1,11 +0,0 @@
-<script setup lang="ts">
-
-</script>
-
-<template>
-
-</template>
-
-<style scoped lang="scss">
-
-</style>

+ 115 - 0
src/views/emr-manage/query-centre/rectify/index.vue

@@ -0,0 +1,115 @@
+<script setup lang="tsx">
+import CyDateRange from "@/components/cy/date-range/CyDateRange.vue";
+import useCompRef from "@/utils/useCompRef";
+import {ElForm, type FormRules} from "element-plus";
+import {emrServerHttp} from "@/api/emr-control/request";
+import {VxeGridProps} from "vxe-table";
+import {
+  emrStateEnum, getEmrUrl,
+  getInEmrUrl
+} from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init";
+
+defineOptions({
+  // 整改查询
+  name: "emrRectificationInquiry"
+})
+
+const elFormRef = useCompRef(ElForm)
+const queryParams = reactive({
+  startTime: "",
+  endTime: "",
+  timeOutVal: 72,
+  timeOutCorrection: false
+})
+
+const tableRef = ref()
+
+const gridOptions = reactive<VxeGridProps<any>>({
+  maxHeight: "100%",
+  showOverflow: true,
+  border: true,
+  loading: false,
+  scrollY: {
+    enabled: true,
+    gt: 0
+  },
+  columns: [
+    {field: 'patNo', title: '住院号', minWidth: 140},
+    {field: 'times', title: '住院次数', minWidth: 80},
+    {field: 'name', title: '姓名', minWidth: 120},
+    {field: 'sexName', title: '性别', minWidth: 80},
+    {field: 'referPhysician', title: '管床医生', minWidth: 160},
+    {field: 'timeOutVal', title: '超时', width: 100},
+    {field: 'dept', title: '科室', minWidth: 160},
+    {field: 'admissDept', title: '入院科室', width: 140},
+    {field: 'reviewTime', title: '质控时间', width: 140},
+    {
+      title: '病历', width: 80,
+      fixed: "right",
+      slots: {
+        default({row}) {
+          return <el-button type="primary" onClick={() => {
+            if (row.leaveHospital == 1) {
+              window.open(getEmrUrl(row.patNo, row.times, emrStateEnum.出院编辑), '_blank')
+            } else {
+              window.open(getEmrUrl(row.patNo, row.times), '_blank')
+            }
+          }}>前往</el-button>
+        }
+      }
+    },
+  ],
+  data: []
+})
+
+
+const rules: FormRules<any> = {
+  startTime: [{required: true, trigger: 'blur', message: "此项必填"}],
+  timeOutVal: [{required: true, trigger: 'blur', message: "此项必填"}]
+}
+
+function resetFields() {
+  elFormRef.value.resetFields();
+}
+
+async function queryClick() {
+  await elFormRef.value.validate();
+  gridOptions.data = await emrServerHttp({
+    method: "post",
+    url: "/queryEmr/queryTimeOut",
+    data: queryParams
+  }).catch(() => [])
+}
+</script>
+
+<template>
+  <div class="layout_container">
+    <header>
+      <el-form ref="elFormRef" :model="queryParams" :rules="rules" label-position="right" inline>
+        <el-form-item prop="startTime" label="质控时间">
+          <CyDateRange v-model="queryParams" :shortcutsIndex="4"/>
+        </el-form-item>
+        <el-form-item prop="timeOutVal" label="超时(小时)">
+          <el-input-number v-model="queryParams.timeOutVal" :min="1"/>
+        </el-form-item>
+        <el-form-item prop="timeOutCorrection" label="是否整改">
+          <el-switch v-model="queryParams.timeOutCorrection" inactive-text="否" active-text="是"/>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="queryClick">查询</el-button>
+          <el-button @click="resetFields">重置</el-button>
+          <el-button type="info" icon="Download" @click="() => tableRef.exportData()">导出</el-button>
+        </el-form-item>
+      </el-form>
+
+    </header>
+
+    <div class="layout_main">
+      <vxe-grid ref="tableRef" v-bind="gridOptions"/>
+    </div>
+  </div>
+</template>
+
+<style lang="scss">
+
+</style>

+ 47 - 0
src/views/emr-manage/query-centre/various-rate/QueryParams.vue

@@ -0,0 +1,47 @@
+<script setup lang="ts">
+import CyDateRange from "@/components/cy/date-range/CyDateRange.vue";
+import useCompRef from "@/utils/useCompRef";
+import {ElForm} from "element-plus";
+
+const props = defineProps<{
+  queryData: any
+}>()
+
+const elFormRef = useCompRef(ElForm)
+const rules = {
+  admissDate: [{required: true, trigger: 'blur', message: "必填",}],
+  dieDate: [{required: true, trigger: 'blur', message: "必填"}],
+  opDate: [{required: true, trigger: 'blur', message: "必填"}],
+}
+
+const queryData = reactive({
+  admissDate: [],
+  dieDate: [],
+  opDate: [],
+});
+
+defineExpose({
+  confirm: async () => {
+    await elFormRef.value.validate();
+    return queryData
+  }
+})
+</script>
+
+<template>
+  <el-form ref="elFormRef" :model="props.queryData" :rules="rules">
+    <el-form-item label="入院" prop="admissDate">
+      <CyDateRange v-model="props.queryData.admissDate"/>
+    </el-form-item>
+    <el-form-item label="出院" prop="dieDate">
+      <CyDateRange v-model="props.queryData.dieDate"/>
+    </el-form-item>
+    <el-form-item label="手术" prop="opDate">
+      <CyDateRange v-model="props.queryData.opDate"/>
+    </el-form-item>
+  </el-form>
+</template>
+
+<style lang="scss">
+
+</style>

+ 100 - 0
src/views/emr-manage/query-centre/various-rate/index.vue

@@ -0,0 +1,100 @@
+<script setup lang="ts">
+import {emrServerHttp} from "@/api/emr-control/request";
+import {VxeGridProps} from "vxe-table";
+import XEUtils from "xe-utils";
+import CyDateRange from "@/components/cy/date-range/CyDateRange.vue";
+import {xcMessage} from "@/utils/xiaochan-element-plus";
+
+defineOptions({
+  name: "variousRate"
+});
+
+const queryData = reactive({
+  start: "",
+  end: "",
+});
+
+const tableRef = ref()
+const tableGrid = reactive<VxeGridProps<any>>({
+  data: [],
+  maxHeight: "100%",
+  showOverflow: true,
+  border: true,
+  loading: false,
+  scrollY: {
+    enabled: true,
+    gt: 0
+  },
+  columns: [
+    {title: '排序', type: 'seq', width: 50},
+    {field: '一级指标', title: '一级指标', minWidth: 80},
+    {field: '二级指标', title: '二级指标', minWidth: 120},
+    {field: '质控问题数', title: '质控问题数', minWidth: 80},
+    {field: '质控病历数', title: '质控病历数', minWidth: 160},
+    {field: '出院数', title: '出院数', minWidth: 160},
+    {field: '实际分母', title: '实际分母', width: 100},
+    {field: '质控一级分子', title: '质控一级分子', width: 100},
+    {field: '质控一级分母', title: '质控一级分母', width: 100},
+    {field: '比值', title: '比值', width: 100},
+    {field: '终极分子', title: '终极分子', width: 100},
+    {field: '终极分母', title: '终极分母', width: 100},
+    {field: '终极比值', title: '终极比值', width: 100},
+  ],
+  columnConfig: {resizable: true}
+})
+
+async function openParams() {
+  if (queryData.start == '') {
+    xcMessage.warning("请选择时间范围")
+    return
+  }
+  tableGrid.loading = true
+  const tmp = await emrServerHttp({
+    method: "get",
+    url: "/queryEmr/variousRate",
+    params: {...queryData}
+  }).catch(() => {
+    return {}
+  });
+
+  if (XEUtils.isEmpty(tmp)) {
+    tableGrid.data = []
+  } else {
+    let tmpData = []
+    let mergeCells = []
+    for (const key in tmp) {
+      const item = tmp[key];
+      if (XEUtils.isArray(item)) {
+        item.forEach(i => {
+          i.一级指标 = key
+        })
+      }
+      const currentLength = tmpData.length;
+      mergeCells.push({
+        row: currentLength,
+        col: 1,
+        rowspan: item.length,
+        colspan: 1
+      })
+      tableGrid.mergeCells = mergeCells
+      tmpData.push(...item)
+      tableGrid.data = tmpData
+    }
+  }
+  tableGrid.loading = false;
+}
+
+</script>
+
+<template>
+  <div class="layout_container">
+    <header>
+      <CyDateRange v-model="queryData" start="start" end="end"/>
+      <el-button type="primary" v-el-btn="openParams">查询</el-button>
+      <el-button @click="() => tableRef.exportData()">导出</el-button>
+    </header>
+    <div class="layout_main">
+      <vxe-grid ref="tableRef" v-bind="tableGrid"/>
+    </div>
+  </div>
+</template>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 313 - 300
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/EmrMain.vue


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

@@ -1,30 +1,30 @@
 <template>
   <div class="layout_container">
     <header style="margin: 0">
-      <EmrHeader />
+      <EmrHeader/>
       <div style="padding: 5px">
-        <EmrSelectPat v-if="emrConfig.editor" :overViewList />
+        <EmrSelectPat v-if="emrConfig.editor" :overViewList/>
 
         <el-input
-          v-model="queryPatNo"
-          placeholder="住院号"
-          style="width: 100px"
-          @blur="queryPatNo = $event.target.value.trim()"
+            v-model="queryPatNo"
+            placeholder="住院号"
+            style="width: 100px"
+            @blur="queryPatNo = $event.target.value.trim()"
         />
-        <el-divider direction="vertical" />
+        <el-divider direction="vertical"/>
         <el-button-group>
           <el-button
-            @click="allPatientsInTheHospital"
-            :disabled="query.state === 4"
+              @click="allPatientsInTheHospital"
+              :disabled="query.state === 4"
           >
             在院
           </el-button>
           <EmrLeaveHospitalPatient
-            :patNo="queryPatNo"
-            @rowClick="disPatients"
+              :patNo="queryPatNo"
+              @rowClick="disPatients"
           />
         </el-button-group>
-        <el-divider direction="vertical" />
+        <el-divider direction="vertical"/>
         {{ patientInfo.name }}
         性别:<span style="color: red">{{ cptSex(patientInfo.sex) }}</span>
         年龄:<span style="color: red">{{
@@ -34,29 +34,29 @@
           XEUtils.addUnit(patientInfo.actIptDays, "天")
         }}</span>
         入院时间:<span style="color: red">{{ patientInfo.admissDate }}</span>
-        <el-divider direction="vertical" />
+        <el-divider direction="vertical"/>
         <el-button-group
-          v-if="
+            v-if="
             query.state === emrStateEnum.在院编辑 ||
             query.state === emrStateEnum.在院只读
           "
         >
-          <el-button type="primary" @click="clickPatientNext">上一位</el-button>
+          <el-button type="primary" @click="() =>clickPatientNext()">上一位</el-button>
           <el-button type="primary" @click="clickPatientNext(false)"
-            >下一位
+          >下一位
           </el-button>
         </el-button-group>
       </div>
     </header>
     <div class="layout_main">
-      <emr-main v-if="show" ref="emrMainRef" />
+      <emr-main v-if="show" ref="emrMainRef"/>
     </div>
   </div>
 
   <LoadingProgress
-    :describes="describes"
-    loading-name="病历加载中"
-    ref="progressRef"
+      :describes="describes"
+      loading-name="病历加载中"
+      ref="progressRef"
   />
 </template>
 
@@ -66,9 +66,9 @@ import {
   getPatientInfo,
 } from "@/api/zhu-yuan-yi-sheng/emr-patient";
 import router from "@/router";
-import { BizException, ExceptionEnum } from "@/utils/BizException";
-import { getServerDateApi } from "@/api/public-api";
-import { subtractTime } from "@/utils/date";
+import {BizException, ExceptionEnum} from "@/utils/BizException";
+import {getServerDateApi} from "@/api/public-api";
+import {subtractTime} from "@/utils/date";
 import {
   applicationData,
   canIUnlockIt,
@@ -81,7 +81,7 @@ import {
   unlockEnum,
   useLiftingRestrictions,
 } from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init";
-import { getMyUnlockByPatNo } from "@/api/zhu-yuan-yi-sheng/emr-control-rule";
+import {getMyUnlockByPatNo} from "@/api/zhu-yuan-yi-sheng/emr-control-rule";
 import {
   ElButton,
   ElMessage,
@@ -89,27 +89,27 @@ import {
   ElNotification,
 } from "element-plus";
 import LoadingProgress from "@/components/loading-progress/LoadingProgress.vue";
-import { defineAsyncComponent, nextTick, onMounted, ref } from "vue";
-import { CyMessageBox } from "@/components/cy/message-box";
+import {defineAsyncComponent, nextTick, onMounted, ref} from "vue";
+import {CyMessageBox} from "@/components/cy/message-box";
 import sleep from "@/utils/sleep";
-import { isDev, windowBtoaAndAtob } from "@/utils/public";
-import { useUserStore } from "@/pinia/user-store";
+import {isDev, windowBtoaAndAtob} from "@/utils/public";
+import {useUserStore} from "@/pinia/user-store";
 import useCompRef from "@/utils/useCompRef";
-import { cptSex } from "@/utils/computed";
-import { getOverView } from "@/api/inpatient/patient";
+import {cptSex} from "@/utils/computed";
+import {getOverView} from "@/api/inpatient/patient";
 import XEUtils from "xe-utils";
 
 const EmrLeaveHospitalPatient = defineAsyncComponent(
-  () => import("@/components/zhu-yuan-yi-sheng/emr/EmrLeaveHospitalPatient.vue")
+    () => import("@/components/zhu-yuan-yi-sheng/emr/EmrLeaveHospitalPatient.vue")
 );
 const EmrSelectPat = defineAsyncComponent(
-  () => import("@/components/zhu-yuan-yi-sheng/EmrSelectPat.vue")
+    () => import("@/components/zhu-yuan-yi-sheng/EmrSelectPat.vue")
 );
 const EmrMain = defineAsyncComponent(
-  () =>
-    import(
-      "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/EmrMain.vue"
-    )
+    () =>
+        import(
+            "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/EmrMain.vue"
+            )
 );
 const EmrHeader = defineAsyncComponent(() => import("./EmrHeader.vue"));
 
@@ -123,8 +123,8 @@ const queryPatNo = ref("");
 const disPatients = async () => {
   if (query.value.times === 0 || !query.value.patNo) {
     BizException(
-      ExceptionEnum.MESSAGE_ERROR,
-      "请输入住院号,住院次数不能为 0 "
+        ExceptionEnum.MESSAGE_ERROR,
+        "请输入住院号,住院次数不能为 0 "
     );
   }
   query.value.state = 2;
@@ -150,16 +150,16 @@ const noPatient = () => {
       return true;
     },
   })
-    .then(({ action, value }) => {
-      query.value.patNo = value;
-      allPatientsInTheHospital();
-    })
-    .catch(({ action, value }) => {
-      if (action === "cancel") {
+      .then(({action, value}) => {
         query.value.patNo = value;
-        emrMitt.emit("queryDischarge");
-      }
-    });
+        allPatientsInTheHospital();
+      })
+      .catch(({action, value}) => {
+        if (action === "cancel") {
+          query.value.patNo = value;
+          emrMitt.emit("queryDischarge");
+        }
+      });
   sleep(500).then(() => {
     progressRef.value.close();
   });
@@ -181,8 +181,8 @@ const routerFunc = async () => {
   }
   // @ts-ignore
   let reqUnlock = await getMyUnlockByPatNo(
-    query.value.patNo,
-    query.value.times
+      query.value.patNo,
+      query.value.times
   ).catch(e => {
     return null;
   });
@@ -196,14 +196,14 @@ const routerFunc = async () => {
   // 在院编辑病历
   if (query.value.state === 1) {
     await getPatientInfo(query.value.patNo)
-      .then(res => {
-        patientInfo.value.$inOutFlag = 1;
-        patientInfo.value = res;
-        show.value = true;
-      })
-      .catch(() => {
-        progressRef.value.close();
-      });
+        .then(res => {
+          patientInfo.value.$inOutFlag = 1;
+          patientInfo.value = res;
+          show.value = true;
+        })
+        .catch(() => {
+          progressRef.value.close();
+        });
   } else if (query.value.state === 2) {
     // 出院编辑病历,
     await queryDisPatient();
@@ -224,8 +224,8 @@ const queryDisPatient = async () => {
   patientInfo.value = await getDisPatient(query.value.patNo, query.value.times);
   patientInfo.value.$inOutFlag = 2;
   patientInfo.value.dischargeDays = subtractTime(
-    await getServerDateApi(),
-    patientInfo.value.disDate
+      await getServerDateApi(),
+      patientInfo.value.disDate
   );
 
   // 如果患者的出院时间大于 7 天就只能看病历和打印病历了
@@ -238,31 +238,31 @@ const queryDisPatient = async () => {
 
   if (!emrConfig.value.editor) {
     const message =
-      "患者出院超7天,无法编辑病历,如需编辑请点击【解锁限制】,待审核完成后刷新页面即可。";
+        "患者出院超7天,无法编辑病历,如需编辑请点击【解锁限制】,待审核完成后刷新页面即可。";
     const notification = ElNotification({
       message: (
-        <div>
-          <div>{message}</div>
-          <div style={{ textAlign: "end" }}>
-            <ElButton text type="danger" onClick={() => notification.close()}>
-              {{
-                default: () => "关闭",
-              }}
-            </ElButton>
-            <ElButton
-              text
-              type="primary"
-              onClick={() => {
-                useLiftingRestrictions();
-                notification.close();
-              }}
-            >
-              {{
-                default: () => "解锁限制",
-              }}
-            </ElButton>
+          <div>
+            <div>{message}</div>
+            <div style={{textAlign: "end"}}>
+              <ElButton text type="danger" onClick={() => notification.close()}>
+                {{
+                  default: () => "关闭",
+                }}
+              </ElButton>
+              <ElButton
+                  text
+                  type="primary"
+                  onClick={() => {
+                    useLiftingRestrictions();
+                    notification.close();
+                  }}
+              >
+                {{
+                  default: () => "解锁限制",
+                }}
+              </ElButton>
+            </div>
           </div>
-        </div>
       ),
       duration: 1000 * 10,
       type: "warning",
@@ -298,8 +298,8 @@ const queryAllPatients = async flag => {
 const channel = new BroadcastChannel("login-channel");
 channel.addEventListener("message", event => {
   if (
-    navigator.userAgent.indexOf("Firefox") !== -1 ||
-    navigator.userAgent.indexOf("Chrome") !== -1
+      navigator.userAgent.indexOf("Firefox") !== -1 ||
+      navigator.userAgent.indexOf("Chrome") !== -1
   ) {
     emrMainRef.value!.changeClear();
     window.location.href = "about:blank";
@@ -315,17 +315,19 @@ channel.addEventListener("message", event => {
 const whetherKickedOut = () => {
   const data = localStorage.getItem("强制刷新");
   if (data) {
-    const { userInfo, saveSuccess } = JSON.parse(data);
+    const {userInfo, saveSuccess} = JSON.parse(data);
     // @ts-ignore
     ElMessageBox.alert(
-      `您已经被强制踢出,操作人:【${userInfo.name}】,您的病历保存【${saveSuccess ? "成功" : "失败"}】。`,
-      "提示",
-      {
-        type: "warning",
-      }
+        `您已经被强制踢出,操作人:【${userInfo.name}】,您的病历保存【${saveSuccess ? "成功" : "失败"}】。`,
+        "提示",
+        {
+          type: "warning",
+        }
     )
-      .then(() => {})
-      .catch(() => {});
+        .then(() => {
+        })
+        .catch(() => {
+        });
 
     localStorage.removeItem("强制刷新");
   }
@@ -376,11 +378,11 @@ async function clickPatientNext(upper: boolean = true) {
 }
 
 watch(
-  () => router.currentRoute.value,
-  () => {
-    window.location.reload();
-  },
-  { deep: true }
+    () => router.currentRoute.value,
+    () => {
+      window.location.reload();
+    },
+    {deep: true}
 );
 
 onMounted(async () => {

+ 6 - 6
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/plugins/opinion/AuditDisplayComponent.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import type { EmrAuditDetail } from "@/api/zhu-yuan-yi-sheng/emr-audit";
+import type {EmrAuditDetail} from "@/api/zhu-yuan-yi-sheng/emr-audit";
 
 defineProps<{
   data: EmrAuditDetail[];
@@ -8,10 +8,10 @@ defineProps<{
 
 <template>
   <el-card
-    v-for="item in data"
-    shadow="hover"
-    class="emr_audit_record-table"
-    :key="item.id"
+      v-for="(item,index) in data"
+      shadow="hover"
+      class="emr_audit_record-table"
+      :key="item.id"
   >
     <el-row>
       <el-col :span="24"> {{ item.name }}{{ item.remark }}</el-col>
@@ -23,7 +23,7 @@ defineProps<{
       <el-col :span="12"> 缺陷等级:{{ item.scoringCriteriaName }}</el-col>
       <el-col :span="12"> 缺陷数:{{ item.numberOfDefects }}</el-col>
       <el-col :span="12"> 质控等级:{{ item.levelName }}</el-col>
-      <slot name="default" :item="item" />
+      <slot name="default" :item="item" :index="index"/>
     </el-row>
   </el-card>
 </template>

+ 25 - 5
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/plugins/opinion/AuditRecord.vue

@@ -1,12 +1,16 @@
 <script setup lang="ts">
-import { emrAuditRootContextKey } from "./useEmrAudit";
+import {emrAuditRootContextKey} from "./useEmrAudit";
 import {
+  deleteEmrAuditByEmrId,
   EmrAuditDetail,
   rectifyMedicalRecords,
 } from "@/api/zhu-yuan-yi-sheng/emr-audit";
-import { useUserStore } from "@/pinia/user-store";
-import { formatDateToStr } from "@/utils/moment-utils";
-import AuditDisplayComponent from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/plugins/opinion/AuditDisplayComponent.vue";
+import {useUserStore} from "@/pinia/user-store";
+import {formatDateToStr} from "@/utils/moment-utils";
+import AuditDisplayComponent
+  from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/plugins/opinion/AuditDisplayComponent.vue";
+import {ElMessageBox} from "element-plus";
+import {needRule} from "@/utils/public";
 
 const root = inject(emrAuditRootContextKey);
 
@@ -17,12 +21,20 @@ function rectification(row: EmrAuditDetail, flag) {
     row.remediationStatusName = flag === 1 ? "已整改" : "已知无需整改";
   });
 }
+
+async function delById(row: EmrAuditDetail, index: number) {
+  await ElMessageBox.confirm('是否删除该意见', '提示', {
+    type: 'error',
+  });
+  await deleteEmrAuditByEmrId(row.id)
+  root!.store.state.currentAudit.splice(index, 1)
+}
 </script>
 
 <template>
   <div class="layout_h-w_max" style="overflow: auto">
     <AuditDisplayComponent :data="root!.store.state.currentAudit">
-      <template #default="{ item }">
+      <template #default="{ item, index }">
         <el-col :span="12">
           <el-button type="primary" @click="rectification(item, 1)">
             已整改
@@ -31,6 +43,14 @@ function rectification(row: EmrAuditDetail, flag) {
         <el-col :span="12">
           <el-button @click="rectification(item, 2)"> 已知</el-button>
         </el-col>
+        <el-col :span="24" v-if="needRule(78)">
+          <el-button size="default"
+                     style="width: 100%"
+                     type="danger"
+                     @click="() =>delById(item, index)"
+          >删除
+          </el-button>
+        </el-col>
       </template>
     </AuditDisplayComponent>
   </div>

+ 78 - 70
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/plugins/opinion/SendAudit.vue

@@ -1,23 +1,23 @@
 <script setup lang="tsx">
-import { emrAuditRootContextKey } from "./useEmrAudit";
+import {emrAuditRootContextKey} from "./useEmrAudit";
 import {
   EmrAuditDetailTable,
   setAudit,
   updateControlLevel,
   updateFinalControl,
 } from "@/api/zhu-yuan-yi-sheng/emr-audit";
-import { scoringCriteriaList } from "@/data";
-import { useCompRef } from "@/utils/useCompRef";
-import { ElTable } from "element-plus";
+import {scoringCriteriaList} from "@/data";
+import {useCompRef} from "@/utils/useCompRef";
+import {ElTable} from "element-plus";
 import XcElOption from "@/components/xiao-chan/xc-el-option/XcElOption.vue";
-import { stringNotBlank } from "@/utils/blank-utils";
-import { needRule } from "@/utils/public";
-import { patientInfo } from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init";
-import { CyMessageBox } from "@/components/cy/message-box";
-import { xcMessage } from "@/utils/xiaochan-element-plus";
+import {stringNotBlank} from "@/utils/blank-utils";
+import {needRule} from "@/utils/public";
+import {patientInfo} from "@/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr-editor/emr-init";
+import {CyMessageBox} from "@/components/cy/message-box";
+import {xcMessage} from "@/utils/xiaochan-element-plus";
 
 const SystemStaffSelect = defineAsyncComponent(
-  () => import("@/components/system/staff-select/SystemStaffSelect.vue")
+    () => import("@/components/system/staff-select/SystemStaffSelect.vue")
 );
 
 const root = inject(emrAuditRootContextKey);
@@ -45,7 +45,7 @@ function addAudit() {
   });
   nextTick(() => {
     tableRef.value?.setScrollTop(
-      tableRef.value?.$el.querySelector(".el-scrollbar__view").scrollHeight
+        tableRef.value?.$el.querySelector(".el-scrollbar__view").scrollHeight
     );
   });
 }
@@ -74,17 +74,18 @@ function handleSendAudit() {
     title: "发送审核",
     message: `请确认是否发送给【${sendDoctor.value.name}】医生`,
   })
-    .then(() => {
-      setAudit(data).then(() => {
-        root?.store.queryCurrentAudit();
+      .then(() => {
+        setAudit(data).then(() => {
+          root?.store.queryCurrentAudit();
+        });
+      })
+      .catch(() => {
       });
-    })
-    .catch(() => {});
 }
 
 const levelList = [
-  { code: 0, name: "全院", disabled: !permissions },
-  { code: 1, name: "科室" },
+  {code: 0, name: "全院", disabled: !permissions},
+  {code: 1, name: "科室"},
 ];
 
 function handleFinalControl() {
@@ -92,15 +93,16 @@ function handleFinalControl() {
     title: "提示",
     message: "是否标记此患者为终末质控。",
   })
-    .then(() => {
-      updateFinalControl(
-        patientInfo.value.inpatientNo,
-        patientInfo.value.admissTimes
-      ).then(res => {
-        patientInfo.value.finalControl = 1;
+      .then(() => {
+        updateFinalControl(
+            patientInfo.value.inpatientNo,
+            patientInfo.value.admissTimes
+        ).then(res => {
+          patientInfo.value.finalControl = 1;
+        });
+      })
+      .catch(() => {
       });
-    })
-    .catch(() => {});
 }
 
 function ratingClick() {
@@ -108,17 +110,17 @@ function ratingClick() {
     title: "病历评分",
     message: "是否改变病案质量,点击后病案首页会改变。",
     selectOption: [
-      { code: 1, name: "Ⅰ" },
-      { code: 2, name: "Ⅱ" },
-      { code: 3, name: "Ⅲ" },
-      { code: 4, name: "Ⅳ" },
-      { code: 5, name: "Ⅴ" },
+      {code: 1, name: "Ⅰ"},
+      {code: 2, name: "Ⅱ"},
+      {code: 3, name: "Ⅲ"},
+      {code: 4, name: "Ⅳ"},
+      {code: 5, name: "Ⅴ"},
     ],
-  }).then(({ value }) => {
+  }).then(({value}) => {
     updateControlLevel(
-      patientInfo.value.inpatientNo,
-      patientInfo.value.admissTimes,
-      value
+        patientInfo.value.inpatientNo,
+        patientInfo.value.admissTimes,
+        value
     );
   });
 }
@@ -129,79 +131,85 @@ function ratingClick() {
     <header style="overflow-x: auto">
       等级:
       <el-select style="width: 70px" v-model="level">
-        <xc-el-option :data="levelList" />
+        <xc-el-option :data="levelList"/>
       </el-select>
       医生:
       <SystemStaffSelect
-        style="width: 80px"
-        value="code"
-        label="name"
-        v-model="sendDoctor"
+          style="width: 80px"
+          value="code"
+          label="name"
+          v-model="sendDoctor"
       />
-      <el-divider direction="vertical" />
+      <el-divider direction="vertical"/>
       <el-button @click="addAudit" type="primary">新增</el-button>
       <el-button @click="handleSendAudit" type="success">发送</el-button>
       <el-button v-if="permissions" @click="handleFinalControl"
-        >标记终末
+      >标记终末
       </el-button>
       <el-button
-        v-if="permissions && patientInfo.finalControl !== 0"
-        @click="ratingClick"
+          v-if="permissions && patientInfo.finalControl !== 0"
+          @click="ratingClick"
       >
         病历评分
       </el-button>
     </header>
     <div class="layout_main layout_el-table">
-      <el-table :data="root.store.state.auditTemplate" ref="tableRef">
-        <el-table-column type="selection" />
+      <el-table ref="tableRef"
+                :data="root.store.state.auditTemplate">
+        <el-table-column type="selection"/>
         <el-table-column prop="name" label="项目" width="180">
           <template #default="{row}: EmrAuditDetailTable">
-            <el-input type="textarea" v-model="row.name" :rows="2" />
+            <el-input type="textarea" v-model="row.name" :rows="2"/>
           </template>
         </el-table-column>
         <el-table-column
-          v-if="false"
-          prop="scoringCriteria"
-          label="等级"
-          width="40"
+            v-if="false"
+            prop="scoringCriteria"
+            label="等级"
+            width="40"
         >
           <template #default="{row}: EmrAuditDetailTable">
             <select v-model="row.scoringCriteria" @change="selectRow(row)">
               <option
-                v-for="item in scoringCriteriaList"
-                :key="item.code"
-                :value="item.code"
+                  v-for="item in scoringCriteriaList"
+                  :key="item.code"
+                  :value="item.code"
               >
                 {{ item.name }}
               </option>
             </select>
           </template>
         </el-table-column>
-        <el-table-column prop="remark" label="备注">
+        <el-table-column prop="remark" label="备注" width="80">
           <template #default="{row}: EmrAuditDetailTable">
             <el-input
-              v-model="row.remark"
-              :maxlength="500"
-              :title="row.remark"
-              @change="selectRow(row)"
-              type="textarea"
-              :rows="2"
+                v-model="row.remark"
+                :maxlength="500"
+                :title="row.remark"
+                @change="selectRow(row)"
+                type="textarea"
+                :rows="2"
             />
           </template>
         </el-table-column>
+        <el-table-column v-if="level === 0" prop="minusPoints" label="减分" width="45">
+          <template #default="{row}">
+            <input style="width: 20px" v-model="row.minusPoints" type="number"/>
+          </template>
+        </el-table-column>
         <el-table-column
-          v-if="false"
-          prop="numberOfDefects"
-          label="缺陷数"
-          width="45"
+            v-if="false"
+            prop="numberOfDefects"
+            label="缺陷数"
+            width="45"
         >
           <template #default="{row}: EmrAuditDetailTable">
             <el-input-number
-              style="width: 40px"
-              v-model="row.numberOfDefects"
-              @change="selectRow(row)"
-              :min="0"
-              :controls="false"
+                style="width: 40px"
+                v-model="row.numberOfDefects"
+                @change="selectRow(row)"
+                :min="0"
+                :controls="false"
             />
           </template>
         </el-table-column>

+ 2 - 0
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/emr_control_rule/RuleSift.vue

@@ -14,6 +14,7 @@
     <vxe-column field="admissTimes" title="次数" width="67"/>
     <vxe-column field="name" title="姓名" width="70"/>
     <vxe-column field="gradingScale" title="评级" width="62"/>
+    <vxe-column field="minusPoints" title="评分" width="62"/>
     <vxe-column field="age" title="年龄" width="82"/>
     <vxe-column field="clinicDiagStr" title="门(急)诊诊断" width="108"/>
     <vxe-column field="admissDiag" title="入院诊断" width="169"/>
@@ -74,6 +75,7 @@ const exportExcel = () => {
     admissTimes: '次数',
     name: '姓名',
     gradingScale: '病历评级',
+    minusPoints: '病历评分',
     age: "年龄",
     clinicDiagStr: '门(急)诊诊断',
     admissDiag: '入院诊断',

+ 2 - 0
src/views/hospitalization/zhu-yuan-yi-sheng/electronic-medical-record/final-quality-control/FinalQualityControl.vue

@@ -50,6 +50,7 @@ const exportExcelClick = () => {
     admissTimes: '次数',
     name: '姓名',
     gradingScale: '病历评级',
+    minusPoints: '病历评分',
     age: '年龄',
     clinicDiagStr: "门(急)诊诊断",
     admissDiag: "入院诊断",
@@ -147,6 +148,7 @@ onMounted(async () => {
         <el-table-column prop="admissTimes" label="次数" width="40"/>
         <el-table-column prop="name" label="姓名" width="220"/>
         <el-table-column prop="gradingScale" label="病历评级"/>
+        <el-table-column prop="minusPoints" label="评分" width="62"/>
         <el-table-column prop="age" label="年龄"/>
         <el-table-column prop="clinicDiagStr" label="门(急)诊诊断"/>
         <el-table-column prop="admissDiag" label="入院诊断"/>

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác