qinlaiqiao 4 лет назад
Родитель
Сommit
744e9463d2
66 измененных файлов с 2085 добавлено и 1707 удалено
  1. 62 49
      .eslintrc.js
  2. 3 3
      bootstrap.js
  3. 4 4
      midway.config.ts
  4. 6 2
      package.json
  5. 1 1
      postcss.config.js
  6. 1 2
      src/App.vue
  7. 7 7
      src/apis/configuration.ts
  8. 5 5
      src/apis/controller/index.ts
  9. 50 28
      src/components/context-menu/ContextMenu.vue
  10. 2 2
      src/composables/useHotRef.ts
  11. 22 20
      src/composables/useProjectID.ts
  12. 9 9
      src/composables/useRefresh.ts
  13. 19 13
      src/composables/useStructureRouter.ts
  14. 0 0
      src/constants/.gitkeep
  15. 6 6
      src/constants/commonClassName.ts
  16. 70 66
      src/constants/emitter.ts
  17. 20 20
      src/constants/provideInject.ts
  18. 5 5
      src/constants/subject.ts
  19. 48 42
      src/constants/tmp/table-columns-meta.ts
  20. 6 8
      src/examples/Examples.vue
  21. 11 11
      src/main.ts
  22. 61 61
      src/router/index.ts
  23. 8 8
      src/store/.localmodules.ts
  24. 12 6
      src/store/DynamicModule.ts
  25. 3 3
      src/store/createStorageState.ts
  26. 2 2
      src/store/index.ts
  27. 12 10
      src/store/modules/breadcrumb.ts
  28. 25 19
      src/store/modules/summaryLayout.ts
  29. 1 1
      src/styles/_main.scss
  30. 0 0
      src/types/.gitkeep
  31. 7 7
      src/types/common.d.ts
  32. 147 137
      src/types/components.d.ts
  33. 16 16
      src/types/subject.d.ts
  34. 46 32
      src/utils/common/tools.ts
  35. 93 35
      src/utils/frontend/alert.ts
  36. 52 20
      src/utils/frontend/dom.ts
  37. 70 66
      src/utils/frontend/emitter.ts
  38. 16 14
      src/utils/frontend/loadImage.ts
  39. 3 3
      src/utils/frontend/tree.ts
  40. 8 5
      src/utils/frontend/vueHelper.ts
  41. 4 5
      src/views/data-library/DataLibrary.vue
  42. 58 53
      src/views/data-library/style.scss
  43. 33 6
      src/views/login/Login.vue
  44. 27 27
      src/views/login/scripts/moduleItem.ts
  45. 3 3
      src/views/login/scripts/preloadImg.ts
  46. 126 101
      src/views/login/scripts/rotateCanvas.ts
  47. 202 202
      src/views/login/style.scss
  48. 28 21
      src/views/main-frame/MainFrame.vue
  49. 3 1
      src/views/main-frame/style.scss
  50. 71 33
      src/views/project-list/ProjectList.vue
  51. 34 22
      src/views/project/Project.vue
  52. 119 104
      src/views/project/overview/Overview.vue
  53. 8 7
      src/views/project/process/Process.vue
  54. 3 6
      src/views/project/report/Report.vue
  55. 35 38
      src/views/project/summary/Summary.vue
  56. 4 4
      src/views/project/summary/components/bottom-tabs/BottomTabs.vue
  57. 2 0
      src/views/project/summary/components/bottom-tabs/style.scss
  58. 28 28
      src/views/project/summary/components/cost-table/CostTable.vue
  59. 43 31
      src/views/project/summary/components/lib-ration/LibRation.vue
  60. 36 26
      src/views/project/summary/components/std-bill/StdBill.vue
  61. 57 49
      src/views/project/summary/components/subject-tree/SubjectTree.vue
  62. 41 33
      src/views/project/summary/components/tool-bar/ToolBar.vue
  63. 3 0
      src/views/project/summary/components/tool-bar/style.scss
  64. 121 121
      src/views/project/summary/scripts/useSummaryLayout.ts
  65. 40 18
      src/views/workbench/Workbench.vue
  66. 17 20
      vite.config.ts

+ 62 - 49
.eslintrc.js

@@ -4,74 +4,87 @@ module.exports = {
     node: true,
   },
   extends: [
-    'plugin:vue/vue3-essential',
-    '@vue/airbnb',
-    '@vue/typescript/recommended',
-    '@vue/prettier',
-    '@vue/prettier/@typescript-eslint',
+    "plugin:vue/vue3-essential",
+    "@vue/airbnb",
+    "@vue/typescript/recommended",
+    "@vue/prettier",
+    "@vue/prettier/@typescript-eslint",
   ],
   parserOptions: {
     ecmaVersion: 2020,
-    parser: '@typescript-eslint/parser',
+    parser: "@typescript-eslint/parser",
   },
   rules: {
-    'import/extensions': [
-      'error',
-      'ignorePackages',
-      {
-        js: 'never',
-        mjs: 'never',
-        jsx: 'never',
-        ts: 'never',
-        tsx: 'never',
-      },
-    ],
-    'import/no-unresolved': 'off',
-    '@typescript-eslint/no-empty-function': 'off',
-    '@typescript-eslint/no-explicit-any': 'off',
-    '@typescript-eslint/explicit-module-boundary-types': 'off',
-    '@typescript-eslint/no-non-null-assertion': 'off',
-    'no-unused-expressions': [
-      'error',
+    /* "import/extensions": [
+            "error",
+            "ignorePackages",
+            {
+              js: "never",
+              mjs: "never",
+              jsx: "never",
+              ts: "never",
+              tsx: "never",
+            },
+          ], */
+    "import/no-unresolved": "off",
+    "@typescript-eslint/no-empty-function": "off",
+    "@typescript-eslint/no-explicit-any": "off",
+    "@typescript-eslint/explicit-module-boundary-types": "off",
+    "@typescript-eslint/no-non-null-assertion": "off",
+    "import/extensions": "off",
+    "no-unused-expressions": [
+      "error",
       {
         allowShortCircuit: true,
       },
     ],
-    'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
-    'no-restricted-syntax': 'off',
-    'no-shadow': 'off',
-    'vue/no-v-model-argument': 'off',
-    '@typescript-eslint/no-shadow': 'error',
-    '@typescript-eslint/interface-name-prefix': 'off',
-    '@typescript-eslint/no-var-requires': 'off',
-    'no-return-assign': 'off',
-    'no-param-reassign': 'off',
-    'no-plusplus': 'off',
-    'class-methods-use-this': 'off',
-    'no-await-in-loop': 'off',
-    'no-continue': 'off',
-    'guard-for-in': 'off',
-    'no-return-await': 'off',
-    'prefer-destructuring': 'off',
-    '@typescript-eslint/no-this-alias': 'off',
-    'import/order': [
-      'error',
+    "import/no-extraneous-dependencies": ["error", { devDependencies: true }],
+    "no-restricted-syntax": "off",
+    "no-shadow": "off",
+    "vue/no-v-model-argument": "off",
+    "@typescript-eslint/no-shadow": "error",
+    "@typescript-eslint/interface-name-prefix": "off",
+    "@typescript-eslint/no-var-requires": "off",
+    "no-return-assign": "off",
+    "no-param-reassign": "off",
+    "no-plusplus": "off",
+    "class-methods-use-this": "off",
+    "no-await-in-loop": "off",
+    "no-continue": "off",
+    "guard-for-in": "off",
+    "no-return-await": "off",
+    "prefer-destructuring": "off",
+    "@typescript-eslint/no-this-alias": "off",
+    "import/order": [
+      "error",
       {
         pathGroups: [
           {
-            pattern: '@/**',
-            group: 'internal',
+            pattern: "@/**",
+            group: "internal",
           },
         ],
-        groups: [['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object']],
+        groups: [
+          [
+            "builtin",
+            "external",
+            "internal",
+            "parent",
+            "sibling",
+            "index",
+            "object",
+          ],
+        ],
       },
     ],
   },
-  globals: {
-  },
+  globals: {},
   overrides: [
     {
-      files: ['**/__tests__/*.{j,t}s?(x)', '**/tests/unit/**/*.spec.{j,t}s?(x)'],
+      files: [
+        "**/__tests__/*.{j,t}s?(x)",
+        "**/tests/unit/**/*.spec.{j,t}s?(x)",
+      ],
       env: {
         mocha: true,
       },

+ 3 - 3
bootstrap.js

@@ -1,5 +1,5 @@
-const { Framework } = require('@midwayjs/koa');
-const { Bootstrap } = require('@midwayjs/bootstrap');
+const { Framework } = require("@midwayjs/koa");
+const { Bootstrap } = require("@midwayjs/bootstrap");
 
 const web = new Framework().configure({
   port: 7002,
@@ -8,5 +8,5 @@ const web = new Framework().configure({
 Bootstrap.load(web)
   .run()
   .then(() => {
-    console.log('Your application is running at http://localhost:7002');
+    console.log("Your application is running at http://localhost:7002");
   });

+ 4 - 4
midway.config.ts

@@ -1,11 +1,11 @@
-import { defineConfig } from '@midwayjs/hooks';
+import { defineConfig } from "@midwayjs/hooks";
 
 export default defineConfig({
-  source: './src/apis',
+  source: "./src/apis",
   routes: [
     {
-      baseDir: 'controller',
-      basePath: '/api',
+      baseDir: "controller",
+      basePath: "/api",
     },
   ],
 });

+ 6 - 2
package.json

@@ -12,6 +12,7 @@
     "test": "jest"
   },
   "dependencies": {
+    "@midwayjs/bootstrap": "^2.13.4",
     "@midwayjs/hooks": "^2.2.2",
     "@midwayjs/koa": "^2.11.0",
     "@sc/handsontable": "^6.3.11",
@@ -45,15 +46,18 @@
     "@typescript-eslint/parser": "^4.18.0",
     "@vitejs/plugin-vue": "^1.9.3",
     "@vue/cli-plugin-eslint": "~4.5.0",
-    "@vue/eslint-config-airbnb": "^5.0.2",
+    "@vue/eslint-config-airbnb": "^6.0.0",
+    "@vue/eslint-config-prettier": "^6.0.0",
     "@vue/eslint-config-typescript": "^7.0.0",
     "autoprefixer": "^10.4.0",
-    "eslint": "^6.7.2",
+    "eslint": "^7.32.0",
     "eslint-plugin-import": "^2.20.2",
     "eslint-plugin-prettier": "^4.0.0",
     "eslint-plugin-vue": "^7.0.0",
+    "eslint-plugin-vuejs-accessibility": "^1.1.0",
     "jest": "^26.6.3",
     "postcss": "^8.3.11",
+    "prettier": "^2.4.1",
     "sass": "^1.43.4",
     "tailwindcss": "^2.2.19",
     "typescript": "^4.4.3",

+ 1 - 1
postcss.config.js

@@ -3,4 +3,4 @@ module.exports = {
     tailwindcss: {},
     autoprefixer: {},
   },
-}
+};

+ 1 - 2
src/App.vue

@@ -1,5 +1,4 @@
-<script setup lang="ts">
-</script>
+<script setup lang="ts"></script>
 
 <template>
   <router-view />

+ 7 - 7
src/apis/configuration.ts

@@ -1,10 +1,10 @@
-import {hooks, createConfiguration} from '@midwayjs/hooks';
-import bodyParser from 'koa-bodyparser';
+import { hooks, createConfiguration } from "@midwayjs/hooks";
+import bodyParser from "koa-bodyparser";
 
 export default createConfiguration({
-    imports: [
-        hooks({
-            middleware: [bodyParser()],
-        }),
-    ],
+  imports: [
+    hooks({
+      middleware: [bodyParser()],
+    }),
+  ],
 });

+ 5 - 5
src/apis/controller/index.ts

@@ -1,18 +1,18 @@
-import { useContext } from '@midwayjs/hooks';
-import { Context } from '@midwayjs/koa';
+import { useContext } from "@midwayjs/hooks";
+import { Context } from "@midwayjs/koa";
 
 function useKoaContext() {
   return useContext<Context>();
 }
 
 export default async () => {
-  console.log('index方法被调用')
+  console.log("index方法被调用");
   return {
-    message: 'Hello World',
+    message: "Hello World",
     method: useKoaContext().method,
   };
 };
 
 export const post = async (name: string) => {
-  return { method: 'POST', name };
+  return { method: "POST", name };
 };

+ 50 - 28
src/components/context-menu/ContextMenu.vue

@@ -19,11 +19,11 @@
 </template>
 
 <script lang="ts">
-import { defineComponent, ref, PropType, onMounted, watchEffect } from 'vue';
-import { Dropdown, Menu } from 'ant-design-vue';
-import { isFunction } from 'lodash';
-import { on, query } from '@/utils/frontend/dom';
-import ContextSubMenu from './ContextSubMenu.vue';
+import { defineComponent, ref, PropType, onMounted, watchEffect } from "vue";
+import { Dropdown, Menu } from "ant-design-vue";
+import { isFunction } from "lodash";
+import { on, query } from "@/utils/frontend/dom";
+import ContextSubMenu from "./ContextSubMenu.vue";
 
 /*
 对于每个菜单项的 text,我们将其拆解成一个个的 widget
@@ -31,11 +31,11 @@ import ContextSubMenu from './ContextSubMenu.vue';
 */
 interface IWidget {
   // 普通文本或者输入框
-  component: 'text' | 'input';
+  component: "text" | "input";
   // 文本值或者输入框(文本输入框或者数字输入框)的值
   value?: string | number;
   // 输入框的类型
-  type?: 'text' | 'number';
+  type?: "text" | "number";
   // 数字输入框最小值
   min?: number;
   // 数字输入框最大值
@@ -59,7 +59,7 @@ export type MenuItem = IMenuItem;
 export type MenuGroup = IMenuItem[];
 
 export default defineComponent({
-  name: 'ContextMenu',
+  name: "ContextMenu",
   components: { ContextSubMenu, ADropdown: Dropdown, AMenu: Menu },
   props: {
     // 菜单分组列表
@@ -89,7 +89,7 @@ export default defineComponent({
       const inputReg = /({%input.*?%})/;
       const splits: string[] = text.split(inputReg);
       const widgets: IWidget[] = [];
-      splits.forEach(item => {
+      splits.forEach((item) => {
         if (inputReg.test(item)) {
           // 匹配 input 模式字符串
           const attrs = item.match(
@@ -97,32 +97,39 @@ export default defineComponent({
           );
           const metaArr: Common.IStringIndex[] = [];
           if (attrs) {
-            attrs.forEach(attr => {
-              const [key, val] = attr.replace('[', '').replace(']', '').split('=');
+            attrs.forEach((attr) => {
+              const [key, val] = attr
+                .replace("[", "")
+                .replace("]", "")
+                .split("=");
               metaArr.push({
                 [key]: val,
               });
             });
           }
-          let widget: IWidget = { component: 'input' };
+          let widget: IWidget = { component: "input" };
           metaArr.forEach((meta: any) => {
             widget = Object.assign(widget, { ...meta });
           });
-          if (widget.type === 'number') {
+          if (widget.type === "number") {
             widget.min = widget.min ? parseInt(`${widget.min}`, 10) : 1;
             widget.max = widget.max ? parseInt(`${widget.max}`, 10) : 100;
             widget.step = widget.step ? widget.step : 1;
-            widget.precision = widget.precision ? parseInt(`${widget.precision}`, 10) : 0;
-            widget.percent = `${widget.percent}` === 'true';
-            widget.value = widget.value ? parseFloat(`${widget.value}`) : widget.min;
-          } else if (widget.type === 'text') {
-            widget.value = widget.value ? widget.value : '';
+            widget.precision = widget.precision
+              ? parseInt(`${widget.precision}`, 10)
+              : 0;
+            widget.percent = `${widget.percent}` === "true";
+            widget.value = widget.value
+              ? parseFloat(`${widget.value}`)
+              : widget.min;
+          } else if (widget.type === "text") {
+            widget.value = widget.value ? widget.value : "";
           }
           widgets.push(widget);
-        } else if (item.trim() !== '') {
+        } else if (item.trim() !== "") {
           // 普通文本字符串
           widgets.push({
-            component: 'text',
+            component: "text",
             value: item,
           });
         }
@@ -138,14 +145,23 @@ export default defineComponent({
         for (const item of group) {
           const menuItem: MenuItem = {
             text: isFunction(item.text) ? item.text() : item.text,
-            content: getWidgets(isFunction(item.text) ? item.text() : item.text),
+            content: getWidgets(
+              isFunction(item.text) ? item.text() : item.text
+            ),
             icon: item.icon,
             hidden: isFunction(item.hidden) ? item.hidden() : item.hidden,
             // 全局只读优先级最高
             // eslint-disable-next-line no-nested-ternary
-            disable: props.readOnly === true ? true : isFunction(item.disable) ? await item.disable() : item.disable,
+            disable:
+              props.readOnly === true
+                ? true
+                : isFunction(item.disable)
+                ? await item.disable()
+                : item.disable,
             callback: item.callback,
-            submenu: item.submenu ? await reshapeGroups(item.submenu) : undefined,
+            submenu: item.submenu
+              ? await reshapeGroups(item.submenu)
+              : undefined,
           };
           menuGroup.push(menuItem);
         }
@@ -166,17 +182,19 @@ export default defineComponent({
     onMounted(() => {
       const triggerArea = triggerAreaRef.value;
       if (triggerArea) {
-        on(triggerArea, 'contextmenu', async () => {
+        on(triggerArea, "contextmenu", async () => {
           menuGroups.value = await reshapeGroups(props.itemGroups);
         });
 
         if (props.autoSize) {
-          triggerArea.style.height = 'auto';
+          triggerArea.style.height = "auto";
         }
       }
     });
 
-    const randomClass = `context-menu-overlay-${Math.random().toString().slice(2)}`;
+    const randomClass = `context-menu-overlay-${Math.random()
+      .toString()
+      .slice(2)}`;
 
     // 禁用当前 dropdown menu 自身的系统右键上下文菜单
     watchEffect(() => {
@@ -184,9 +202,13 @@ export default defineComponent({
         return;
       }
       setTimeout(() => {
-        const contextMenuOverlay = query(document.body, `.${randomClass}`) as HTMLElement;
+        const contextMenuOverlay = query(
+          document.body,
+          `.${randomClass}`
+        ) as HTMLElement;
         if (contextMenuOverlay) {
-          contextMenuOverlay.oncontextmenu = (e: MouseEvent) => e.preventDefault();
+          contextMenuOverlay.oncontextmenu = (e: MouseEvent) =>
+            e.preventDefault();
         }
       }, 200);
     });

+ 2 - 2
src/composables/useHotRef.ts

@@ -1,5 +1,5 @@
-import { Hot } from '@/types/components';
-import { ref, Ref } from 'vue';
+import { Hot } from "@/types/components";
+import { ref, Ref } from "vue";
 
 // handsontable 组件的模板引用相关代码
 export default function useHotRef() {

+ 22 - 20
src/composables/useProjectID.ts

@@ -1,33 +1,35 @@
-import { ref, watch } from 'vue'
-import { useRoute, useRouter } from 'vue-router'
-import { isNil } from 'lodash'
+import { ref, watch } from "vue";
+import { useRoute, useRouter } from "vue-router";
+import { isNil } from "lodash";
 
 // project 页面及其子页面获取项目 ID
 export default function useProjectID() {
-  const route = useRoute()
-  const router = useRouter()
+  const route = useRoute();
+  const router = useRouter();
 
   // 是否已经获取到了 projectID
-  const shouldRender = ref(false)
+  const shouldRender = ref(false);
 
   // 项目 ID
-  let projectID = ''
-  watch(() => route.query.projectID, (val) => {
-    if (isNil(val) || val === '') {
-      router.replace('/project-list')
-    } else {
-      shouldRender.value = true
-      projectID = val as string
+  let projectID = "";
+  watch(
+    () => route.query.projectID,
+    (val) => {
+      if (isNil(val) || val === "") {
+        router.replace("/project-list");
+      } else {
+        shouldRender.value = true;
+        projectID = val as string;
+      }
+    },
+    {
+      immediate: true,
     }
-  }, {
-    immediate: true
-  })
+  );
 
   return {
     // 是否已经获取到了 projectID, Ref 类型
     shouldRender,
-    projectID
-  }
+    projectID,
+  };
 }
-
-

+ 9 - 9
src/composables/useRefresh.ts

@@ -1,25 +1,25 @@
-import { onUnmounted } from 'vue'
+import { onUnmounted } from "vue";
 // 回调池
-const cbPool: (() => void)[] = []
+const cbPool: (() => void)[] = [];
 
 // 注册顶部按钮刷新回调(组件销毁时,自动销毁回调, 这是推荐的方式)
 export function registerRefreshCallback(cb: () => void) {
-  cbPool.push(cb)
+  cbPool.push(cb);
   onUnmounted(() => {
-    const targetIndex = cbPool.findIndex(item => item === cb)
+    const targetIndex = cbPool.findIndex((item) => item === cb);
     if (targetIndex !== -1) {
-      cbPool.splice(targetIndex, 1)
+      cbPool.splice(targetIndex, 1);
     }
-    console.log('cbPool', cbPool.length)
-  })
+    console.log("cbPool", cbPool.length);
+  });
 }
 
 // 注册顶部按钮刷新回调(组件销毁时,不会自动销毁回调,慎用)
 export function registerRefreshCallbackForever(cb: () => void) {
-  cbPool.push(cb)
+  cbPool.push(cb);
 }
 
 // 调用触发刷新事件回调
 export function invokeAllRefreshCallback() {
-  cbPool.forEach(cb => cb && cb())
+  cbPool.forEach((cb) => cb && cb());
 }

+ 19 - 13
src/composables/useStructureRouter.ts

@@ -1,22 +1,28 @@
-import { watch, ref } from 'vue';
-import { useRoute } from 'vue-router'
-import { SubjectStructure } from '@/constants/subject'
+import { watch, ref } from "vue";
+import { useRoute } from "vue-router";
+import { SubjectStructure } from "@/constants/subject";
 
 // summary 结构类型
 export default function useStructureRouter() {
-  const route = useRoute()
+  const route = useRoute();
 
-  const currentStructure = route.query.structure === SubjectStructure.ARRANGE ? SubjectStructure.ARRANGE : SubjectStructure.RAW
-  const structure = ref<SubjectStructure>(currentStructure)
+  const currentStructure =
+    route.query.structure === SubjectStructure.ARRANGE
+      ? SubjectStructure.ARRANGE
+      : SubjectStructure.RAW;
+  const structure = ref<SubjectStructure>(currentStructure);
 
   // 监听路由 query structure 参数改变
-  watch(() => route.query.structure, val => {
-    if (val !== SubjectStructure.ARRANGE) {
-      structure.value = SubjectStructure.RAW
-    } else {
-      structure.value = SubjectStructure.ARRANGE
+  watch(
+    () => route.query.structure,
+    (val) => {
+      if (val !== SubjectStructure.ARRANGE) {
+        structure.value = SubjectStructure.RAW;
+      } else {
+        structure.value = SubjectStructure.ARRANGE;
+      }
     }
-  })
+  );
 
-  return structure
+  return structure;
 }

+ 0 - 0
src/constants/.gitkeep


+ 6 - 6
src/constants/commonClassName.ts

@@ -1,7 +1,7 @@
-export const classRight = 'htRight htMiddle wcSingleLine';
-export const classLeft = 'htLeft htMiddle wcSingleLine';
-export const classCenter = 'htCenter htMiddle wcSingleLine';
+export const classRight = "htRight htMiddle wcSingleLine";
+export const classLeft = "htLeft htMiddle wcSingleLine";
+export const classCenter = "htCenter htMiddle wcSingleLine";
 
-export const autoClassRight = 'htRight htMiddle';
-export const autoClassLeft = 'htLeft htMiddle';
-export const autoClassCenter = 'htCenter htMiddle';
+export const autoClassRight = "htRight htMiddle";
+export const autoClassLeft = "htLeft htMiddle";
+export const autoClassCenter = "htCenter htMiddle";

+ 70 - 66
src/constants/emitter.ts

@@ -1,138 +1,138 @@
 /* mitt事件相关 */
-import mitt, { Emitter, Handler } from 'mitt';
+import mitt, { Emitter, Handler } from "mitt";
 
 /**
  * mitt事件枚举,分发和监听的事件类型必须在此定义
  */
 export enum EmitterType {
   // 拖动拖拽布局
-  DRAG_BAR_MOVE = 'dragBarMove',
+  DRAG_BAR_MOVE = "dragBarMove",
   // sidebar侧边栏宽度变化
-  SIDEBAR_WIDTH_CHANGE = 'sidebarWidthChange',
+  SIDEBAR_WIDTH_CHANGE = "sidebarWidthChange",
   // 点击了新建项目按钮
-  CLICK_CREATE_PROJECT = 'clickCreateProject',
+  CLICK_CREATE_PROJECT = "clickCreateProject",
   // 重新加载建设项目
-  RELOAD_CONSTRUCTION_PROJECTS = 'reload:construction',
+  RELOAD_CONSTRUCTION_PROJECTS = "reload:construction",
   // 刷新项目管理-全部 表格
-  REFRESH_ALL_TABLE = 'refresh:allTable',
+  REFRESH_ALL_TABLE = "refresh:allTable",
   // 更改了项目管理-全部树
-  UPDATE_ALL_TREE = 'update:allTree',
+  UPDATE_ALL_TREE = "update:allTree",
   // 更改了项目导航树
-  UPDATE_SUBJECT_TREE = 'update:subjectTree',
+  UPDATE_SUBJECT_TREE = "update:subjectTree",
   // 更改(恢复)回收站树
-  UPDATE_RECYCLE_TREE = 'update:recycleTree',
+  UPDATE_RECYCLE_TREE = "update:recycleTree",
   // 点击了回收站的恢复按钮
-  RECYCLE = 'clickRecycle',
+  RECYCLE = "clickRecycle",
   // 点击了彻底删除
-  COMPLETELY_REMOVE = 'clickCompletelyRemove',
+  COMPLETELY_REMOVE = "clickCompletelyRemove",
   // 更改了造价书节点
-  UPDATE_COST_NODE = 'update:costNode',
+  UPDATE_COST_NODE = "update:costNode",
   // 更新了特征及内容文本
-  UPDATE_CONTENT_CHARACTER = 'update:contentCharacter',
+  UPDATE_CONTENT_CHARACTER = "update:contentCharacter",
   // 更新造价书列设置
-  UPDATE_COST_SETTING = 'update:costSetting',
+  UPDATE_COST_SETTING = "update:costSetting",
   // 刷新造价书
-  REFRESH_COST = 'refresh:cost',
+  REFRESH_COST = "refresh:cost",
   // 刷新造价书按钮有效性
-  REFRESH_COST_BUTTON = 'refresh:costButton',
+  REFRESH_COST_BUTTON = "refresh:costButton",
   // 选中造价书节点
-  SELECT_COST = 'select:cost',
+  SELECT_COST = "select:cost",
   // 设置造价书Loading
-  SET_COST_LOADING = 'set:costLoading',
+  SET_COST_LOADING = "set:costLoading",
   // 刷新项目工料机表格
-  REFRESH_PROJECT_GLJ = 'refresh:projectGlj',
+  REFRESH_PROJECT_GLJ = "refresh:projectGlj",
   // 刷新关联材料表格
-  REFRESH_RELATED_MATERIAL = 'refresh:relatedMaterial',
+  REFRESH_RELATED_MATERIAL = "refresh:relatedMaterial",
   // 刷新建设项目级工料机汇总
-  REFRESH_SUMMARY_GLJ = 'refresh:summaryGlj',
+  REFRESH_SUMMARY_GLJ = "refresh:summaryGlj",
   // 切换建设项目工料机汇总表格的loading状态
-  TRIGGER_SUMMARY_LOADING = 'trigger:summaryLoading',
+  TRIGGER_SUMMARY_LOADING = "trigger:summaryLoading",
   // 刷新量价表格
-  REFRESH_VOLUME_PRICE = 'refresh:volumePrice',
+  REFRESH_VOLUME_PRICE = "refresh:volumePrice",
   // 刷新定额工料机表格
-  REFRESH_RATION_GLJ = 'refresh:rationGlj',
+  REFRESH_RATION_GLJ = "refresh:rationGlj",
   // 刷新定额安装增加费表格
-  REFRESH_RATION_INSTALL = 'refresh:rationInstall',
+  REFRESH_RATION_INSTALL = "refresh:rationInstall",
   // 刷新费用修改表格
-  REFRESH_EDIT_RULE = 'refresh:editRule',
+  REFRESH_EDIT_RULE = "refresh:editRule",
   // 刷新计算程序表格
-  REFRESH_CALC_PROGRAM = 'refresh:calcProgram',
+  REFRESH_CALC_PROGRAM = "refresh:calcProgram",
   // 刷新定额子目换算表格
-  REFRESH_RATION_CALC = 'refresh:rationCalc',
+  REFRESH_RATION_CALC = "refresh:rationCalc",
   // 刷新定额库定额列表
-  REFRESH_LIB_RATION = 'refresh:libRation',
+  REFRESH_LIB_RATION = "refresh:libRation",
   // 刷新定额库定额列表列设置
-  UPDATE_LIB_RATION_SETTING = 'refresh:libRationSetting',
+  UPDATE_LIB_RATION_SETTING = "refresh:libRationSetting",
   // 刷新定额模板子目
-  RELOAD_RATION_TEMPLATE = 'refresh:rationTemplate',
+  RELOAD_RATION_TEMPLATE = "refresh:rationTemplate",
   // 刷新信息价表格
-  REFRESH_INFO_PRICE = 'refresh:infoPrice',
+  REFRESH_INFO_PRICE = "refresh:infoPrice",
   // 刷新费率页面表格
-  REFRESH_FEE_RATE = 'refresh:feeRate',
+  REFRESH_FEE_RATE = "refresh:feeRate",
   // 刷新补充定额章节树按钮区有效性
-  REFRESH_RATION_TREE_TOOLS = 'refresh:rationTreeTools',
+  REFRESH_RATION_TREE_TOOLS = "refresh:rationTreeTools",
   // 刷新补充定额表格
-  REFRESH_CPT_RATION = 'refresh:cptRation',
+  REFRESH_CPT_RATION = "refresh:cptRation",
   // 刷新安装增加费用项表格
-  REFRESH_INSTALL_FEE_ITEM = 'refresh:installFeeItem',
+  REFRESH_INSTALL_FEE_ITEM = "refresh:installFeeItem",
   // 项目分享历史变更
-  PROJECT_SHARE_HISTORY_CHANGED = 'projectShareHistoryChanged',
+  PROJECT_SHARE_HISTORY_CHANGED = "projectShareHistoryChanged",
   // 定额库分享历史变更
-  RATION_LIB_SHARE_HISTORY_CHANGED = 'rationLibShareHistoryChanged',
+  RATION_LIB_SHARE_HISTORY_CHANGED = "rationLibShareHistoryChanged",
   // 人材机库分享历史变更
-  GLJ_LIB_SHARE_HISTORY_CHANGED = 'gljLibShareHistoryChanged',
+  GLJ_LIB_SHARE_HISTORY_CHANGED = "gljLibShareHistoryChanged",
   // 更新了子目换算总表数据
-  UPDATE_CPT_COE = 'update:cptCoe',
+  UPDATE_CPT_COE = "update:cptCoe",
   // 关闭计算基数弹窗
-  CLOSE_FORMULA_POPUP = 'close:formulaPopup',
+  CLOSE_FORMULA_POPUP = "close:formulaPopup",
   // 打开库标签
-  OPEN_LIB_TAB = 'open:libTab',
+  OPEN_LIB_TAB = "open:libTab",
   // 添加新成员
-  ADD_NEW_MEMBER = 'addNewMember',
+  ADD_NEW_MEMBER = "addNewMember",
   // 打开消息中心
-  OPEN_NOTIFICATION = 'openNotification',
+  OPEN_NOTIFICATION = "openNotification",
   // 未读消息数量变化
-  UNREAD_COUNT_CHANGE = 'unreadCountChange',
+  UNREAD_COUNT_CHANGE = "unreadCountChange",
   // 新消息
-  NEW_MESSAGE = 'newMessage',
+  NEW_MESSAGE = "newMessage",
   // 离开 socket 房间
-  LEAVE_ROOM = 'leaveRoom',
+  LEAVE_ROOM = "leaveRoom",
   // 刷新工料机库显示(按选中类别)
-  REFRESH_CPT_GLJ_LIB = 'refresh:cptGljLib',
+  REFRESH_CPT_GLJ_LIB = "refresh:cptGljLib",
   // 变更补充定额库
-  CHANGE_CPT_RATION_LIB = 'change:cptRationLib',
+  CHANGE_CPT_RATION_LIB = "change:cptRationLib",
   // 变更补充人材机库
-  CHANGE_CPT_GLJ_LIB = 'change:cptGljLib',
+  CHANGE_CPT_GLJ_LIB = "change:cptGljLib",
   // 刷新书签批注
-  REFRESH_BOOKMARK = 'refresh:bookmark',
+  REFRESH_BOOKMARK = "refresh:bookmark",
   // 更新显示/隐藏特征按钮
-  UPDATE_SHOW_FEATURE = 'update:isShowFeature',
+  UPDATE_SHOW_FEATURE = "update:isShowFeature",
   // 造价单书签批注用,hover事件计数器
-  CLEAR_CELL_HOVER_LIST = 'clear:cellHoverList',
+  CLEAR_CELL_HOVER_LIST = "clear:cellHoverList",
   // 清空人材机组成物
-  CLEAR_GLJ_COMPONENT = 'clear:gljComponent',
+  CLEAR_GLJ_COMPONENT = "clear:gljComponent",
   // 刷新建设项目分享标记
-  REFRESH_CONSTRUCTION_SHARE_MARK = 'refresh:constructionShareMark',
+  REFRESH_CONSTRUCTION_SHARE_MARK = "refresh:constructionShareMark",
   // 单位工程信息指标表格刷新
-  REFRESH_TARGET_GRID = 'refresh:targetGrid',
+  REFRESH_TARGET_GRID = "refresh:targetGrid",
   // 刷新建设项目汇总
-  REFRESH_CONSTRUCTION_SUMMARY = 'refresh:constructionSummary',
+  REFRESH_CONSTRUCTION_SUMMARY = "refresh:constructionSummary",
   // 刷新分享项目数据
-  REFRESH_SHARE_PROJECT = 'refresh:shareProject',
+  REFRESH_SHARE_PROJECT = "refresh:shareProject",
   // 刷新分享定额库数据
-  REFRESH_SHARE_RATION_LIB = 'refresh:shareRationLib',
+  REFRESH_SHARE_RATION_LIB = "refresh:shareRationLib",
   // 刷新分享人材机库数据
-  REFRESH_SHARE_GLJ_LIB = 'refresh:shareGljLib',
+  REFRESH_SHARE_GLJ_LIB = "refresh:shareGljLib",
   // 追加定额库选项
-  APPEND_RATION_LIB_OPTION = 'append:rationLibOption',
+  APPEND_RATION_LIB_OPTION = "append:rationLibOption",
   // 追加人材机库选项
-  APPEND_GLJ_LIB_OPTION = 'append:gljLibOption',
+  APPEND_GLJ_LIB_OPTION = "append:gljLibOption",
   // 移除定额库选项
-  REMOVE_RATION_LIB_OPTION = 'remove:rationLibOption',
+  REMOVE_RATION_LIB_OPTION = "remove:rationLibOption",
   // 移除人材机库选项
-  REMOVE_GLJ_LIB_OPTION = 'remove:gljLibOption',
+  REMOVE_GLJ_LIB_OPTION = "remove:gljLibOption",
   // 刷新项目权限
-  REFRESH_PROJECT_PERMISSION = 'refresh:projectPermission',
+  REFRESH_PROJECT_PERMISSION = "refresh:projectPermission",
 }
 
 // 单例的emitter(有些事件不能用单例,可能会有多建设项目页面)
@@ -159,7 +159,11 @@ export const getEmitter = (key?: string) => {
      * !!!注意!!!:emit监听时,按需增加监听事件名称,同一类型下,不可有重复监听事件名称
      * 由于组件可能多次渲染(多次进入setup方法),为了避免重复监听事件。
      */
-    on<T = any>(emitterType: EmitterType, handler: Handler<T>, listenerName?: string) {
+    on<T = any>(
+      emitterType: EmitterType,
+      handler: Handler<T>,
+      listenerName?: string
+    ) {
       const listenerKey = `${emitterType}-${listenerName}`;
       if (listenedMap[listenerKey]) {
         this.off(emitterType, listenedMap[listenerKey]);

+ 20 - 20
src/constants/provideInject.ts

@@ -1,30 +1,30 @@
 // provide/inject枚举
 enum ProvideInject {
-  DIRECTION = 'direction',
-  DEBOUNCE = 'debounce',
-  MAX_WAIT = 'maxWait',
+  DIRECTION = "direction",
+  DEBOUNCE = "debounce",
+  MAX_WAIT = "maxWait",
   // BAR_WIDTH = 'barWidth',
   // DOTTED = 'dotted',
-  SUBJECT_TREE_DATA = 'subjectTreeData',
-  CUR_TAB_VUEX = 'currentTabVuexData',
-  CUR_PM_TAB = 'currentProjectManageTab',
-  CONSTRUCTION_ID = 'constructionID',
-  CONSTRUCTION_READONLY = 'constructionReadOnly',
-  SINGLE_ID = 'singleID',
-  SINGLE_READONLY = 'singleReadOnly',
-  UNIT_ID = 'unitID',
-  UNIT_READONLY = 'unitReadOnly',
-  UNIT_ACTIVE_KEY = 'unitActiveKey',
-  GLJ_NAV_KEY = 'GljNavKey',
-  COST_SELECTED_ROW_DATA = 'costSelectedRowData',
-  SELECTED_PROJECT_GLJ = 'selectedProjectGLJ',
-  USER_INFO = 'userInfo',
+  SUBJECT_TREE_DATA = "subjectTreeData",
+  CUR_TAB_VUEX = "currentTabVuexData",
+  CUR_PM_TAB = "currentProjectManageTab",
+  CONSTRUCTION_ID = "constructionID",
+  CONSTRUCTION_READONLY = "constructionReadOnly",
+  SINGLE_ID = "singleID",
+  SINGLE_READONLY = "singleReadOnly",
+  UNIT_ID = "unitID",
+  UNIT_READONLY = "unitReadOnly",
+  UNIT_ACTIVE_KEY = "unitActiveKey",
+  GLJ_NAV_KEY = "GljNavKey",
+  COST_SELECTED_ROW_DATA = "costSelectedRowData",
+  SELECTED_PROJECT_GLJ = "selectedProjectGLJ",
+  USER_INFO = "userInfo",
   // 当前定额库ID
-  CPT_RATION_LIB_ID = 'cptRationLibID',
+  CPT_RATION_LIB_ID = "cptRationLibID",
   // 选中的补充定额章节树节点
-  CPT_RATION_TREE_SELECTED = 'cptRationTreeSelected',
+  CPT_RATION_TREE_SELECTED = "cptRationTreeSelected",
   // 选中的补充定额
-  CPT_RATION_SELECTED = 'cptRationSelected',
+  CPT_RATION_SELECTED = "cptRationSelected",
 }
 
 export default ProvideInject;

+ 5 - 5
src/constants/subject.ts

@@ -1,10 +1,10 @@
 export enum SubjectTreeNodeType {
-    CONSTRUCTION = 'construction',
-    SINGLE = 'single',
-    UNIT = 'unit'
+  CONSTRUCTION = "construction",
+  SINGLE = "single",
+  UNIT = "unit",
 }
 
 export enum SubjectStructure {
-    RAW = 'raw',
-    ARRANGE = 'arrange'
+  RAW = "raw",
+  ARRANGE = "arrange",
 }

+ 48 - 42
src/constants/tmp/table-columns-meta.ts

@@ -1,76 +1,82 @@
 /* subject 中 revise 的 columns meta */
 const subjectRevise = [
-  { title: '项目编码', data: 'code', renderer: 'wc.switcherRenderer', readOnly: true, width: 170 },
-  { title: '项目名称', data: 'name', width: 200 },
-  { title: '计量单位', data: 'unit', width: 60 },
-  { title: '工程量', data: 'count', type: 'numeric', width: 70 },
   {
-    title: '综合单价(初始)',
-    data: 'initPrice',
-    type: 'numeric',
-    numericFormat: { pattern: '0,0.00' },
+    title: "项目编码",
+    data: "code",
+    renderer: "wc.switcherRenderer",
+    readOnly: true,
+    width: 170,
+  },
+  { title: "项目名称", data: "name", width: 200 },
+  { title: "计量单位", data: "unit", width: 60 },
+  { title: "工程量", data: "count", type: "numeric", width: 70 },
+  {
+    title: "综合单价(初始)",
+    data: "initPrice",
+    type: "numeric",
+    numericFormat: { pattern: "0,0.00" },
     width: 100,
   },
   {
-    title: '综合合价(初始)',
-    data: 'initAllPrice',
-    type: 'numeric',
-    numericFormat: { pattern: '0,0.00' },
+    title: "综合合价(初始)",
+    data: "initAllPrice",
+    type: "numeric",
+    numericFormat: { pattern: "0,0.00" },
     width: 100,
   },
   {
-    title: '综合单价(目标)',
-    data: 'targetPrice',
-    type: 'numeric',
-    numericFormat: { pattern: '0,0.00' },
+    title: "综合单价(目标)",
+    data: "targetPrice",
+    type: "numeric",
+    numericFormat: { pattern: "0,0.00" },
     width: 100,
   },
   {
-    title: '综合合价(目标)',
-    data: 'targetAllPrice',
-    type: 'numeric',
-    numericFormat: { pattern: '0,0.00' },
+    title: "综合合价(目标)",
+    data: "targetAllPrice",
+    type: "numeric",
+    numericFormat: { pattern: "0,0.00" },
     width: 100,
   },
   {
-    title: '综合单价(调整)',
-    data: 'adjustPrice',
-    type: 'numeric',
-    numericFormat: { pattern: '0,0.00' },
+    title: "综合单价(调整)",
+    data: "adjustPrice",
+    type: "numeric",
+    numericFormat: { pattern: "0,0.00" },
     width: 100,
   },
   {
-    title: '综合合价(调整)',
-    data: 'adjustAllPrice',
-    type: 'numeric',
-    numericFormat: { pattern: '0,0.00' },
+    title: "综合合价(调整)",
+    data: "adjustAllPrice",
+    type: "numeric",
+    numericFormat: { pattern: "0,0.00" },
     width: 100,
   },
   {
-    title: '人工',
-    data: 'labour',
-    type: 'numeric',
+    title: "人工",
+    data: "labour",
+    type: "numeric",
     width: 80,
   },
   {
-    title: '材料',
-    data: 'material',
-    type: 'numeric',
+    title: "材料",
+    data: "material",
+    type: "numeric",
     width: 80,
   },
   {
-    title: '机械',
-    data: 'mechanics',
-    type: 'numeric',
+    title: "机械",
+    data: "mechanics",
+    type: "numeric",
     width: 80,
   },
   {
-    title: '主材',
-    data: 'mainMaterial',
-    type: 'numeric',
+    title: "主材",
+    data: "mainMaterial",
+    type: "numeric",
     width: 80,
   },
-  { title: '设备', data: 'device', type: 'numeric', width: 80 },
-  { title: '子目工程量调整系数', data: 'coe', type: 'numeric', width: 80 },
+  { title: "设备", data: "device", type: "numeric", width: 80 },
+  { title: "子目工程量调整系数", data: "coe", type: "numeric", width: 80 },
 ];
 export default subjectRevise;

+ 6 - 8
src/examples/Examples.vue

@@ -1,15 +1,13 @@
 <script setup lang="ts">
 import { ref, reactive, onMounted } from "vue";
-import { Input as AInput, InputNumber as AInputNumber } from 'ant-design-vue';
-
+import { Input as AInput, InputNumber as AInputNumber } from "ant-design-vue";
 </script>
 
 <template>
-    <article class="examples-page">
-        <h1>哈哈哈</h1>
-        <a-input />
-    </article>
+  <article class="examples-page">
+    <h1>哈哈哈</h1>
+    <a-input />
+  </article>
 </template>
 
-<style lang="scss" scoped>
-</style>
+<style lang="scss" scoped></style>

+ 11 - 11
src/main.ts

@@ -1,13 +1,13 @@
-import { createApp } from 'vue'
-import App from './App.vue'
-import ElementPlus from 'element-plus'
-import zhCn from 'element-plus/es/locale/lang/zh-cn'
-import '@/styles/index.scss';
-import router from './router';
-import register from '@/components';
+import { createApp } from "vue";
+import App from "./App.vue";
+import ElementPlus from "element-plus";
+import zhCn from "element-plus/es/locale/lang/zh-cn";
+import "@/styles/index.scss";
+import router from "./router";
+import register from "@/components";
 
 const app = createApp(App);
-app.use(ElementPlus, { size: 'mini', locale: zhCn, })
-app.use(router)
-register(app)
-app.mount('#app')
+app.use(ElementPlus, { size: "mini", locale: zhCn });
+app.use(router);
+register(app);
+app.mount("#app");

+ 61 - 61
src/router/index.ts

@@ -1,70 +1,70 @@
-import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
+import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
 
 const routes: Array<RouteRecordRaw> = [
-    {
-        path: '/',
-        name: 'MainFrame',
-        component: () => import('@/views/main-frame/MainFrame.vue'),
+  {
+    path: "/",
+    name: "MainFrame",
+    component: () => import("@/views/main-frame/MainFrame.vue"),
+    children: [
+      {
+        path: "",
+        name: "Workbench",
+        component: () => import("@/views/workbench/Workbench.vue"),
+      },
+      {
+        path: "project-list",
+        name: "ProjectList",
+        component: () => import("@/views/project-list/ProjectList.vue"),
+      },
+      {
+        path: "data-library",
+        name: "DataLibrary",
+        component: () => import("@/views/data-library/DataLibrary.vue"),
+      },
+      {
+        path: "project",
+        name: "Project",
+        component: () => import("@/views/project/Project.vue"),
         children: [
-            {
-                path: '',
-                name: 'Workbench',
-                component: () => import('@/views/workbench/Workbench.vue'),
-            },
-            {
-                path: 'project-list',
-                name: 'ProjectList',
-                component: () => import('@/views/project-list/ProjectList.vue'),
-            },
-            {
-                path: 'data-library',
-                name: 'DataLibrary',
-                component: () => import('@/views/data-library/DataLibrary.vue'),
-            },
-            {
-                path: 'project',
-                name: 'Project',
-                component: () => import('@/views/project/Project.vue'),
-                children: [
-                    {
-                        path: '',
-                        name: 'Overview',
-                        component: () => import('@/views/project/overview/Overview.vue')
-                    },
-                    {
-                        path: 'process',
-                        name: 'Process',
-                        component: () => import('@/views/project/process/Process.vue')
-                    },
-                    {
-                        path: 'summary',
-                        name: 'Summary',
-                        component: () => import('@/views/project/summary/Summary.vue')
-                    },
-                    {
-                        path: 'report',
-                        name: 'Report',
-                        component: () => import('@/views/project/report/Report.vue')
-                    }
-                ]
-            }
-        ]
-    },
-    {
-        path: '/login',
-        name: 'Login',
-        component: () => import('@/views/login/Login.vue'),
-    },
-    {
-        path: '/examples',
-        name: 'Examples',
-        component: () => import('@/examples/Examples.vue')
-    }
+          {
+            path: "",
+            name: "Overview",
+            component: () => import("@/views/project/overview/Overview.vue"),
+          },
+          {
+            path: "process",
+            name: "Process",
+            component: () => import("@/views/project/process/Process.vue"),
+          },
+          {
+            path: "summary",
+            name: "Summary",
+            component: () => import("@/views/project/summary/Summary.vue"),
+          },
+          {
+            path: "report",
+            name: "Report",
+            component: () => import("@/views/project/report/Report.vue"),
+          },
+        ],
+      },
+    ],
+  },
+  {
+    path: "/login",
+    name: "Login",
+    component: () => import("@/views/login/Login.vue"),
+  },
+  {
+    path: "/examples",
+    name: "Examples",
+    component: () => import("@/examples/Examples.vue"),
+  },
 ];
 
 const router = createRouter({
-    history: createWebHistory(import.meta.env.BASE_URL),
-    routes,
+  history: createWebHistory(import.meta.env.BASE_URL),
+  routes,
 });
 
 export default router;

+ 8 - 8
src/store/.localmodules.ts

@@ -1,23 +1,23 @@
 // import { isShareHref } from '@/utils/share';
 
 interface IConfig {
-  key?: string; // localStorage(sessionStorage) 的键名,默认是 vuex
-  paths: string[]; // 需要本地持久化的 vuex 模块名称
-  storage: Storage; // 使用不同的 storage 对象存储
+    key?: string; // localStorage(sessionStorage) 的键名,默认是 vuex
+    paths: string[]; // 需要本地持久化的 vuex 模块名称
+    storage: Storage; // 使用不同的 storage 对象存储
 }
 
 
 // 获取storage对象
 const getStorage = (): Storage => {
-  // 如果是进入分享链接项目,只需要session持久化,避免与正常项目localStorage冲突
-  // return isShareHref() ? window.sessionStorage : window.localStorage;
-  return window.localStorage;
+    // 如果是进入分享链接项目,只需要session持久化,避免与正常项目localStorage冲突
+    // return isShareHref() ? window.sessionStorage : window.localStorage;
+    return window.localStorage;
 };
 
 // 需要本地持久化的 vuex 模块名称
 const config: IConfig = {
-  paths: ['summaryLayout'],
-  storage: getStorage(),
+    paths: ['summaryLayout'],
+    storage: getStorage(),
 };
 
 export default config;

+ 12 - 6
src/store/DynamicModule.ts

@@ -1,9 +1,9 @@
-import { Module } from 'vuex-module-decorators';
-import storeInstance from '@/store';
-import { Store } from 'vuex';
-import options from './.localmodules';
+import { Module } from "vuex-module-decorators";
+import storeInstance from "@/store";
+import { Store } from "vuex";
+import options from "./.localmodules";
 
-const { paths, key = 'vuex', storage } = options;
+const { paths, key = "vuex", storage } = options;
 
 export interface IOptions {
   namespaced?: boolean;
@@ -13,7 +13,13 @@ export interface IOptions {
   preserveState?: boolean;
 }
 
-function DynamicModule({ namespaced = true, dynamic = true, name, store = storeInstance, preserveState }: IOptions) {
+function DynamicModule({
+  namespaced = true,
+  dynamic = true,
+  name,
+  store = storeInstance,
+  preserveState,
+}: IOptions) {
   if (preserveState === undefined) {
     const modulesStr = storage.getItem(key);
     if (paths.includes(name) && modulesStr != null) {

+ 3 - 3
src/store/createStorageState.ts

@@ -1,7 +1,7 @@
-import createPersistedState from 'vuex-persistedstate';
-import options from './.localmodules';
+import createPersistedState from "vuex-persistedstate";
+import options from "./.localmodules";
 
-const { key = 'vuex', paths, storage } = options;
+const { key = "vuex", paths, storage } = options;
 
 const createStorageState = () => {
   return createPersistedState({

+ 2 - 2
src/store/index.ts

@@ -1,5 +1,5 @@
-import { createStore } from 'vuex';
-import createStorageState from './createStorageState';
+import { createStore } from "vuex";
+import createStorageState from "./createStorageState";
 
 export default createStore({
   modules: {},

+ 12 - 10
src/store/modules/breadcrumb.ts

@@ -1,21 +1,23 @@
-import { VuexModule, Module, getModule, Mutation } from 'vuex-module-decorators';
-import store from '@/store';
+import {
+  VuexModule,
+  Module,
+  getModule,
+  Mutation,
+} from "vuex-module-decorators";
+import store from "@/store";
 
 export interface IBreadcrumbItem {
-  label: string,
-  path?: string
+  label: string;
+  path?: string;
 }
 
-@Module({ namespaced: true, name: 'breadcrumb', dynamic: true, store })
+@Module({ namespaced: true, name: "breadcrumb", dynamic: true, store })
 export class Breadcrumb extends VuexModule {
-
-  breadcrumbs: IBreadcrumbItem[] = [
-    { label: '首页', path: '/' },
-  ]
+  breadcrumbs: IBreadcrumbItem[] = [{ label: "首页", path: "/" }];
 
   @Mutation
   setBreadcrumb(breadcrumbs: IBreadcrumbItem[]) {
-    this.breadcrumbs.splice(1, this.breadcrumbs.length - 1, ...breadcrumbs)
+    this.breadcrumbs.splice(1, this.breadcrumbs.length - 1, ...breadcrumbs);
   }
 }
 

+ 25 - 19
src/store/modules/summaryLayout.ts

@@ -1,58 +1,64 @@
-import { VuexModule, Mutation, getModule } from 'vuex-module-decorators';
-import DynamicModule from '../DynamicModule';
+import { VuexModule, Mutation, getModule } from "vuex-module-decorators";
+import DynamicModule from "../DynamicModule";
 
-@DynamicModule({ name: 'summaryLayout' })
+@DynamicModule({ name: "summaryLayout" })
 export class SummaryLayout extends VuexModule {
-  subjectTreeSize = 60
-  mainContentSize = 300
-  mainLeftSize = 150
-  mainRightSize = 50
-  mainLeftTopSize = 300
-  mainLeftBottomSize = 50
+  subjectTreeSize = 60;
+
+  mainContentSize = 300;
+
+  mainLeftSize = 150;
+
+  mainRightSize = 50;
+
+  mainLeftTopSize = 300;
+
+  mainLeftBottomSize = 50;
 
   // 右侧标准清单可见性
-  rightStdBillVisible = false
+  rightStdBillVisible = false;
+
   // 右侧定额库可见性
-  rightLibRationVisible = false
+  rightLibRationVisible = false;
 
   @Mutation
   setSubjectTreeSize(size: number) {
-    this.subjectTreeSize = size
+    this.subjectTreeSize = size;
   }
 
   @Mutation
   setMainContentSize(size: number) {
-    this.mainContentSize = size
+    this.mainContentSize = size;
   }
 
   @Mutation
   setMainLeftSize(size: number) {
-    this.mainLeftSize = size
+    this.mainLeftSize = size;
   }
 
   @Mutation
   setMainRightSize(size: number) {
-    this.mainRightSize = size
+    this.mainRightSize = size;
   }
 
   @Mutation
   setMainLeftTopSize(size: number) {
-    this.mainLeftTopSize = size
+    this.mainLeftTopSize = size;
   }
 
   @Mutation
   setMainLeftBottomSize(size: number) {
-    this.mainLeftBottomSize = size
+    this.mainLeftBottomSize = size;
   }
 
   @Mutation
   setRightStdBillVisible(visible: boolean) {
-    this.rightStdBillVisible = visible
+    this.rightStdBillVisible = visible;
   }
 
   @Mutation
   setRightLibRationVisible(visible: boolean) {
-    this.rightLibRationVisible = visible
+    this.rightLibRationVisible = visible;
   }
 }
 

+ 1 - 1
src/styles/_main.scss

@@ -7,7 +7,7 @@ html {
     width: 100%;
     height: 100%;
     font-family: "微软雅黑", "Microsoft YaHei", "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial,
-      sans-serif;
+    sans-serif;
     -webkit-font-smoothing: antialiased; /*chrome、safari*/
     -moz-osx-font-smoothing: grayscale; /*firefox*/
     -webkit-text-size-adjust: none;

+ 0 - 0
src/types/.gitkeep


+ 7 - 7
src/types/common.d.ts

@@ -1,9 +1,9 @@
 declare namespace Common {
-    interface IStringIndex {
-        [key: string]: any;
-    }
+  interface IStringIndex {
+    [key: string]: any;
+  }
 
-    interface IRender {
-        Render: () => void;
-    }
-}
+  interface IRender {
+    Render: () => void;
+  }
+}

+ 147 - 137
src/types/components.d.ts

@@ -1,149 +1,159 @@
-import Handsontable, { GridSettings } from '@sc/handsontable';
+import Handsontable, { GridSettings } from "@sc/handsontable";
 
 declare namespace ContextMenu {
-    interface IContextMenuComponent {
-        // 隐藏
-        Hide: () => void;
-    }
-
-    // 菜单项的每一个 item
-    interface IMenuItem {
-        text: (() => string) | string;
-        icon?: string;
-        hidden?: (() => boolean) | boolean;
-        disable?: (() => Promise<boolean> | boolean) | boolean;
-        callback?: (inputVal?: number | string) => void;
-        submenu?: IMenuItem[][];
-    }
-
-    // 菜单项分组
-    type MenuGroup = IMenuItem[];
+  interface IContextMenuComponent {
+    // 隐藏
+    Hide: () => void;
+  }
+
+  // 菜单项的每一个 item
+  interface IMenuItem {
+    text: (() => string) | string;
+    icon?: string;
+    hidden?: (() => boolean) | boolean;
+    disable?: (() => Promise<boolean> | boolean) | boolean;
+    callback?: (inputVal?: number | string) => void;
+    submenu?: IMenuItem[][];
+  }
+
+  // 菜单项分组
+  type MenuGroup = IMenuItem[];
 }
 
 declare namespace ResizableLayout {
-    interface IDataParam {
-        index: number;
-        instance: any;
-        minSize: number;
-    }
-
-    interface IMoveParam {
-        index: number; // 当前layoutItem是父组件的第几个子组件
-        distance: number; // 鼠标移动的距离,负数代表左移,正数代表右移
-        moveId: symbol; // move事件的唯一标志
-    }
-
-    interface IResizableLayoutComponent {
-        Refresh: () => void;
-    }
+  interface IDataParam {
+    index: number;
+    instance: any;
+    minSize: number;
+  }
+
+  interface IMoveParam {
+    index: number; // 当前layoutItem是父组件的第几个子组件
+    distance: number; // 鼠标移动的距离,负数代表左移,正数代表右移
+    moveId: symbol; // move事件的唯一标志
+  }
+
+  interface IResizableLayoutComponent {
+    Refresh: () => void;
+  }
 }
 
-
 type Renderer = (
-    instance: Handsontable,
-    TD: HTMLElement,
-    row: number,
-    col: number,
-    prop: string | number,
-    value: any,
-    cellProperties: GridSettings
+  instance: Handsontable,
+  TD: HTMLElement,
+  row: number,
+  col: number,
+  prop: string | number,
+  value: any,
+  cellProperties: GridSettings
 ) => HTMLElement;
 
 declare namespace Hot {
-    interface IHandsontableComponent {
-        // 重新渲染(如容器宽高发生改变),供外界调用
-        Render: () => void;
-        // 更新 Settings,供外界调用(如增加或减少列)
-        Update: (settings: any) => void;
-        // 重新加载数据(如引用的数据发生改变),供外界调用
-        Load: (data?: any) => void;
-        // 获取 instance,供外界调用
-        GetInstance: () => Handsontable;
-    }
-
-    interface ICoords {
-        startRow: number;
-        startCol: number;
-        endRow: number;
-        endCol: number;
-    }
-
-    interface IColumnMeta {
-        title: string;
-        data: string;
-        renderer?: | string | Renderer | ((
-            instance: Handsontable,
-            td: HTMLElement,
-            row: number,
-            col: number,
-            prop: string | number,
-            value: any,
-            cellProperties: IColumnMeta
+  interface IHandsontableComponent {
+    // 重新渲染(如容器宽高发生改变),供外界调用
+    Render: () => void;
+    // 更新 Settings,供外界调用(如增加或减少列)
+    Update: (settings: any) => void;
+    // 重新加载数据(如引用的数据发生改变),供外界调用
+    Load: (data?: any) => void;
+    // 获取 instance,供外界调用
+    GetInstance: () => Handsontable;
+  }
+
+  interface ICoords {
+    startRow: number;
+    startCol: number;
+    endRow: number;
+    endCol: number;
+  }
+
+  interface IColumnMeta {
+    title: string;
+    data: string;
+    renderer?:
+      | string
+      | Renderer
+      | ((
+          instance: Handsontable,
+          td: HTMLElement,
+          row: number,
+          col: number,
+          prop: string | number,
+          value: any,
+          cellProperties: IColumnMeta
         ) => void);
-        editor?: string;
-        readOnly?: boolean;
-        showButton?: boolean; // 默认readOnly为true时,右上角的按钮也不显示,对于readOnly为true,又要显示按钮的情况,这里也要设置为true
-        width: number;
-        // 小数位数,如果存在此项配置,搭配'wc.numeric' cellType后,会将数值string转换为number,并进行四舍五入
-        decimal?: number | (() => number);
-        // 允许输入空值,转换成null
-        numberAllowEmpty?: boolean;
-        type?: string;
-        checkedTemplate?: any;
-        uncheckedTemplate?: any;
-        numericFormat?: { pattern?: string; zeroFormat?: string };
-        source?: string[] | any[];
-        className?: string;
-        required?: boolean;
-        isTemporary?: boolean;
-    }
-
-    type MouseKey = 'left' | 'middle' | 'right';
-    type ClickPosition = 'outside' | 'barren' | 'content';
-
-    interface IGroupHeaderCell {
-        label: string;
-        colspan?: number;
-        rowspan?: number;
-    }
-
-    type GroupHeaderCell = IGroupHeaderCell | string;
-
-    interface ISettings extends GridSettings {
-        columnsMeta?: IColumnMeta[];
-        /**
-         * 获取鼠标点击的区域
-         * @param isOutside 是否在表格外面
-         * @param isBarren 是否在表格内部的空白区域
-         * @param isContent 是否在表格内容的内同区域
-         */
-        onClickPosition?: (whichKey: MouseKey, clickPosition: ClickPosition) => void;
-        // 表头分组
-        groupingHeaders?: GroupHeaderCell[][];
-        // contextMenu?: { callback: (...args: any) => void; items: any };
-    }
-
-    interface IHandsontableProps {
-        data: any[];
-        settings: ISettings;
-        tree: boolean;
-        readOnly: boolean;
-        border: string;
-        loading: boolean;
-    }
-
-    interface IRenderer {
-        (
-            instance: Handsontable,
-            row: number,
-            col: number,
-            prop: string | number,
-            value: any,
-            cellProperties: GridSettings
-        ): HTMLElement;
-    }
-
-    type CellChangeParam = [/* row */ number, /* prop */ string, /* oldValue */ any, /* newValue */ any];
-
-    type RendererItem = [string, ComponentObjectPropsOptions | IRenderer];
-}
+    editor?: string;
+    readOnly?: boolean;
+    showButton?: boolean; // 默认readOnly为true时,右上角的按钮也不显示,对于readOnly为true,又要显示按钮的情况,这里也要设置为true
+    width: number;
+    // 小数位数,如果存在此项配置,搭配'wc.numeric' cellType后,会将数值string转换为number,并进行四舍五入
+    decimal?: number | (() => number);
+    // 允许输入空值,转换成null
+    numberAllowEmpty?: boolean;
+    type?: string;
+    checkedTemplate?: any;
+    uncheckedTemplate?: any;
+    numericFormat?: { pattern?: string; zeroFormat?: string };
+    source?: string[] | any[];
+    className?: string;
+    required?: boolean;
+    isTemporary?: boolean;
+  }
+
+  type MouseKey = "left" | "middle" | "right";
+  type ClickPosition = "outside" | "barren" | "content";
+
+  interface IGroupHeaderCell {
+    label: string;
+    colspan?: number;
+    rowspan?: number;
+  }
+
+  type GroupHeaderCell = IGroupHeaderCell | string;
+
+  interface ISettings extends GridSettings {
+    columnsMeta?: IColumnMeta[];
+    /**
+     * 获取鼠标点击的区域
+     * @param isOutside 是否在表格外面
+     * @param isBarren 是否在表格内部的空白区域
+     * @param isContent 是否在表格内容的内同区域
+     */
+    onClickPosition?: (
+      whichKey: MouseKey,
+      clickPosition: ClickPosition
+    ) => void;
+    // 表头分组
+    groupingHeaders?: GroupHeaderCell[][];
+    // contextMenu?: { callback: (...args: any) => void; items: any };
+  }
+
+  interface IHandsontableProps {
+    data: any[];
+    settings: ISettings;
+    tree: boolean;
+    readOnly: boolean;
+    border: string;
+    loading: boolean;
+  }
+
+  interface IRenderer {
+    (
+      instance: Handsontable,
+      row: number,
+      col: number,
+      prop: string | number,
+      value: any,
+      cellProperties: GridSettings
+    ): HTMLElement;
+  }
+
+  type CellChangeParam = [
+    /* row */ number,
+    /* prop */ string,
+    /* oldValue */ any,
+    /* newValue */ any
+  ];
+
+  type RendererItem = [string, ComponentObjectPropsOptions | IRenderer];
+}

+ 16 - 16
src/types/subject.d.ts

@@ -1,20 +1,20 @@
-import { SubjectTreeNodeType } from '@/constants/subject'
+import { SubjectTreeNodeType } from "@/constants/subject";
 
 declare namespace Subject {
-    interface ISubjectTreeNode {
-        id: string;
-        label: string;
-        icon?: string;
-        type: SubjectTreeNodeType;
-        children?: ISubjectTreeNode[];
-    }
+  interface ISubjectTreeNode {
+    id: string;
+    label: string;
+    icon?: string;
+    type: SubjectTreeNodeType;
+    children?: ISubjectTreeNode[];
+  }
 
-    interface IRightVisible {
-        stdBillVisible: boolean;
-        libRationVisible: boolean;
+  interface IRightVisible {
+    stdBillVisible: boolean;
+    libRationVisible: boolean;
 
-        // searchLocationVisible: boolean;
-        // priceTemplateVisible: boolean;
-        // bookmarkVisible: boolean;
-    }
-}
+    // searchLocationVisible: boolean;
+    // priceTemplateVisible: boolean;
+    // bookmarkVisible: boolean;
+  }
+}

+ 46 - 32
src/utils/common/tools.ts

@@ -1,15 +1,29 @@
 /* eslint-disable import/prefer-default-export */
-export const replaceAll = (FindText: RegExp | string, RepText: string, str: string): string => {
-  const regExp = new RegExp(FindText, 'g');
+export const replaceAll = (
+  FindText: RegExp | string,
+  RepText: string,
+  str: string
+): string => {
+  const regExp = new RegExp(FindText, "g");
   return str.replace(regExp, RepText);
 };
 
 // 全局替换 字符串(处理字符串内有需要转义的字符 如:'()')
-export const replaceStrAll = (replaceThis: string, withThis: string, inThis: string): string => {
-  withThis = withThis.replace(/\$/g, '$$$$');
+export const replaceStrAll = (
+  replaceThis: string,
+  withThis: string,
+  inThis: string
+): string => {
+  withThis = withThis.replace(/\$/g, "$$$$");
   return inThis.replace(
     // eslint-disable-next-line no-useless-escape
-    new RegExp(replaceThis.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|<>\-\&])/g, '\\$&'), 'g'),
+    new RegExp(
+      replaceThis.replace(
+        /([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|<>\-\&])/g,
+        "\\$&"
+      ),
+      "g"
+    ),
     withThis
   );
 };
@@ -21,53 +35,53 @@ export const isDef = (value: any): boolean => {
 
 // 是否为空值
 export const isEmptyVal = (val: any): boolean => {
-  return val === null || val === undefined || val === '';
+  return val === null || val === undefined || val === "";
 };
 
 export const getPatten = (decimal: number) => {
-  const header = '0,0.';
-  return header + '00000000'.substr(0, decimal);
+  const header = "0,0.";
+  return header + "00000000".substr(0, decimal);
 };
 
 // 判断是否数字
 export const isNumeric = (n: any) => {
   /* eslint-disable */
-  var t = typeof n;
+    var t = typeof n;
 
-  return t == 'number'
-    ? !isNaN(n) && isFinite(n)
-    : t == 'string'
-    ? !n.length
-      ? false
-      : n.length == 1
-      ? /\d/.test(n)
-      : /^\s*[+-]?\s*(?:(?:\d+(?:\.\d+)?(?:e[+-]?\d+)?)|(?:0x[a-f\d]+))\s*$/i.test(n)
-    : t == 'object'
-    ? !!n && typeof n.valueOf() == 'number' && !(n instanceof Date)
-    : false;
+    return t == 'number'
+        ? !isNaN(n) && isFinite(n)
+        : t == 'string'
+            ? !n.length
+                ? false
+                : n.length == 1
+                    ? /\d/.test(n)
+                    : /^\s*[+-]?\s*(?:(?:\d+(?:\.\d+)?(?:e[+-]?\d+)?)|(?:0x[a-f\d]+))\s*$/i.test(n)
+            : t == 'object'
+                ? !!n && typeof n.valueOf() == 'number' && !(n instanceof Date)
+                : false;
 };
 
 // 判断数据库中的某个字段是否为空
 export const isEmptyForDB = (obj: any) => {
-  return obj == null || obj === -1 || obj === '';
+    return obj == null || obj === -1 || obj === '';
 };
 
 // 判断是否过期
-export const isExpired = (deadline:number)=> {
-  // deadline 为 0 表示无限制
-  if (deadline !== 0) {
-    return Date.now() >= deadline + 24 * 60 * 60 * 1000;
-  }
-  return false;
+export const isExpired = (deadline: number) => {
+    // deadline 为 0 表示无限制
+    if (deadline !== 0) {
+        return Date.now() >= deadline + 24 * 60 * 60 * 1000;
+    }
+    return false;
 }
 
 const canvas = document.createElement("canvas");
 
-export const getTextWidth = (text:string, font :string)=> {
-  const context = canvas.getContext("2d") as CanvasRenderingContext2D;
-  context.font = font;
-  const metrics = context.measureText(text);
-  return metrics.width;
+export const getTextWidth = (text: string, font: string) => {
+    const context = canvas.getContext("2d") as CanvasRenderingContext2D;
+    context.font = font;
+    const metrics = context.measureText(text);
+    return metrics.width;
 }
 
 

+ 93 - 35
src/utils/frontend/alert.ts

@@ -13,12 +13,16 @@
     })
  Confirm.success, Confirm.error, Confirm.warning 使用方法同理
  */
-import { VNode } from 'vue';
-import { ElMessageBox, ElMessage } from 'element-plus';
+import { VNode } from "vue";
+import { ElMessageBox, ElMessage } from "element-plus";
 
-type MessageBoxType = 'info' | 'success' | 'error' | 'warning' | undefined;
+type MessageBoxType = "info" | "success" | "error" | "warning" | undefined;
 
-function alert(type: MessageBoxType, content: string, callback?: (action: string) => void) {
+function alert(
+  type: MessageBoxType,
+  content: string,
+  callback?: (action: string) => void
+) {
   ElMessageBox.alert(content, {
     type,
     showClose: false,
@@ -30,16 +34,22 @@ const Alert = (content: string, callback?: (action: string) => void): void => {
   alert(undefined, content, callback);
 };
 Alert.info = (content: string, callback?: (action: string) => void): void => {
-  alert('info', content, callback);
+  alert("info", content, callback);
 };
-Alert.success = (content: string, callback?: (action: string) => void): void => {
-  alert('success', content, callback);
+Alert.success = (
+  content: string,
+  callback?: (action: string) => void
+): void => {
+  alert("success", content, callback);
 };
 Alert.error = (content: string, callback?: (action: string) => void): void => {
-  alert('error', content, callback);
+  alert("error", content, callback);
 };
-Alert.warning = (content: string, callback?: (action: string) => void): void => {
-  alert('warning', content, callback);
+Alert.warning = (
+  content: string,
+  callback?: (action: string) => void
+): void => {
+  alert("warning", content, callback);
 };
 
 interface ConfirmParam {
@@ -52,15 +62,19 @@ interface ConfirmParam {
 }
 
 // options的属性可为element-plus notification-box options的任意一项:https://element-plus.gitee.io/#/zh-CN/component/message-box
-function confirm(type: MessageBoxType, param: ConfirmParam, options?: Record<string, any>) {
+function confirm(
+  type: MessageBoxType,
+  param: ConfirmParam,
+  options?: Record<string, any>
+) {
   const { title, content, onOk, onCancel } = param;
   let { okText, cancelText } = param;
   if (!okText) {
-    okText = '确认';
+    okText = "确认";
   }
 
   if (!cancelText) {
-    cancelText = '取消';
+    cancelText = "取消";
   }
   const message = content;
   const head = title;
@@ -96,24 +110,31 @@ const Confirm = (param: ConfirmParam, options?: Record<string, any>): void => {
   confirm(undefined, param, options);
 };
 Confirm.info = (param: ConfirmParam, options?: Record<string, any>): void => {
-  confirm('info', param, options);
+  confirm("info", param, options);
 };
-Confirm.success = (param: ConfirmParam, options?: Record<string, any>): void => {
-  confirm('success', param, options);
+Confirm.success = (
+  param: ConfirmParam,
+  options?: Record<string, any>
+): void => {
+  confirm("success", param, options);
 };
 Confirm.error = (param: ConfirmParam, options?: Record<string, any>): void => {
-  confirm('error', param, options);
+  confirm("error", param, options);
 };
-Confirm.warning = (param: ConfirmParam, options?: Record<string, any>): void => {
-  confirm('warning', param, options);
+Confirm.warning = (
+  param: ConfirmParam,
+  options?: Record<string, any>
+): void => {
+  confirm("warning", param, options);
 };
 
 enum MessageType {
-  SUCCESS = 'success',
-  WARNING = 'warning',
-  INFO = 'info',
-  ERROR = 'error',
+  SUCCESS = "success",
+  WARNING = "warning",
+  INFO = "info",
+  ERROR = "error",
 }
+
 interface IMessageConfig {
   message: string | VNode;
   type: MessageType;
@@ -137,29 +158,66 @@ const baseMessageConfig: Partial<IMessageConfig> = {
 };
 
 /* 提示 */
+
 // 可统一共用的提示文本
 export enum MessageContent {
-  PERMISSION = '对不起,您没有权限进行该操作',
-  CELL_VALIDATE = '输入的数据类型不对,请重新输入',
+  PERMISSION = "对不起,您没有权限进行该操作",
+  CELL_VALIDATE = "输入的数据类型不对,请重新输入",
 }
-const Message = (message: string, options: Partial<IMessageConfig> = {}): IMessageHandle => {
+
+const Message = (
+  message: string,
+  options: Partial<IMessageConfig> = {}
+): IMessageHandle => {
   return ElMessage({ message, ...baseMessageConfig, ...options });
 };
 
-Message.success = (message: string, options: Partial<IMessageConfig> = {}): IMessageHandle => {
-  return ElMessage({ message, ...baseMessageConfig, ...options, type: MessageType.SUCCESS });
+Message.success = (
+  message: string,
+  options: Partial<IMessageConfig> = {}
+): IMessageHandle => {
+  return ElMessage({
+    message,
+    ...baseMessageConfig,
+    ...options,
+    type: MessageType.SUCCESS,
+  });
 };
 
-Message.warning = (message: string, options: Partial<IMessageConfig> = {}): IMessageHandle => {
-  return ElMessage({ message, ...baseMessageConfig, ...options, type: MessageType.WARNING });
+Message.warning = (
+  message: string,
+  options: Partial<IMessageConfig> = {}
+): IMessageHandle => {
+  return ElMessage({
+    message,
+    ...baseMessageConfig,
+    ...options,
+    type: MessageType.WARNING,
+  });
 };
 
-Message.info = (message: string, options: Partial<IMessageConfig> = {}): IMessageHandle => {
-  return ElMessage({ message, ...baseMessageConfig, ...options, type: MessageType.INFO });
+Message.info = (
+  message: string,
+  options: Partial<IMessageConfig> = {}
+): IMessageHandle => {
+  return ElMessage({
+    message,
+    ...baseMessageConfig,
+    ...options,
+    type: MessageType.INFO,
+  });
 };
 
-Message.error = (message: string, options: Partial<IMessageConfig> = {}): IMessageHandle => {
-  return ElMessage({ message, ...baseMessageConfig, ...options, type: MessageType.ERROR });
+Message.error = (
+  message: string,
+  options: Partial<IMessageConfig> = {}
+): IMessageHandle => {
+  return ElMessage({
+    message,
+    ...baseMessageConfig,
+    ...options,
+    type: MessageType.ERROR,
+  });
 };
 
 export const asyncConfirm = (content: string, title?: string) => {
@@ -171,7 +229,7 @@ export const asyncConfirm = (content: string, title?: string) => {
         resolve(true);
       },
       onCancel: () => {
-        console.log('cancel');
+        console.log("cancel");
         resolve(false);
       },
     });

+ 52 - 20
src/utils/frontend/dom.ts

@@ -25,19 +25,25 @@ export const toggleClass = (element: Element, className: string): boolean => {
 /* == DOM 相关 == */
 
 // 查找第一个指定的css选择器
-export const query = (startNode: Element, cssSelector: string): Element | null => {
+export const query = (
+  startNode: Element,
+  cssSelector: string
+): Element | null => {
   return startNode.querySelector(cssSelector);
 };
 
 // 查找所有指定的css选择器
-export const queryAll = (startNode: Element, cssSelector: string): NodeListOf<Element> => {
+export const queryAll = (
+  startNode: Element,
+  cssSelector: string
+): NodeListOf<Element> => {
   return (startNode || document).querySelectorAll(cssSelector);
 };
 
 // 返回或者设置 innerHTML
 // eslint-disable-next-line consistent-return
 export const html = (element: Element, innerHTML?: string): string | void => {
-  if (typeof innerHTML === 'undefined') {
+  if (typeof innerHTML === "undefined") {
     return element.innerHTML;
   }
   element.innerHTML = innerHTML;
@@ -45,8 +51,11 @@ export const html = (element: Element, innerHTML?: string): string | void => {
 
 // 返回或者设置 innerText
 // eslint-disable-next-line consistent-return
-export const text = (element: HTMLElement, innerText?: string): string | void => {
-  if (typeof innerText === 'undefined') {
+export const text = (
+  element: HTMLElement,
+  innerText?: string
+): string | void => {
+  if (typeof innerText === "undefined") {
     return element.innerText;
   }
   element.innerText = innerText;
@@ -73,37 +82,56 @@ export const remove = (element: Element | null): void => {
 };
 
 // 绑定事件
-export const on = (element: Element, eventName: string, callback: (event: Event) => void, useCapture = false): void => {
+export const on = (
+  element: Element,
+  eventName: string,
+  callback: (event: Event) => void,
+  useCapture = false
+): void => {
   element.addEventListener(eventName, callback, useCapture);
 };
 
 // 解绑事件
-export const off = (element: Element, eventName: string, callback: (event: Event) => void): void => {
+export const off = (
+  element: Element,
+  eventName: string,
+  callback: (event: Event) => void
+): void => {
   element.removeEventListener(eventName, callback);
 };
 
 // hover
-export const hover = (element: Element, handlerIn: (e: Event) => void, handlerOut: (e: Event) => void): void => {
-  on(element, 'mouseenter', handlerIn);
-  on(element, 'mouseleave', handlerOut);
+export const hover = (
+  element: Element,
+  handlerIn: (e: Event) => void,
+  handlerOut: (e: Event) => void
+): void => {
+  on(element, "mouseenter", handlerIn);
+  on(element, "mouseleave", handlerOut);
 };
 
 // wheel滚轮事件
-export const wheel = (element: Element, handlerWheel: (e: Event) => void): void => {
-  on(element, 'mousewheel', handlerWheel);
+export const wheel = (
+  element: Element,
+  handlerWheel: (e: Event) => void
+): void => {
+  on(element, "mousewheel", handlerWheel);
 };
 
 // 解析字符串生成DOM元素
 export const parse = (innerHTML: string): Element => {
-  const container = createElement('div');
+  const container = createElement("div");
   html(container, innerHTML.trim());
   return container.firstChild as Element;
 };
 
 // 设置元素样式
-export const style = (element: HTMLElement, styleObj: { [key in keyof CSSStyleDeclaration]?: string }): void => {
+export const style = (
+  element: HTMLElement,
+  styleObj: { [key in keyof CSSStyleDeclaration]?: string }
+): void => {
   const keys = Object.keys(styleObj);
-  keys.forEach(key => {
+  keys.forEach((key) => {
     any(element.style)[key] = any(styleObj)[key];
   });
 };
@@ -156,7 +184,7 @@ export const getCaretPosition = (el: HTMLInputElement) => {
     const rc = re.duplicate();
 
     re.moveToBookmark(r.getBookmark());
-    rc.setEndPoint('EndToStart', re);
+    rc.setEndPoint("EndToStart", re);
 
     return rc.text.length;
   }
@@ -172,7 +200,11 @@ export const getCaretPosition = (el: HTMLInputElement) => {
  * @param {Number} pos
  * @param {Number} endPos
  */
-export const setCaretPosition = (element: HTMLInputElement, pos: number, endPos: number) => {
+export const setCaretPosition = (
+  element: HTMLInputElement,
+  pos: number,
+  endPos: number
+) => {
   if (endPos === 0) {
     endPos = pos;
   }
@@ -184,7 +216,7 @@ export const setCaretPosition = (element: HTMLInputElement, pos: number, endPos:
     } catch (err) {
       const elementParent = element.parentNode as HTMLElement;
       const parentDisplayValue = elementParent.style.display;
-      elementParent.style.display = 'block';
+      elementParent.style.display = "block";
       element.setSelectionRange(pos, endPos);
       elementParent.style.display = parentDisplayValue;
     }
@@ -192,8 +224,8 @@ export const setCaretPosition = (element: HTMLInputElement, pos: number, endPos:
     // IE8
     const range = (element as any).createTextRange();
     range.collapse(true);
-    range.moveEnd('character', endPos);
-    range.moveStart('character', pos);
+    range.moveEnd("character", endPos);
+    range.moveStart("character", pos);
     range.select();
   }
 };

+ 70 - 66
src/utils/frontend/emitter.ts

@@ -1,5 +1,5 @@
 /* mitt事件相关 */
-import mitt, { Emitter, Handler } from 'mitt';
+import mitt, { Emitter, Handler } from "mitt";
 // import tabStore from '@/store/modules/tabs';
 
 /**
@@ -7,133 +7,133 @@ import mitt, { Emitter, Handler } from 'mitt';
  */
 export enum EmitterType {
   // 拖动拖拽布局
-  DRAG_BAR_MOVE = 'dragBarMove',
+  DRAG_BAR_MOVE = "dragBarMove",
   // sidebar侧边栏宽度变化
-  SIDEBAR_WIDTH_CHANGE = 'sidebarWidthChange',
+  SIDEBAR_WIDTH_CHANGE = "sidebarWidthChange",
   // 点击了新建项目按钮
-  CLICK_CREATE_PROJECT = 'clickCreateProject',
+  CLICK_CREATE_PROJECT = "clickCreateProject",
   // 重新加载建设项目
-  RELOAD_CONSTRUCTION_PROJECTS = 'reload:construction',
+  RELOAD_CONSTRUCTION_PROJECTS = "reload:construction",
   // 刷新项目管理-全部 表格
-  REFRESH_ALL_TABLE = 'refresh:allTable',
+  REFRESH_ALL_TABLE = "refresh:allTable",
   // 更改了项目管理-全部树
-  UPDATE_ALL_TREE = 'update:allTree',
+  UPDATE_ALL_TREE = "update:allTree",
   // 更改了项目导航树
-  UPDATE_SUBJECT_TREE = 'update:subjectTree',
+  UPDATE_SUBJECT_TREE = "update:subjectTree",
   // 更改(恢复)回收站树
-  UPDATE_RECYCLE_TREE = 'update:recycleTree',
+  UPDATE_RECYCLE_TREE = "update:recycleTree",
   // 点击了回收站的恢复按钮
-  RECYCLE = 'clickRecycle',
+  RECYCLE = "clickRecycle",
   // 点击了彻底删除
-  COMPLETELY_REMOVE = 'clickCompletelyRemove',
+  COMPLETELY_REMOVE = "clickCompletelyRemove",
   // 更改了造价书节点
-  UPDATE_COST_NODE = 'update:costNode',
+  UPDATE_COST_NODE = "update:costNode",
   // 更新了特征及内容文本
-  UPDATE_CONTENT_CHARACTER = 'update:contentCharacter',
+  UPDATE_CONTENT_CHARACTER = "update:contentCharacter",
   // 更新造价书列设置
-  UPDATE_COST_SETTING = 'update:costSetting',
+  UPDATE_COST_SETTING = "update:costSetting",
   // 刷新造价书
-  REFRESH_COST = 'refresh:cost',
+  REFRESH_COST = "refresh:cost",
   // 刷新造价书按钮有效性
-  REFRESH_COST_BUTTON = 'refresh:costButton',
+  REFRESH_COST_BUTTON = "refresh:costButton",
   // 选中造价书节点
-  SELECT_COST = 'select:cost',
+  SELECT_COST = "select:cost",
   // 设置造价书Loading
-  SET_COST_LOADING = 'set:costLoading',
+  SET_COST_LOADING = "set:costLoading",
   // 刷新项目工料机表格
-  REFRESH_PROJECT_GLJ = 'refresh:projectGlj',
+  REFRESH_PROJECT_GLJ = "refresh:projectGlj",
   // 刷新关联材料表格
-  REFRESH_RELATED_MATERIAL = 'refresh:relatedMaterial',
+  REFRESH_RELATED_MATERIAL = "refresh:relatedMaterial",
   // 刷新建设项目级工料机汇总
-  REFRESH_SUMMARY_GLJ = 'refresh:summaryGlj',
+  REFRESH_SUMMARY_GLJ = "refresh:summaryGlj",
   // 切换建设项目工料机汇总表格的loading状态
-  TRIGGER_SUMMARY_LOADING = 'trigger:summaryLoading',
+  TRIGGER_SUMMARY_LOADING = "trigger:summaryLoading",
   // 刷新量价表格
-  REFRESH_VOLUME_PRICE = 'refresh:volumePrice',
+  REFRESH_VOLUME_PRICE = "refresh:volumePrice",
   // 刷新定额工料机表格
-  REFRESH_RATION_GLJ = 'refresh:rationGlj',
+  REFRESH_RATION_GLJ = "refresh:rationGlj",
   // 刷新定额安装增加费表格
-  REFRESH_RATION_INSTALL = 'refresh:rationInstall',
+  REFRESH_RATION_INSTALL = "refresh:rationInstall",
   // 刷新费用修改表格
-  REFRESH_EDIT_RULE = 'refresh:editRule',
+  REFRESH_EDIT_RULE = "refresh:editRule",
   // 刷新计算程序表格
-  REFRESH_CALC_PROGRAM = 'refresh:calcProgram',
+  REFRESH_CALC_PROGRAM = "refresh:calcProgram",
   // 刷新定额子目换算表格
-  REFRESH_RATION_CALC = 'refresh:rationCalc',
+  REFRESH_RATION_CALC = "refresh:rationCalc",
   // 刷新定额库定额列表
-  REFRESH_LIB_RATION = 'refresh:libRation',
+  REFRESH_LIB_RATION = "refresh:libRation",
   // 刷新定额库定额列表列设置
-  UPDATE_LIB_RATION_SETTING = 'refresh:libRationSetting',
+  UPDATE_LIB_RATION_SETTING = "refresh:libRationSetting",
   // 刷新定额模板子目
-  RELOAD_RATION_TEMPLATE = 'refresh:rationTemplate',
+  RELOAD_RATION_TEMPLATE = "refresh:rationTemplate",
   // 刷新信息价表格
-  REFRESH_INFO_PRICE = 'refresh:infoPrice',
+  REFRESH_INFO_PRICE = "refresh:infoPrice",
   // 刷新费率页面表格
-  REFRESH_FEE_RATE = 'refresh:feeRate',
+  REFRESH_FEE_RATE = "refresh:feeRate",
   // 刷新补充定额章节树按钮区有效性
-  REFRESH_RATION_TREE_TOOLS = 'refresh:rationTreeTools',
+  REFRESH_RATION_TREE_TOOLS = "refresh:rationTreeTools",
   // 刷新补充定额表格
-  REFRESH_CPT_RATION = 'refresh:cptRation',
+  REFRESH_CPT_RATION = "refresh:cptRation",
   // 刷新安装增加费用项表格
-  REFRESH_INSTALL_FEE_ITEM = 'refresh:installFeeItem',
+  REFRESH_INSTALL_FEE_ITEM = "refresh:installFeeItem",
   // 项目分享历史变更
-  PROJECT_SHARE_HISTORY_CHANGED = 'projectShareHistoryChanged',
+  PROJECT_SHARE_HISTORY_CHANGED = "projectShareHistoryChanged",
   // 定额库分享历史变更
-  RATION_LIB_SHARE_HISTORY_CHANGED = 'rationLibShareHistoryChanged',
+  RATION_LIB_SHARE_HISTORY_CHANGED = "rationLibShareHistoryChanged",
   // 人材机库分享历史变更
-  GLJ_LIB_SHARE_HISTORY_CHANGED = 'gljLibShareHistoryChanged',
+  GLJ_LIB_SHARE_HISTORY_CHANGED = "gljLibShareHistoryChanged",
   // 更新了子目换算总表数据
-  UPDATE_CPT_COE = 'update:cptCoe',
+  UPDATE_CPT_COE = "update:cptCoe",
   // 关闭计算基数弹窗
-  CLOSE_FORMULA_POPUP = 'close:formulaPopup',
+  CLOSE_FORMULA_POPUP = "close:formulaPopup",
   // 打开库标签
-  OPEN_LIB_TAB = 'open:libTab',
+  OPEN_LIB_TAB = "open:libTab",
   // 添加新成员
-  ADD_NEW_MEMBER = 'addNewMember',
+  ADD_NEW_MEMBER = "addNewMember",
   // 打开消息中心
-  OPEN_NOTIFICATION = 'openNotification',
+  OPEN_NOTIFICATION = "openNotification",
   // 未读消息数量变化
-  UNREAD_COUNT_CHANGE = 'unreadCountChange',
+  UNREAD_COUNT_CHANGE = "unreadCountChange",
   // 新消息
-  NEW_MESSAGE = 'newMessage',
+  NEW_MESSAGE = "newMessage",
   // 离开 socket 房间
-  LEAVE_ROOM = 'leaveRoom',
+  LEAVE_ROOM = "leaveRoom",
   // 刷新工料机库显示(按选中类别)
-  REFRESH_CPT_GLJ_LIB = 'refresh:cptGljLib',
+  REFRESH_CPT_GLJ_LIB = "refresh:cptGljLib",
   // 变更补充定额库
-  CHANGE_CPT_RATION_LIB = 'change:cptRationLib',
+  CHANGE_CPT_RATION_LIB = "change:cptRationLib",
   // 变更补充人材机库
-  CHANGE_CPT_GLJ_LIB = 'change:cptGljLib',
+  CHANGE_CPT_GLJ_LIB = "change:cptGljLib",
   // 刷新书签批注
-  REFRESH_BOOKMARK = 'refresh:bookmark',
+  REFRESH_BOOKMARK = "refresh:bookmark",
   // 更新显示/隐藏特征按钮
-  UPDATE_SHOW_FEATURE = 'update:isShowFeature',
+  UPDATE_SHOW_FEATURE = "update:isShowFeature",
   // 造价单书签批注用,hover事件计数器
-  CLEAR_CELL_HOVER_LIST = 'clear:cellHoverList',
+  CLEAR_CELL_HOVER_LIST = "clear:cellHoverList",
   // 清空人材机组成物
-  CLEAR_GLJ_COMPONENT = 'clear:gljComponent',
+  CLEAR_GLJ_COMPONENT = "clear:gljComponent",
   // 刷新建设项目分享标记
-  REFRESH_CONSTRUCTION_SHARE_MARK = 'refresh:constructionShareMark',
+  REFRESH_CONSTRUCTION_SHARE_MARK = "refresh:constructionShareMark",
   // 单位工程信息指标表格刷新
-  REFRESH_TARGET_GRID = 'refresh:targetGrid',
+  REFRESH_TARGET_GRID = "refresh:targetGrid",
   // 刷新建设项目汇总
-  REFRESH_CONSTRUCTION_SUMMARY = 'refresh:constructionSummary',
+  REFRESH_CONSTRUCTION_SUMMARY = "refresh:constructionSummary",
   // 刷新分享项目数据
-  REFRESH_SHARE_PROJECT = 'refresh:shareProject',
+  REFRESH_SHARE_PROJECT = "refresh:shareProject",
   // 刷新分享定额库数据
-  REFRESH_SHARE_RATION_LIB = 'refresh:shareRationLib',
+  REFRESH_SHARE_RATION_LIB = "refresh:shareRationLib",
   // 刷新分享人材机库数据
-  REFRESH_SHARE_GLJ_LIB = 'refresh:shareGljLib',
+  REFRESH_SHARE_GLJ_LIB = "refresh:shareGljLib",
   // 追加定额库选项
-  APPEND_RATION_LIB_OPTION = 'append:rationLibOption',
+  APPEND_RATION_LIB_OPTION = "append:rationLibOption",
   // 追加人材机库选项
-  APPEND_GLJ_LIB_OPTION = 'append:gljLibOption',
+  APPEND_GLJ_LIB_OPTION = "append:gljLibOption",
   // 移除定额库选项
-  REMOVE_RATION_LIB_OPTION = 'remove:rationLibOption',
+  REMOVE_RATION_LIB_OPTION = "remove:rationLibOption",
   // 移除人材机库选项
-  REMOVE_GLJ_LIB_OPTION = 'remove:gljLibOption',
+  REMOVE_GLJ_LIB_OPTION = "remove:gljLibOption",
   // 刷新项目权限
-  REFRESH_PROJECT_PERMISSION = 'refresh:projectPermission',
+  REFRESH_PROJECT_PERMISSION = "refresh:projectPermission",
 }
 
 // 单例的emitter(有些事件不能用单例,可能会有多建设项目页面)
@@ -160,7 +160,11 @@ export const getEmitter = (key?: string) => {
      * !!!注意!!!:emit监听时,按需增加监听事件名称,同一类型下,不可有重复监听事件名称
      * 由于组件可能多次渲染(多次进入setup方法),为了避免重复监听事件。
      */
-    on<T = any>(emitterType: EmitterType, handler: Handler<T>, listenerName?: string) {
+    on<T = any>(
+      emitterType: EmitterType,
+      handler: Handler<T>,
+      listenerName?: string
+    ) {
       const listenerKey = `${emitterType}-${listenerName}`;
       if (listenedMap[listenerKey]) {
         this.off(emitterType, listenedMap[listenerKey]);

+ 16 - 14
src/utils/frontend/loadImage.ts

@@ -1,19 +1,21 @@
 const load = async (imgSrc: string) => {
-    return new Promise(resolve => {
-        let image = new Image();
-        image.onload = () => resolve(image);
-        image.onerror = () => resolve(null);
-        image.src = imgSrc;
-    });
+  return new Promise((resolve) => {
+    const image = new Image();
+    image.onload = () => resolve(image);
+    image.onerror = () => resolve(null);
+    image.src = imgSrc;
+  });
 };
 
 // 预加载图片
-export async function loadImage(imgSrcs: string | string[]) {
-    if (typeof imgSrcs === "string") {
-        await load(imgSrcs);
-    } else if (Array.isArray(imgSrcs)) {
-        await Promise.all(imgSrcs.map(async src => {
-            await load(src);
-        }))
-    }
+export default async function loadImage(imgSrcs: string | string[]) {
+  if (typeof imgSrcs === "string") {
+    await load(imgSrcs);
+  } else if (Array.isArray(imgSrcs)) {
+    await Promise.all(
+      imgSrcs.map(async (src) => {
+        await load(src);
+      })
+    );
+  }
 }

+ 3 - 3
src/utils/frontend/tree.ts

@@ -1,9 +1,9 @@
 /* eslint-disable import/prefer-default-export */
-import { Tree, TreeNode } from '@sc/tree';
+import { Tree, TreeNode } from "@sc/tree";
 
 // 展开所有的树节点
 export function expandAllTreeNode(treeData: TreeNode[]): void {
-  treeData.forEach(item => {
+  treeData.forEach((item) => {
     item.getCtx().expanded = true;
   });
 }
@@ -38,7 +38,7 @@ export const toElTreeData = (tree: Tree): IElTreeNode[] => {
   const elTreeData: IElTreeNode[] = [];
   const roots = tree.getRoots();
   if (roots.length > 0) {
-    roots.forEach(root => {
+    roots.forEach((root) => {
       elTreeData.push(getElTreeData(root));
     });
   }

+ 8 - 5
src/utils/frontend/vueHelper.ts

@@ -1,4 +1,4 @@
-import { App, Component } from 'vue';
+import { App, Component } from "vue";
 // import { IGlobalPopup } from '@/components/popup/types';
 
 // type GlobalPopupMethod = (component?: Component, options?: any) => IGlobalPopup;
@@ -15,16 +15,19 @@ export function setGlobalApp(app: App): void {
   curApp = app;
 }
 
-export function getGlobal()/* : IGlobalProperties */ {
+export function getGlobal() /* : IGlobalProperties */ {
   if (!curApp) {
-    throw new Error('没有正确注册全局app');
+    throw new Error("没有正确注册全局app");
   }
-  return curApp.config.globalProperties/*  as IGlobalProperties */;
+  return curApp.config.globalProperties /*  as IGlobalProperties */;
 }
 
 // export function createPopup<T = any>(component?: Component, options?: T): IGlobalPopup {
 //   return getGlobal().$popup(component, options);
 // }
-export function createPopover<T = any>(component?: Component, options?: T): void {
+export function createPopover<T = any>(
+  component?: Component,
+  options?: T
+): void {
   return getGlobal().$popover(component, options);
 }

+ 4 - 5
src/views/data-library/DataLibrary.vue

@@ -1,13 +1,12 @@
 <script setup lang="ts">
-import { onMounted, reactive, ref } from "vue";
-import breadcrumbStore from '@/store/modules/breadcrumb'
+import breadcrumbStore from "@/store/modules/breadcrumb";
 
-const { setBreadcrumb } = breadcrumbStore
+const { setBreadcrumb } = breadcrumbStore;
 setBreadcrumb([
   {
-    label: '系统数据库',
+    label: "系统数据库",
   },
-])
+]);
 </script>
 
 <template>

+ 58 - 53
src/views/data-library/style.scss

@@ -1,63 +1,68 @@
 .data-library {
-    .header {
-        padding: 16px 32px;
-        border-bottom: 1px solid #e8eaec;
-        background: #fff;
-
-        .title {
-            font-size: 20px;
-            font-weight: 500;
-            color: #17233d;
-            margin-bottom: 16px;
-        }
+  .header {
+    padding: 16px 32px;
+    border-bottom: 1px solid #e8eaec;
+    background: #fff;
+
+    .title {
+      font-size: 20px;
+      font-weight: 500;
+      color: #17233d;
+      margin-bottom: 16px;
     }
-    .main-wrap {
-        padding: 16px 24px 60px;
+  }
 
-        .el-row {
-            margin-bottom: 20px;
-            &:last-child {
-                margin-bottom: 0;
-            }
+  .main-wrap {
+    padding: 16px 24px 60px;
+
+    .el-row {
+      margin-bottom: 20px;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+    }
+
+    .el-col {
+      border-radius: 4px;
+      margin-bottom: 16px;
+
+      .el-card {
+        border: none;
+        transition: all 0.2s ease-in-out;
+
+        &:hover {
+          @apply cursor-pointer;
+          box-shadow: 0 1px 6px rgb(0 0 0 / 20%);
+          border-color: #eee;
         }
 
-        .el-col {
-            border-radius: 4px;
-            margin-bottom: 16px;
+        ::v-deep .el-card__body {
+          @apply text-center;
+          padding: 16px;
+
+          .figure-wrap {
+            width: 60%;
+            margin: 0 auto;
 
-            .el-card {
-                border: none;
-                transition: all 0.2s ease-in-out;
-                &:hover {
-                    @apply cursor-pointer;
-                    box-shadow: 0 1px 6px rgb(0 0 0 / 20%);
-                    border-color: #eee;
-                }
-
-                ::v-deep .el-card__body {
-                    @apply text-center;
-                    padding: 16px;
-                    .figure-wrap {
-                        width: 60%;
-                        margin: 0 auto;
-                        .figure {
-                            @apply inline-block;
-                        }
-                    }
-
-                    .title {
-                        font-size: 16px;
-                        font-weight: 700;
-                        margin: 8px 0;
-                    }
-
-                    .desc {
-                        font-size: 14px;
-                        color: #808695;
-                        margin-bottom: 16px;
-                    }
-                }
+            .figure {
+              @apply inline-block;
             }
+          }
+
+          .title {
+            font-size: 16px;
+            font-weight: 700;
+            margin: 8px 0;
+          }
+
+          .desc {
+            font-size: 14px;
+            color: #808695;
+            margin-bottom: 16px;
+          }
         }
+      }
     }
+  }
 }

+ 33 - 6
src/views/login/Login.vue

@@ -76,12 +76,39 @@ const { moduleRef } = useModuleItem();
       </div>
       <!-- 功能模块 -->
       <ul class="module" ref="moduleRef">
-        <li class="item budget animate__animated animate__bounceIn" ref="budgetRef">预算审核模块</li>
-        <li class="item estimate animate__animated animate__bounceIn" ref="estimateRef">估/概算模块</li>
-        <li class="item util animate__animated animate__bounceIn" ref="utilRef">基础工具模块</li>
-        <li class="item settlement animate__animated animate__bounceIn" ref="settlementRef">结算审核模块</li>
-        <li class="item final animate__animated animate__bounceIn" ref="finalRef">决算审核模块</li>
-        <li class="item check animate__animated animate__bounceIn" ref="checkRef">检测功能模块</li>
+        <li
+          class="item budget animate__animated animate__bounceIn"
+          ref="budgetRef"
+        >
+          预算审核模块
+        </li>
+        <li
+          class="item estimate animate__animated animate__bounceIn"
+          ref="estimateRef"
+        >
+          估/概算模块
+        </li>
+        <li class="item util animate__animated animate__bounceIn" ref="utilRef">
+          基础工具模块
+        </li>
+        <li
+          class="item settlement animate__animated animate__bounceIn"
+          ref="settlementRef"
+        >
+          结算审核模块
+        </li>
+        <li
+          class="item final animate__animated animate__bounceIn"
+          ref="finalRef"
+        >
+          决算审核模块
+        </li>
+        <li
+          class="item check animate__animated animate__bounceIn"
+          ref="checkRef"
+        >
+          检测功能模块
+        </li>
       </ul>
     </main>
   </article>

+ 27 - 27
src/views/login/scripts/moduleItem.ts

@@ -1,33 +1,33 @@
-import { onMounted, ref } from 'vue'
+import { onMounted, ref } from "vue";
 
 export default function useModuleItem() {
-    const budgetRef = ref<HTMLLIElement>()
-    const estimateRef = ref<HTMLLIElement>()
-    const utilRef = ref<HTMLLIElement>()
-    const settlementRef = ref<HTMLLIElement>()
-    const finalRef = ref<HTMLLIElement>()
-    const checkRef = ref<HTMLLIElement>()
+  const budgetRef = ref<HTMLLIElement>();
+  const estimateRef = ref<HTMLLIElement>();
+  const utilRef = ref<HTMLLIElement>();
+  const settlementRef = ref<HTMLLIElement>();
+  const finalRef = ref<HTMLLIElement>();
+  const checkRef = ref<HTMLLIElement>();
 
-    const moduleRef = ref<HTMLUListElement>()
+  const moduleRef = ref<HTMLUListElement>();
 
-    onMounted(() => {
-        if (moduleRef.value) {
-            const ul = moduleRef.value
-            const list = ul.querySelectorAll('.item')
-            list.forEach(item => {
-                item.classList.remove('animate__animated')
-                item.classList.add('can-hover')
-            })
-        }
-    })
-
-    return {
-        budgetRef,
-        estimateRef,
-        utilRef,
-        settlementRef,
-        finalRef,
-        checkRef,
-        moduleRef
+  onMounted(() => {
+    if (moduleRef.value) {
+      const ul = moduleRef.value;
+      const list = ul.querySelectorAll(".item");
+      list.forEach((item) => {
+        item.classList.remove("animate__animated");
+        item.classList.add("can-hover");
+      });
     }
+  });
+
+  return {
+    budgetRef,
+    estimateRef,
+    utilRef,
+    settlementRef,
+    finalRef,
+    checkRef,
+    moduleRef,
+  };
 }

+ 3 - 3
src/views/login/scripts/preloadImg.ts

@@ -1,6 +1,6 @@
-import hoverImgUrl from '@/assets/login-module-item-hover.png'
-import { loadImage } from "../../../utils/frontend/loadImage";
+import hoverImgUrl from "@/assets/login-module-item-hover.png";
+import loadImage from "../../../utils/frontend/loadImage";
 
 export default function usePreloadImg() {
-    loadImage(hoverImgUrl)
+  loadImage(hoverImgUrl);
 }

+ 126 - 101
src/views/login/scripts/rotateCanvas.ts

@@ -1,117 +1,142 @@
 import { onMounted, ref } from "vue";
-import blueImageUrl from '@/assets/login-rotate-blue.png'
-import yellowImageUrl from '@/assets/login-rotate-yellow.png'
-
+import blueImageUrl from "@/assets/login-rotate-blue.png";
+import yellowImageUrl from "@/assets/login-rotate-yellow.png";
 
 interface IPoint {
-    x: number;
-    y: number;
+  x: number;
+  y: number;
 }
 
 class CircleItem {
-    ctx: CanvasRenderingContext2D
-    img: HTMLImageElement
-    r: number
-    w: number
-    h: number
-    x: number
-    y: number
+  ctx: CanvasRenderingContext2D;
+
+  img: HTMLImageElement;
+
+  r: number;
+
+  w: number;
+
+  h: number;
+
+  x: number;
+
+  y: number;
+
+  speed: number;
+
+  rectCenterPoint: IPoint;
+
+  cacheCanvas: HTMLCanvasElement;
+
+  cacheCtx: CanvasRenderingContext2D;
+
+  constructor(
+    ctx: CanvasRenderingContext2D,
+    img: HTMLImageElement,
+    r: number,
+    x: number,
+    y: number,
     speed: number
-    rectCenterPoint: IPoint
-    cacheCanvas: HTMLCanvasElement
-    cacheCtx: CanvasRenderingContext2D
-
-    constructor(ctx: CanvasRenderingContext2D, img: HTMLImageElement, r: number, x: number, y: number, speed: number) {
-        this.ctx = ctx
-        this.img = img;
-        this.r = r;
-        this.w = r * 2;
-        this.h = r * 2;
-        this.x = x;
-        this.y = y;
-        this.speed = speed;
-        this.rectCenterPoint = {
-            x: r,
-            y: r,
-        };
-
-        this.cacheCanvas = document.createElement("canvas")
-        this.cacheCtx = this.cacheCanvas.getContext("2d") as CanvasRenderingContext2D
-        this.cache();
-    }
+  ) {
+    this.ctx = ctx;
+    this.img = img;
+    this.r = r;
+    this.w = r * 2;
+    this.h = r * 2;
+    this.x = x;
+    this.y = y;
+    this.speed = speed;
+    this.rectCenterPoint = {
+      x: r,
+      y: r,
+    };
 
-    draw() {
-        this.rotate();
-        this.ctx.scale(1, 0.3);
-        this.ctx.drawImage(
-            this.cacheCanvas,
-            0,
-            0,
-            this.w,
-            this.h,
-            this.x - this.r,
-            this.y - this.r,
-            this.r * 2,
-            this.r * 2
-        );
-        this.ctx.scale(1, 1 / 0.3);
-    }
+    this.cacheCanvas = document.createElement("canvas");
+    this.cacheCtx = this.cacheCanvas.getContext(
+      "2d"
+    ) as CanvasRenderingContext2D;
+    this.cache();
+  }
 
-    cache() {
-        this.cacheCanvas.width = this.w;
-        this.cacheCanvas.height = this.h;
-        this.cacheCtx.save();
-        this.cacheCtx.beginPath();
-        this.cacheCtx.drawImage(this.img, 0, 0, this.r * 2, this.r * 2);
-        this.cacheCtx.closePath();
-        this.cacheCtx.restore();
-    }
+  draw() {
+    this.rotate();
+    this.ctx.scale(1, 0.3);
+    this.ctx.drawImage(
+      this.cacheCanvas,
+      0,
+      0,
+      this.w,
+      this.h,
+      this.x - this.r,
+      this.y - this.r,
+      this.r * 2,
+      this.r * 2
+    );
+    this.ctx.scale(1, 1 / 0.3);
+  }
 
-    rotate() {
-        this.cacheCtx.clearRect(0, 0, this.w, this.h);
-        this.cacheCtx.translate(this.rectCenterPoint.x, this.rectCenterPoint.y);
-        this.cacheCtx.rotate((this.speed * Math.PI) / 180);
-        this.cacheCtx.translate(-this.rectCenterPoint.x, -this.rectCenterPoint.y);
-        this.cacheCtx.drawImage(this.img, 0, 0, this.r * 2, this.r * 2);
-    }
+  cache() {
+    this.cacheCanvas.width = this.w;
+    this.cacheCanvas.height = this.h;
+    this.cacheCtx.save();
+    this.cacheCtx.beginPath();
+    this.cacheCtx.drawImage(this.img, 0, 0, this.r * 2, this.r * 2);
+    this.cacheCtx.closePath();
+    this.cacheCtx.restore();
+  }
+
+  rotate() {
+    this.cacheCtx.clearRect(0, 0, this.w, this.h);
+    this.cacheCtx.translate(this.rectCenterPoint.x, this.rectCenterPoint.y);
+    this.cacheCtx.rotate((this.speed * Math.PI) / 180);
+    this.cacheCtx.translate(-this.rectCenterPoint.x, -this.rectCenterPoint.y);
+    this.cacheCtx.drawImage(this.img, 0, 0, this.r * 2, this.r * 2);
+  }
 }
 
 // 旋转底座
 export default function useRotateCanvas() {
-    const CANVAS_W = 1800
-    const CANVAS_H = 600
-    const canvasRef = ref<HTMLCanvasElement>();
-    onMounted(() => {
-        if (canvasRef.value) {
-            const canvas = canvasRef.value
-            const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
-
-            const blueImg = new Image();
-            blueImg.src = blueImageUrl;
-            let rotateBlue: CircleItem
-            blueImg.onload = function () {
-                rotateBlue = new CircleItem(ctx, blueImg, 750, CANVAS_W / 2, 800, 1);
-            };
-
-            const yellowImg = new Image();
-            yellowImg.src = yellowImageUrl;
-            let rotateYellow: CircleItem
-            yellowImg.onload = function () {
-                rotateYellow = new CircleItem(ctx, yellowImg, 400, CANVAS_W / 2, 800, 0.6);
-            };
-
-            function animate() {
-                ctx.clearRect(0, 0, CANVAS_W, CANVAS_H);
-                rotateBlue && rotateBlue.draw();
-                rotateYellow && rotateYellow.draw();
-                requestAnimationFrame(animate);
-            }
-
-            animate();
-        }
-    })
-
-    return {
-        canvasRef
+  const CANVAS_W = 1800;
+  const CANVAS_H = 600;
+  const canvasRef = ref<HTMLCanvasElement>();
+  onMounted(() => {
+    if (canvasRef.value) {
+      const canvas = canvasRef.value;
+      const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
+
+      const blueImg = new Image();
+      blueImg.src = blueImageUrl;
+      let rotateBlue: CircleItem;
+      blueImg.onload = function () {
+        rotateBlue = new CircleItem(ctx, blueImg, 750, CANVAS_W / 2, 800, 1);
+      };
+
+      const yellowImg = new Image();
+      yellowImg.src = yellowImageUrl;
+      let rotateYellow: CircleItem;
+      yellowImg.onload = function () {
+        rotateYellow = new CircleItem(
+          ctx,
+          yellowImg,
+          400,
+          CANVAS_W / 2,
+          800,
+          0.6
+        );
+      };
+
+      function animate() {
+        ctx.clearRect(0, 0, CANVAS_W, CANVAS_H);
+        rotateBlue && rotateBlue.draw();
+        rotateYellow && rotateYellow.draw();
+        requestAnimationFrame(animate);
+      }
+
+      animate();
     }
+  });
+
+  return {
+    canvasRef,
+  };
 }

+ 202 - 202
src/views/login/style.scss

@@ -1,235 +1,235 @@
 @keyframes aperture-rotate {
-    to {
-        transform: rotate(1turn);
-    }
+  to {
+    transform: rotate(1turn);
+  }
 }
 
 @keyframes flash-change {
-    from {
-        left: -100%;
-    }
+  from {
+    left: -100%;
+  }
 
-    to {
-        left: 150%;
-    }
+  to {
+    left: 150%;
+  }
 }
 
 .login-page {
-    @apply w-full h-full overflow-hidden;
-    background-color: #011531;
+  @apply w-full h-full overflow-hidden;
+  background-color: #011531;
+
+  .video-bg {
+    @apply fixed z-0 right-0 bottom-0 min-w-full min-h-full h-auto w-auto object-fill;
+    filter: brightness(0.7);
+  }
+
+  .header {
+    @apply flex justify-center w-full bg-contain bg-no-repeat bg-center text-center text-4xl select-none;
+    height: 68px;
+
+    .span {
+      background-size: 100% 100%;
+
+      &.left {
+        flex: 100 1 auto;
+        background-image: url("@/assets/login-header-bg1.png");
+      }
+
+      &.center {
+        flex: 1 0 590px;
+        background-image: url("@/assets/login-header-bg2.png");
+
+        .text {
+          @apply text-center font-bold bg-clip-text;
+          font-size: 36px;
+          line-height: 64px;
+          background-image: linear-gradient(0deg, #3084e8, #adf0f6 80%);
+          -webkit-text-fill-color: transparent;
+        }
+      }
 
-    .video-bg {
-        @apply fixed z-0 right-0 bottom-0 min-w-full min-h-full h-auto w-auto object-fill;
-        filter: brightness(0.7);
+      &.right {
+        flex: 100 1 auto;
+        background-image: url("@/assets/login-header-bg3.png");
+      }
     }
+  }
+
+  .main {
+    @apply relative flex justify-center items-center;
+    height: calc(100% - 68px);
+
+    .panel {
+      @apply relative z-40 flex items-center justify-center flex-col;
+      width: 487px;
+      height: 487px;
+      margin-top: -80px;
+      background: url("@/assets/login-panel.png") no-repeat;
+
+      .input-wrap {
+        @apply flex justify-center relative;
+        width: 250px;
+        height: 40px;
+        margin-top: 40px;
+        border-bottom: 2px solid #145da5;
+        background: no-repeat 0 center;
+        background-size: 31px 31px;
+
+        &.username {
+          background-image: url("@/assets/login-input-user-icon.svg");
+        }
 
-    .header {
-        @apply flex justify-center w-full bg-contain bg-no-repeat bg-center text-center text-4xl select-none;
-        height: 68px;
+        &.password {
+          margin-top: 36px;
+          background-image: url("@/assets/login-input-password-icon.svg");
+        }
 
-        .span {
-            background-size: 100% 100%;
+        .input {
+          @apply w-full h-full outline-none bg-transparent;
+          font-size: 21px;
+          color: #8ae2ff;
+          padding-left: 50px;
 
-            &.left {
-                flex: 100 1 auto;
-                background-image: url("@/assets/login-header-bg1.png");
-            }
+          &::-ms-input-placeholder {
+            color: #145da5;
+          }
 
-            &.center {
-                flex: 1 0 590px;
-                background-image: url("@/assets/login-header-bg2.png");
-
-                .text {
-                    @apply text-center font-bold bg-clip-text;
-                    font-size: 36px;
-                    line-height: 64px;
-                    background-image: linear-gradient(0deg, #3084e8, #adf0f6 80%);
-                    -webkit-text-fill-color: transparent;
-                }
-            }
+          &::-moz-placeholder {
+            color: #145da5;
+          }
 
-            &.right {
-                flex: 100 1 auto;
-                background-image: url("@/assets/login-header-bg3.png");
+          &::-webkit-input-placeholder {
+            color: #145da5;
+          }
+
+          &:focus {
+            + .line {
+              @apply w-full;
             }
+          }
         }
-    }
 
-    .main {
-        @apply relative flex justify-center items-center;
-        height: calc(100% - 68px);
-
-        .panel {
-            @apply relative z-40 flex items-center justify-center flex-col;
-            width: 487px;
-            height: 487px;
-            margin-top: -80px;
-            background: url("@/assets/login-panel.png") no-repeat;
-
-            .input-wrap {
-                @apply flex justify-center relative;
-                width: 250px;
-                height: 40px;
-                margin-top: 40px;
-                border-bottom: 2px solid #145da5;
-                background: no-repeat 0 center;
-                background-size: 31px 31px;
-
-                &.username {
-                    background-image: url("@/assets/login-input-user-icon.svg");
-                }
-
-                &.password {
-                    margin-top: 36px;
-                    background-image: url("@/assets/login-input-password-icon.svg");
-                }
-
-                .input {
-                    @apply w-full h-full outline-none bg-transparent;
-                    font-size: 21px;
-                    color: #8ae2ff;
-                    padding-left: 50px;
-
-                    &::-ms-input-placeholder {
-                        color: #145da5;
-                    }
-
-                    &::-moz-placeholder {
-                        color: #145da5;
-                    }
-
-                    &::-webkit-input-placeholder {
-                        color: #145da5;
-                    }
-
-                    &:focus {
-                        + .line {
-                            @apply w-full;
-                        }
-                    }
-                }
-
-                .line {
-                    @apply absolute w-0;
-                    height: 2px;
-                    content: " ";
-                    bottom: -2px;
-                    background-color: #459ef7;
-                    transition: width 0.2s;
-                }
+        .line {
+          @apply absolute w-0;
+          height: 2px;
+          content: " ";
+          bottom: -2px;
+          background-color: #459ef7;
+          transition: width 0.2s;
+        }
+      }
+
+      .login-btn {
+        @apply relative;
+        margin-top: 40px;
+
+        .button {
+          width: 120px;
+          height: 40px;
+          line-height: 40px;
+          background: url("@/assets/login-btn.png") no-repeat;
+          background-size: 100%;
+          color: #9ae1f9;
+          font-size: 18px;
+        }
+
+        .flash-wrap {
+          @apply absolute top-0 w-full h-full cursor-pointer;
+          clip-path: inset(0 0 round 10px);
+          transition: all 0.2s;
+
+          &:hover {
+            .flash {
+              animation: flash-change 1s ease 0s;
             }
+          }
 
-            .login-btn {
-                @apply relative;
-                margin-top: 40px;
-
-                .button {
-                    width: 120px;
-                    height: 40px;
-                    line-height: 40px;
-                    background: url("@/assets/login-btn.png") no-repeat;
-                    background-size: 100%;
-                    color: #9ae1f9;
-                    font-size: 18px;
-                }
-
-                .flash-wrap {
-                    @apply absolute top-0 w-full h-full cursor-pointer;
-                    clip-path: inset(0 0 round 10px);
-                    transition: all 0.2s;
-
-                    &:hover {
-                        .flash {
-                            animation: flash-change 1s ease 0s;
-                        }
-                    }
-
-                    .flash {
-                        @apply absolute top-0 w-1/3 h-full;
-                        left: -100%;
-                        background: linear-gradient(
+          .flash {
+            @apply absolute top-0 w-1/3 h-full;
+            left: -100%;
+            background: linear-gradient(
                             to right,
                             rgba(255, 255, 255, 0) 0,
                             rgba(255, 255, 255, 0.4) 50%,
                             rgba(255, 255, 255, 0) 100%
-                        );
-                        transform: skewX(-45deg);
-                        animation-iteration-count: infinite;
-                    }
-                }
-            }
+            );
+            transform: skewX(-45deg);
+            animation-iteration-count: infinite;
+          }
         }
+      }
+    }
+
+    .aperture {
+      @apply absolute z-20;
+      width: 617px;
+      height: 617px;
+      margin-top: -80px;
+      background: url("@/assets/login-aperture.png") no-repeat center center;
+      background-size: contain;
+      animation: aperture-rotate 12s linear infinite;
+    }
 
-        .aperture {
-            @apply absolute z-20;
-            width: 617px;
-            height: 617px;
-            margin-top: -80px;
-            background: url("@/assets/login-aperture.png") no-repeat center center;
-            background-size: contain;
-            animation: aperture-rotate 12s linear infinite;
+    .rotating-base {
+      @apply absolute z-10;
+      transform: scale(0.6);
+      margin-top: 510px;
+      filter: brightness(2);
+    }
+
+    .module {
+      @apply absolute z-30 flex justify-center items-center;
+      width: 1100px;
+      height: 500px;
+      margin-top: -60px;
+
+      .item {
+        @apply absolute flex justify-center cursor-pointer transform-gpu select-none opacity-95;
+        width: 180px;
+        height: 156px;
+        color: #c1ecfa;
+        font-size: 22px;
+        padding-top: 40px;
+        background: url("@/assets/login-module-item-normal.png") no-repeat center;
+        background-size: cover;
+        transition: all 0.26s;
+
+        &.can-hover:hover {
+          @apply opacity-100;
+          background-image: url("@/assets/login-module-item-hover.png");
+          transform: scale(1.06);
         }
 
-        .rotating-base {
-            @apply absolute z-10;
-            transform: scale(0.6);
-            margin-top: 510px;
-            filter: brightness(2);
+        &.budget {
+          left: 40px;
+          top: 0;
         }
 
-        .module {
-            @apply absolute z-30 flex justify-center items-center;
-            width: 1100px;
-            height: 500px;
-            margin-top: -60px;
-
-            .item {
-                @apply absolute flex justify-center cursor-pointer transform-gpu select-none opacity-95;
-                width: 180px;
-                height: 156px;
-                color: #c1ecfa;
-                font-size: 22px;
-                padding-top: 40px;
-                background: url("@/assets/login-module-item-normal.png") no-repeat center;
-                background-size: cover;
-                transition: all 0.26s;
-
-                &.can-hover:hover {
-                    @apply opacity-100;
-                    background-image: url("@/assets/login-module-item-hover.png");
-                    transform: scale(1.06);
-                }
-
-                &.budget {
-                    left: 40px;
-                    top: 0;
-                }
-
-                &.estimate {
-                    left: 0;
-                    top: 170px;
-                }
-
-                &.util {
-                    left: 80px;
-                    top: 340px;
-                }
-
-                &.settlement {
-                    right: 40px;
-                    top: 0;
-                }
-
-                &.final {
-                    right: 0;
-                    top: 170px;
-                }
-
-                &.check {
-                    right: 80px;
-                    top: 340px;
-                }
-            }
+        &.estimate {
+          left: 0;
+          top: 170px;
+        }
+
+        &.util {
+          left: 80px;
+          top: 340px;
+        }
+
+        &.settlement {
+          right: 40px;
+          top: 0;
+        }
+
+        &.final {
+          right: 0;
+          top: 170px;
+        }
+
+        &.check {
+          right: 80px;
+          top: 340px;
         }
+      }
     }
+  }
 }

+ 28 - 21
src/views/main-frame/MainFrame.vue

@@ -1,26 +1,25 @@
 <script setup lang="ts">
-import { ref, computed } from 'vue'
-import { useRoute } from 'vue-router'
-import { invokeAllRefreshCallback } from '@/composables/useRefresh'
-import breadcrumbStore from '@/store/modules/breadcrumb'
-import { isUndefined } from 'lodash'
+import { ref, computed } from "vue";
+import { useRoute } from "vue-router";
+import { invokeAllRefreshCallback } from "@/composables/useRefresh";
+import breadcrumbStore from "@/store/modules/breadcrumb";
+import { isUndefined } from "lodash";
 
-const route = useRoute()
+const route = useRoute();
 
-const refreshing = ref(false)
+const refreshing = ref(false);
 
 const handleRefresh = () => {
-  if (refreshing.value)
-    return
+  if (refreshing.value) return;
 
-  invokeAllRefreshCallback()
-  refreshing.value = true
+  invokeAllRefreshCallback();
+  refreshing.value = true;
   setTimeout(() => {
-    refreshing.value = false
+    refreshing.value = false;
   }, 1000);
-}
+};
 
-const breadcrumbs = computed(() => breadcrumbStore.breadcrumbs)
+const breadcrumbs = computed(() => breadcrumbStore.breadcrumbs);
 </script>
 
 <template>
@@ -32,8 +31,12 @@ const breadcrumbs = computed(() => breadcrumbStore.breadcrumbs)
       </span>
       <el-breadcrumb separator="/">
         <template v-for="item in breadcrumbs">
-          <el-breadcrumb-item v-if="isUndefined(item.path)">{{ item.label }}</el-breadcrumb-item>
-          <el-breadcrumb-item v-else :to="{ path: item.path }">{{ item.label }}</el-breadcrumb-item>
+          <el-breadcrumb-item v-if="isUndefined(item.path)">{{
+            item.label
+          }}</el-breadcrumb-item>
+          <el-breadcrumb-item v-else :to="{ path: item.path }">{{
+            item.label
+          }}</el-breadcrumb-item>
         </template>
       </el-breadcrumb>
       <span class="data-big-screen">
@@ -55,7 +58,7 @@ const breadcrumbs = computed(() => breadcrumbStore.breadcrumbs)
     <aside class="aside">
       <ul class="menu">
         <router-link custom to="/" v-slot="{ navigate, isExactActive }">
-          <li class="item" @click="navigate" :class="{ 'active': isExactActive }">
+          <li class="item" @click="navigate" :class="{ active: isExactActive }">
             <iconfont class="icon dsk-dashboard-one" />
           </li>
         </router-link>
@@ -64,18 +67,22 @@ const breadcrumbs = computed(() => breadcrumbStore.breadcrumbs)
           <li
             class="item"
             @click="navigate"
-            :class="{ 'active': route.fullPath.startsWith('/project') }"
+            :class="{ active: route.fullPath.startsWith('/project') }"
           >
             <iconfont class="icon dsk-city-one" />
           </li>
         </router-link>
-        <router-link custom to="/data-library" v-slot="{ navigate, isExactActive }">
-          <li class="item" @click="navigate" :class="{ 'active': isExactActive }">
+        <router-link
+          custom
+          to="/data-library"
+          v-slot="{ navigate, isExactActive }"
+        >
+          <li class="item" @click="navigate" :class="{ active: isExactActive }">
             <iconfont class="icon dsk-data" />
           </li>
         </router-link>
         <router-link custom to="/login" v-slot="{ navigate, isExactActive }">
-          <li class="item" @click="navigate" :class="{ 'active': isExactActive }">
+          <li class="item" @click="navigate" :class="{ active: isExactActive }">
             <iconfont class="icon dsk-me" />
           </li>
         </router-link>

+ 3 - 1
src/views/main-frame/style.scss

@@ -53,12 +53,14 @@
         @media (max-width: 900px) {
           display: none;
         }
-        
+
         .el-breadcrumb__inner {
           color: rgba(255, 255, 255, 0.7);
           font-size: 15px;
+
           &.is-link {
             font-weight: 400;
+
             &:hover {
               color: #fff;
             }

+ 71 - 33
src/views/project-list/ProjectList.vue

@@ -1,20 +1,20 @@
 <script setup lang="ts">
 import { reactive, ref } from "vue";
-import breadcrumbStore from '@/store/modules/breadcrumb'
+import breadcrumbStore from "@/store/modules/breadcrumb";
 
 const filterForm = reactive({
-  name: '',
-  type: '',
-  process: '',
-  step: '',
-  time: ''
-})
+  name: "",
+  type: "",
+  process: "",
+  step: "",
+  time: "",
+});
 
-const inlineMode = ref(true)
+const inlineMode = ref(true);
 
 const list = [
   {
-    ID: '1',
+    ID: "1",
     name: "市妇幼保健医院新址配套市政道路工程",
     process: "预算",
     step: "(2) 收件员预审项目",
@@ -24,7 +24,7 @@ const list = [
     offset: "0.00",
   },
   {
-    ID: '2',
+    ID: "2",
     name: "梧桐路(石花西路)电力改迁工程",
     process: "结算",
     step: "(1) 建设单位报审项目",
@@ -34,7 +34,7 @@ const list = [
     offset: "0.00",
   },
   {
-    ID: '3',
+    ID: "3",
     name: "珠海城市职业技术学院机电学院、航空与海洋工程珠海城市职业技术学院机电学院、航空与海洋工程",
     process: "预算",
     step: "(1) 建设单位报审项目",
@@ -44,7 +44,7 @@ const list = [
     offset: "0.00",
   },
   {
-    ID: '4',
+    ID: "4",
     name: "珠海城市职业技术学院机电学院、航空与海洋工程",
     process: "预算",
     step: "(5) 主审人编制审核方案",
@@ -54,7 +54,7 @@ const list = [
     offset: "0.00",
   },
   {
-    ID: '5',
+    ID: "5",
     name: "珠海城市职业技术学院机电学院、航空与海洋工程",
     process: "预算",
     step: "(5) 主审人编制审核方案",
@@ -63,20 +63,20 @@ const list = [
     decrease: "0.00",
     offset: "0.00",
   },
-]
-list.push(...list)
+];
+list.push(...list);
 const projectList = reactive(list);
 
 const onSubmit = () => {
   //
-}
+};
 
-const { setBreadcrumb } = breadcrumbStore
+const { setBreadcrumb } = breadcrumbStore;
 setBreadcrumb([
   {
-    label: '项目列表',
-  }
-])
+    label: "项目列表",
+  },
+]);
 </script>
 
 <template>
@@ -88,28 +88,47 @@ setBreadcrumb([
     <main class="main">
       <el-form inline :model="filterForm" :label-width="80">
         <el-form-item label="项目名称" class="name-item">
-          <el-input v-model="filterForm.name" placeholder="请输入项目名称"></el-input>
+          <el-input
+            v-model="filterForm.name"
+            placeholder="请输入项目名称"
+          ></el-input>
         </el-form-item>
-        <el-form-item label="工程类型" class="type-item" :class="{ inline: inlineMode }">
+        <el-form-item
+          label="工程类型"
+          class="type-item"
+          :class="{ inline: inlineMode }"
+        >
           <el-select v-model="filterForm.type" placeholder="请选择工程类型">
             <el-option label="Zone one" value="shanghai"></el-option>
             <el-option label="Zone two" value="beijing"></el-option>
           </el-select>
         </el-form-item>
-        <el-form-item label="项目流程" class="process-item" :class="{ inline: inlineMode }">
+        <el-form-item
+          label="项目流程"
+          class="process-item"
+          :class="{ inline: inlineMode }"
+        >
           <el-select v-model="filterForm.process" placeholder="请选择项目流程">
             <el-option label="Zone one" value="shanghai"></el-option>
             <el-option label="Zone two" value="beijing"></el-option>
           </el-select>
         </el-form-item>
         <br v-if="!inlineMode" />
-        <el-form-item label="审核步骤" class="step-item" :class="{ inline: inlineMode }">
+        <el-form-item
+          label="审核步骤"
+          class="step-item"
+          :class="{ inline: inlineMode }"
+        >
           <el-select v-model="filterForm.step" placeholder="请选择审核步骤">
             <el-option label="Zone one" value="shanghai"></el-option>
             <el-option label="Zone two" value="beijing"></el-option>
           </el-select>
         </el-form-item>
-        <el-form-item label="流程时间" class="time-item" :class="{ inline: inlineMode }">
+        <el-form-item
+          label="流程时间"
+          class="time-item"
+          :class="{ inline: inlineMode }"
+        >
           <el-select v-model="filterForm.time" placeholder="请选择">
             <el-option label="Zone one" value="shanghai"></el-option>
             <el-option label="Zone two" value="beijing"></el-option>
@@ -129,18 +148,37 @@ setBreadcrumb([
       <el-table :data="projectList">
         <el-table-column prop="name" label="项目名称" :min-width="300">
           <template #default="scope">
-            <router-link
-              :to="`/project?projectID=${scope.row.ID}`"
-              class="link"
-            >{{ scope.row.name }}</router-link>
+            <router-link :to="`/project?projectID=${scope.row.ID}`" class="link"
+              >{{ scope.row.name }}
+            </router-link>
           </template>
         </el-table-column>
         <el-table-column prop="process" label="项目流程" :min-width="80" />
         <el-table-column prop="step" label="当前步骤" :min-width="140" />
-        <el-table-column prop="submit" label="送审金额(元)" align="center" :min-width="115" />
-        <el-table-column prop="increase" label="审增金额(元)" align="center" :min-width="115" />
-        <el-table-column prop="decrease" label="审减金额(元)" align="center" :min-width="115" />
-        <el-table-column prop="offset" label="品迭金额(元)" align="center" :min-width="115" />
+        <el-table-column
+          prop="submit"
+          label="送审金额(元)"
+          align="center"
+          :min-width="115"
+        />
+        <el-table-column
+          prop="increase"
+          label="审增金额(元)"
+          align="center"
+          :min-width="115"
+        />
+        <el-table-column
+          prop="decrease"
+          label="审减金额(元)"
+          align="center"
+          :min-width="115"
+        />
+        <el-table-column
+          prop="offset"
+          label="品迭金额(元)"
+          align="center"
+          :min-width="115"
+        />
         <template #empty>
           <el-empty :image-size="120" description="暂无项目" />
         </template>

+ 34 - 22
src/views/project/Project.vue

@@ -1,27 +1,25 @@
 <script setup lang="ts">
 import { onMounted, ref } from "vue";
-import useProjectID from '@/composables/useProjectID'
-import { useRoute } from 'vue-router'
-import breadcrumbStore from '@/store/modules/breadcrumb'
-const route = useRoute()
+import useProjectID from "@/composables/useProjectID";
+import { useRoute } from "vue-router";
+import breadcrumbStore from "@/store/modules/breadcrumb";
 
-const {
-  shouldRender,
-  projectID
-} = useProjectID()
+const route = useRoute();
 
-console.log('项目 ID', projectID)
+const { shouldRender, projectID } = useProjectID();
 
-const { setBreadcrumb } = breadcrumbStore
+console.log("项目 ID", projectID);
+
+const { setBreadcrumb } = breadcrumbStore;
 setBreadcrumb([
   {
-    label: '项目列表',
-    path: '/project-list'
+    label: "项目列表",
+    path: "/project-list",
   },
   {
-    label: '莲花路电力迁改项目'
-  }
-])
+    label: "莲花路电力迁改项目",
+  },
+]);
 </script>
 
 <template>
@@ -33,18 +31,26 @@ setBreadcrumb([
     >
       <h1 class="name">莲花路电力迁改项目</h1>
       <el-descriptions :column="4" size="mini">
-        <el-descriptions-item label="申请单位:">某某建筑公司</el-descriptions-item>
-        <el-descriptions-item label="审批单位:">某某审批单位</el-descriptions-item>
+        <el-descriptions-item label="申请单位:"
+          >某某建筑公司</el-descriptions-item
+        >
+        <el-descriptions-item label="审批单位:"
+          >某某审批单位</el-descriptions-item
+        >
         <el-descriptions-item label="工程类型:">某某类型</el-descriptions-item>
         <el-descriptions-item label="项目编号:">100000</el-descriptions-item>
-        <el-descriptions-item label="工程时间:">2022-01-01 至 2023-12-31</el-descriptions-item>
+        <el-descriptions-item label="工程时间:"
+          >2022-01-01 至 2023-12-31</el-descriptions-item
+        >
         <el-descriptions-item label="状态:">
           <el-tag size="small">待审批</el-tag>
         </el-descriptions-item>
         <el-descriptions-item label="当前流程:">
           <el-tag size="small" type="success">某某步骤</el-tag>
         </el-descriptions-item>
-        <el-descriptions-item label="工程地址:">珠海市香洲区某某街道某某路100号</el-descriptions-item>
+        <el-descriptions-item label="工程地址:"
+          >珠海市香洲区某某街道某某路100号</el-descriptions-item
+        >
       </el-descriptions>
 
       <el-affix :offset="64">
@@ -58,7 +64,9 @@ setBreadcrumb([
               class="item overview"
               @click="navigate"
               :class="{ 'exact-active': isExactActive }"
-            >项目概况</li>
+            >
+              项目概况
+            </li>
           </router-link>
           <router-link
             custom
@@ -69,7 +77,9 @@ setBreadcrumb([
               class="item process"
               @click="navigate"
               :class="{ 'exact-active': isExactActive }"
-            >项目流程</li>
+            >
+              项目流程
+            </li>
           </router-link>
           <router-link
             custom
@@ -80,7 +90,9 @@ setBreadcrumb([
               class="item summary"
               @click="navigate"
               :class="{ 'exact-active': isExactActive }"
-            >项目流汇总</li>
+            >
+              项目流汇总
+            </li>
           </router-link>
           <!-- <router-link
             custom

+ 119 - 104
src/views/project/overview/Overview.vue

@@ -1,106 +1,114 @@
 <script setup lang="ts">
 import { onMounted, reactive, ref } from "vue";
-import { registerRefreshCallback } from '@/composables/useRefresh'
-import useProjectID from '@/composables/useProjectID'
+import { registerRefreshCallback } from "@/composables/useRefresh";
+import useProjectID from "@/composables/useProjectID";
 
-import * as echarts from 'echarts';
+import * as echarts from "echarts";
 
-const {
-  shouldRender,
-  projectID
-} = useProjectID()
+const { shouldRender, projectID } = useProjectID();
 
-console.log('项目 ID', projectID)
-
-const chart1Ref = ref<HTMLDivElement>()
-const chart2Ref = ref<HTMLDivElement>()
-const chart3Ref = ref<HTMLDivElement>()
+console.log("项目 ID", projectID);
 
+const chart1Ref = ref<HTMLDivElement>();
+const chart2Ref = ref<HTMLDivElement>();
+const chart3Ref = ref<HTMLDivElement>();
 
 onMounted(() => {
   if (chart1Ref.value && chart2Ref.value && chart3Ref.value) {
     const myChart1 = echarts.init(chart1Ref.value);
     const option1 = {
       xAxis: {
-        type: 'category',
-        data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
+        type: "category",
+        data: [
+          "1月",
+          "2月",
+          "3月",
+          "4月",
+          "5月",
+          "6月",
+          "7月",
+          "8月",
+          "9月",
+          "10月",
+          "11月",
+          "12月",
+        ],
       },
       yAxis: {
-        type: 'value'
+        type: "value",
       },
 
       series: [
         {
           data: [120, 200, 150, 80, 70, 110, 130, 140, 210, 100, 80, 20],
-          type: 'bar',
+          type: "bar",
           itemStyle: {
             color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-              { offset: 0, color: '#83bff6' },
-              { offset: 0.5, color: '#188df0' },
-              { offset: 1, color: '#188df0' }
-            ])
+              { offset: 0, color: "#83bff6" },
+              { offset: 0.5, color: "#188df0" },
+              { offset: 1, color: "#188df0" },
+            ]),
           },
-        }
-      ]
+        },
+      ],
     };
     myChart1.setOption(option1);
 
     const myChart2 = echarts.init(chart2Ref.value);
     const option2 = {
       tooltip: {
-        trigger: 'item'
+        trigger: "item",
       },
       legend: {
-        top: '5%',
-        left: 'center'
+        top: "5%",
+        left: "center",
       },
       series: [
         {
-          name: 'Access From',
-          type: 'pie',
-          radius: ['50%', '60%'],
+          name: "Access From",
+          type: "pie",
+          radius: ["50%", "60%"],
           avoidLabelOverlap: true,
           label: {
             show: false,
-            position: 'center'
+            position: "center",
           },
           emphasis: {
             label: {
               show: false,
-              fontSize: '40',
-              fontWeight: 'bold'
-            }
+              fontSize: "40",
+              fontWeight: "bold",
+            },
           },
           labelLine: {
-            show: false
+            show: false,
           },
           data: [
-            { value: 1048, name: '人工费' },
-            { value: 735, name: '材料费' },
-            { value: 580, name: '其他' },
-          ]
-        }
-      ]
+            { value: 1048, name: "人工费" },
+            { value: 735, name: "材料费" },
+            { value: 580, name: "其他" },
+          ],
+        },
+      ],
     };
     myChart2.setOption(option2);
 
-
     const myChart3 = echarts.init(chart3Ref.value);
     const option3 = {
       series: [
         {
-          type: 'gauge',
+          type: "gauge",
           progress: {
             show: true,
-            width: 5
+            width: 5,
           },
           axisLine: {
             lineStyle: {
-              width: 5
-            }
+              width: 5,
+            },
           },
           axisTick: {
-            show: false
+            show: false,
           },
           splitLine: {
             show: false,
@@ -113,98 +121,95 @@ onMounted(() => {
             showAbove: true,
             size: 10,
             itemStyle: {
-              borderWidth: 2
-            }
+              borderWidth: 2,
+            },
           },
           title: {
-            show: false
+            show: false,
           },
           detail: {
             valueAnimation: true,
             fontSize: 20,
-            offsetCenter: [0, '70%']
+            offsetCenter: [0, "70%"],
           },
           data: [
             {
-              value: 70
-            }
-          ]
-        }
-      ]
+              value: 70,
+            },
+          ],
+        },
+      ],
     };
     myChart3.setOption(option3);
 
-
     window.onresize = function () {
-      myChart1.resize()
-      myChart2.resize()
-      myChart3.resize()
+      myChart1.resize();
+      myChart2.resize();
+      myChart3.resize();
     };
   }
-
-})
+});
 
 const list = [
   {
-    type: '财务审核',
-    who: '张三',
-    result: '成功',
-    time: '2022-07-28 09:41:00',
-    remark: '通过',
+    type: "财务审核",
+    who: "张三",
+    result: "成功",
+    time: "2022-07-28 09:41:00",
+    remark: "通过",
   },
   {
-    type: '财务审核',
-    who: '张三',
-    result: '成功',
-    time: '2022-07-28 09:41:00',
-    remark: '通过',
+    type: "财务审核",
+    who: "张三",
+    result: "成功",
+    time: "2022-07-28 09:41:00",
+    remark: "通过",
   },
   {
-    type: '财务审核',
-    who: '张三',
-    result: '成功',
-    time: '2022-07-28 09:41:00',
-    remark: '通过',
+    type: "财务审核",
+    who: "张三",
+    result: "成功",
+    time: "2022-07-28 09:41:00",
+    remark: "通过",
   },
   {
-    type: '财务审核',
-    who: '张三',
-    result: '成功',
-    time: '2022-07-28 09:41:00',
-    remark: '通过',
+    type: "财务审核",
+    who: "张三",
+    result: "成功",
+    time: "2022-07-28 09:41:00",
+    remark: "通过",
   },
-]
-list.push(...list)
+];
+list.push(...list);
 const logList = reactive(list);
 
 const appoveList = reactive([
   {
-    name: '张三',
-    number: '001',
-    department: '财务部门'
+    name: "张三",
+    number: "001",
+    department: "财务部门",
   },
   {
-    name: '李四',
-    number: '002',
-    department: '财务部门'
+    name: "李四",
+    number: "002",
+    department: "财务部门",
   },
   {
-    name: '王五',
-    number: '003',
-    department: '财务部门'
+    name: "王五",
+    number: "003",
+    department: "财务部门",
   },
   {
-    name: '赵六',
-    number: '004',
-    department: '财务部门'
-  }
-])
+    name: "赵六",
+    number: "004",
+    department: "财务部门",
+  },
+]);
 
 // 顶部刷新按钮点击事件
 registerRefreshCallback(() => {
-  console.log('overview 顶部刷新按钮被点击了')
-})
-
+  console.log("overview 顶部刷新按钮被点击了");
+});
 </script>
 
 <template>
@@ -270,11 +275,17 @@ registerRefreshCallback(() => {
 
     <el-card shadow="never" header="项目信息">
       <el-descriptions :column="4" size="small">
-        <el-descriptions-item label="申请单位:">某某建筑公司</el-descriptions-item>
+        <el-descriptions-item label="申请单位:"
+          >某某建筑公司
+        </el-descriptions-item>
         <el-descriptions-item label="单位编号:">11111111</el-descriptions-item>
         <el-descriptions-item label="负责人:">张三</el-descriptions-item>
-        <el-descriptions-item label="评估单位:">某某建筑公司</el-descriptions-item>
-        <el-descriptions-item label="审批单位:">某某审批单位</el-descriptions-item>
+        <el-descriptions-item label="评估单位:"
+          >某某建筑公司
+        </el-descriptions-item>
+        <el-descriptions-item label="审批单位:"
+          >某某审批单位
+        </el-descriptions-item>
         <el-descriptions-item label="工程类型:">某某类型</el-descriptions-item>
         <el-descriptions-item label="项目编号:">100000</el-descriptions-item>
         <el-descriptions-item label="项目规模:">100000</el-descriptions-item>
@@ -282,7 +293,9 @@ registerRefreshCallback(() => {
           <el-tag size="small" type="danger">紧急</el-tag>
         </el-descriptions-item>
         <el-descriptions-item label="预计报价:">100000</el-descriptions-item>
-        <el-descriptions-item label="工程时间:">2022-01-01 至 2023-12-31</el-descriptions-item>
+        <el-descriptions-item label="工程时间:"
+          >2022-01-01 至 2023-12-31
+        </el-descriptions-item>
         <el-descriptions-item label="工程周期:">2年</el-descriptions-item>
         <el-descriptions-item label="人员规模:">200</el-descriptions-item>
         <el-descriptions-item label="备注:">没有备注</el-descriptions-item>
@@ -292,7 +305,9 @@ registerRefreshCallback(() => {
         <el-descriptions-item label="当前流程:">
           <el-tag size="small" type="success">某某步骤</el-tag>
         </el-descriptions-item>
-        <el-descriptions-item label="工程地址:">珠海市香洲区某某街道某某路100号</el-descriptions-item>
+        <el-descriptions-item label="工程地址:"
+          >珠海市香洲区某某街道某某路100号
+        </el-descriptions-item>
       </el-descriptions>
     </el-card>
 

+ 8 - 7
src/views/project/process/Process.vue

@@ -1,13 +1,10 @@
 <script setup lang="ts">
 import { onMounted, reactive, ref } from "vue";
-import useProjectID from '@/composables/useProjectID'
+import useProjectID from "@/composables/useProjectID";
 
-const {
-  shouldRender,
-  projectID
-} = useProjectID()
+const { shouldRender, projectID } = useProjectID();
 
-console.log('项目 ID', projectID)
+console.log("项目 ID", projectID);
 
 const steps = reactive([
   {
@@ -108,7 +105,11 @@ const steps = reactive([
     <div class="wrap">
       <el-affix :offset="130">
         <el-card header="步骤" shadow="never" class="step">
-          <el-tree :data="steps" default-expand-all :expand-on-click-node="false" />
+          <el-tree
+            :data="steps"
+            default-expand-all
+            :expand-on-click-node="false"
+          />
         </el-card>
       </el-affix>
       <el-card shadow="never" class="preview">

+ 3 - 6
src/views/project/report/Report.vue

@@ -1,13 +1,10 @@
 <script setup lang="ts">
 import { onMounted, reactive, ref } from "vue";
-import useProjectID from '@/composables/useProjectID'
+import useProjectID from "@/composables/useProjectID";
 
-const {
-  shouldRender,
-  projectID
-} = useProjectID()
+const { shouldRender, projectID } = useProjectID();
 
-console.log('项目 ID', projectID)
+console.log("项目 ID", projectID);
 </script>
 
 <template>

+ 35 - 38
src/views/project/summary/Summary.vue

@@ -6,19 +6,16 @@ import CostTable from "./components/cost-table/CostTable.vue";
 import BottomTabs from "./components/bottom-tabs/BottomTabs.vue";
 import StdBill from "./components/std-bill/StdBill.vue";
 import LibRation from "./components/lib-ration/LibRation.vue";
-import { SubjectTreeNodeType } from '@/constants/subject'
+import { SubjectTreeNodeType } from "@/constants/subject";
 import { Subject } from "@/types/subject";
-import useSummaryLayout from './scripts/useSummaryLayout'
-import { registerRefreshCallback } from '@/composables/useRefresh'
+import useSummaryLayout from "./scripts/useSummaryLayout";
+import { registerRefreshCallback } from "@/composables/useRefresh";
 
-import useProjectID from '@/composables/useProjectID'
+import useProjectID from "@/composables/useProjectID";
 
-const {
-  shouldRender,
-  projectID
-} = useProjectID()
+const { shouldRender, projectID } = useProjectID();
 
-console.log('项目 ID', projectID)
+console.log("项目 ID", projectID);
 
 // 布局相关代码
 const {
@@ -42,79 +39,79 @@ const {
   handleMainRightSize,
   handleMainLeftTopSize,
   handleMainLeftBottomSize,
-} = useSummaryLayout()
+} = useSummaryLayout();
 
-const loading = ref(true)
+const loading = ref(true);
 
 // 侧边树结构数据
-const treeData = reactive<Subject.ISubjectTreeNode[]>([])
+const treeData = reactive<Subject.ISubjectTreeNode[]>([]);
 
 onMounted(async () => {
   setTimeout(() => {
     treeData.push({
-      id: '1',
-      label: '市妇幼保健院新址配套市政道路',
-      icon: 'dsk-city-one',
+      id: "1",
+      label: "市妇幼保健院新址配套市政道路",
+      icon: "dsk-city-one",
       type: SubjectTreeNodeType.CONSTRUCTION,
       children: [
         {
-          id: '1.1',
-          label: '单项工程1',
-          icon: 'dsk-home-two',
+          id: "1.1",
+          label: "单项工程1",
+          icon: "dsk-home-two",
           type: SubjectTreeNodeType.SINGLE,
           children: [
             {
-              id: '1.1.1',
-              label: '单位工程1.1',
+              id: "1.1.1",
+              label: "单位工程1.1",
               type: SubjectTreeNodeType.UNIT,
             },
             {
-              id: '1.1.2',
-              label: '单位工程1.2',
+              id: "1.1.2",
+              label: "单位工程1.2",
               type: SubjectTreeNodeType.UNIT,
             },
           ],
         },
         {
-          id: '1.2',
-          label: '单项工程2',
-          icon: 'dsk-home-two',
+          id: "1.2",
+          label: "单项工程2",
+          icon: "dsk-home-two",
           type: SubjectTreeNodeType.SINGLE,
           children: [
             {
-              id: '1.2.1',
-              label: '单位工程2.1',
+              id: "1.2.1",
+              label: "单位工程2.1",
               type: SubjectTreeNodeType.UNIT,
             },
             {
-              id: '1.2.2',
-              label: '单位工程2.2',
+              id: "1.2.2",
+              label: "单位工程2.2",
               type: SubjectTreeNodeType.UNIT,
             },
           ],
         },
       ],
-    })
+    });
 
-    loading.value = false
+    loading.value = false;
   }, 1000);
-})
+});
 
-const mainLayout = ref<ResizableLayout.IResizableLayoutComponent>()
+const mainLayout = ref<ResizableLayout.IResizableLayoutComponent>();
 const handleRightVisibleChange = async (needRender: boolean) => {
   if (needRender) {
     setTimeout(() => {
       costTableRef.value && costTableRef.value.Render();
       bottomTabsRef.value && bottomTabsRef.value.Render();
-    }, 100)
+    }, 100);
   }
-  mainLayout.value && mainLayout.value.Refresh()
-}
+  mainLayout.value && mainLayout.value.Refresh();
+};
 
 // 顶部刷新按钮点击事件
 registerRefreshCallback(() => {
-  console.log('summary 顶部刷新按钮被点击了')
-})
+  console.log("summary 顶部刷新按钮被点击了");
+});
 </script>
 
 <template>

+ 4 - 4
src/views/project/summary/components/bottom-tabs/BottomTabs.vue

@@ -4,12 +4,12 @@ import { onMounted, reactive, ref } from "vue";
 const Render = () => {
   // 重新渲染
   // hotRef.value && hotRef.value.Render();
-  console.log('bottom tabs render')
-}
+  console.log("bottom tabs render");
+};
 
 defineExpose({
-  Render
-})
+  Render,
+});
 </script>
 
 <template>

+ 2 - 0
src/views/project/summary/components/bottom-tabs/style.scss

@@ -18,6 +18,7 @@
       line-height: 36px;
       color: #515a6e;
       transition: none;
+
       &.is-active {
         color: #409eff;
       }
@@ -27,6 +28,7 @@
   ::v-deep .el-tabs__content {
     padding: 0;
     height: calc(100% - 35px);
+
     .el-tab-pane {
       @apply w-full h-full;
     }

+ 28 - 28
src/views/project/summary/components/cost-table/CostTable.vue

@@ -1,10 +1,10 @@
 <script setup lang="ts">
 import { onMounted, ref } from "vue";
-import { Tree, TreeNode } from '@sc/tree';
-import { expandAllTreeNode } from '@/utils/frontend/tree';
-import useHotRef from '@/composables/useHotRef';
-import rawData from '@/constants/tmp/table-data.json'
-import tblColMeta from '@/constants/tmp/table-columns-meta'
+import { Tree, TreeNode } from "@sc/tree";
+import { expandAllTreeNode } from "@/utils/frontend/tree";
+import useHotRef from "@/composables/useHotRef";
+import rawData from "@/constants/tmp/table-data.json";
+import tblColMeta from "@/constants/tmp/table-columns-meta";
 import { Hot } from "@/types/components";
 
 const { getHotRef, notNull } = useHotRef();
@@ -30,28 +30,28 @@ const tableSettings = {
   // fixedColumnsLeft: 2,
   groupingHeaders: [
     [
-      { label: '项目编码', rowspan: 2 },
-      { label: '项目名称', rowspan: 2 },
-      { label: '计量单位', rowspan: 2 },
-      { label: '工程量', rowspan: 2 },
-      { label: '初始报价', colspan: 2 },
-      { label: '目标造价', colspan: 2 },
-      { label: '调整后报价', colspan: 2 },
-      { label: '消耗量调整系数', colspan: 5 },
-      { label: '子目工程量调整系数', rowspan: 2 },
+      { label: "项目编码", rowspan: 2 },
+      { label: "项目名称", rowspan: 2 },
+      { label: "计量单位", rowspan: 2 },
+      { label: "工程量", rowspan: 2 },
+      { label: "初始报价", colspan: 2 },
+      { label: "目标造价", colspan: 2 },
+      { label: "调整后报价", colspan: 2 },
+      { label: "消耗量调整系数", colspan: 5 },
+      { label: "子目工程量调整系数", rowspan: 2 },
     ],
     [
-      '综合单价',
-      '综合合价',
-      '综合单价',
-      '综合合价',
-      '综合单价',
-      '综合合价',
-      '人工',
-      '材料',
-      '机械',
-      '主材',
-      '设备',
+      "综合单价",
+      "综合合价",
+      "综合单价",
+      "综合合价",
+      "综合单价",
+      "综合合价",
+      "人工",
+      "材料",
+      "机械",
+      "主材",
+      "设备",
     ],
   ],
 };
@@ -59,11 +59,11 @@ const tableSettings = {
 const Render = () => {
   // 重新渲染
   hotRef.value && hotRef.value.Render();
-}
+};
 
 defineExpose({
-  Render
-})
+  Render,
+});
 </script>
 
 <template>

+ 43 - 31
src/views/project/summary/components/lib-ration/LibRation.vue

@@ -2,30 +2,30 @@
 import { onMounted, reactive, ref } from "vue";
 import { ElInput } from "element-plus";
 
-const libID = ref('1')
+const libID = ref("1");
 const options = reactive([
   {
-    ID: '1',
-    name: 'Option1',
+    ID: "1",
+    name: "Option1",
   },
   {
-    ID: '2',
-    name: 'Option2',
+    ID: "2",
+    name: "Option2",
   },
-])
+]);
 
-const showSearchResult = ref(false)
-const searchCount = ref(0)
+const showSearchResult = ref(false);
+const searchCount = ref(0);
 
 // 搜索框的模板引用
 const searchRef = ref<typeof ElInput>();
 
 // 搜索结果页面定额类型
-const rationType = ref('selectedLib');
+const rationType = ref("selectedLib");
 
-const searchValue = ref('')
+const searchValue = ref("");
 const handleSearch = () => {
-  console.log('搜索')
+  console.log("搜索");
 
   searchRef.value && searchRef.value.blur();
   searchCount.value = 0;
@@ -33,31 +33,30 @@ const handleSearch = () => {
   // currentIndex = -1;
   showSearchResult.value = true;
   // const searchKey = searchValue.value.toLowerCase();
-}
+};
 
-const topSize = ref(60)
-const bottomSize = ref(40)
+const topSize = ref(60);
+const bottomSize = ref(40);
 
 const handleTopResize = (size: number) => {
-  topSize.value = size
-}
+  topSize.value = size;
+};
 
 const handleBottomResize = (size: number) => {
-  bottomSize.value = size
-}
+  bottomSize.value = size;
+};
 
-
-const showRationTable = ref(false)
+const showRationTable = ref(false);
 
 const Render = () => {
   // 重新渲染
   // hotRef.value && hotRef.value.Render();
-  console.log('lib ration render')
-}
+  console.log("lib ration render");
+};
 
 defineExpose({
-  Render
-})
+  Render,
+});
 </script>
 
 <template>
@@ -65,7 +64,12 @@ defineExpose({
     <!-- 过滤栏 -->
     <div class="filter-bar">
       <el-select size="mini" style="width: 100%" v-model="libID">
-        <el-option v-for="item in options" :key="item.ID" :label="item.name" :value="item.ID" />
+        <el-option
+          v-for="item in options"
+          :key="item.ID"
+          :label="item.name"
+          :value="item.ID"
+        />
       </el-select>
       <el-input
         size="mini"
@@ -93,7 +97,9 @@ defineExpose({
     </div>
     <div
       class="table-area"
-      :style="{ height: showSearchResult ? 'calc(100% - 68px)' : 'calc(100% - 36px)' }"
+      :style="{
+        height: showSearchResult ? 'calc(100% - 68px)' : 'calc(100% - 36px)',
+      }"
     >
       <resizable-layout direction="vertical" ref="layoutRef">
         <!-- 章节 -->
@@ -114,11 +120,16 @@ defineExpose({
           />-->
           <span
             class="临时待删"
-            style="display: block; height:100%; width:100%; background: #eee;"
-          >上面表格区域</span>
+            style="display: block; height: 100%; width: 100%; background: #eee"
+            >上面表格区域</span
+          >
         </resizable-layout-item>
         <!-- 定额 -->
-        <resizable-layout-item :weight="bottomSize" :min-height="200" @resize="handleBottomResize">
+        <resizable-layout-item
+          :weight="bottomSize"
+          :min-height="200"
+          @resize="handleBottomResize"
+        >
           <!-- <context-menu :item-groups="contextMenuGroups" :read-only="unitReadOnly"> -->
           <!-- <handsontable
               v-if="showRationTable"
@@ -131,9 +142,10 @@ defineExpose({
           />-->
           <span
             class="临时wrap,待删"
-            style="display: block; height:100%; width:100%; background: #eee;"
+            style="display: block; height: 100%; width: 100%; background: #eee"
             v-if="showRationTable"
-          >下面表格区域</span>
+            >下面表格区域</span
+          >
           <el-empty
             v-else
             :image-size="80"

+ 36 - 26
src/views/project/summary/components/std-bill/StdBill.vue

@@ -1,29 +1,29 @@
 <script setup lang="ts">
 import { ElInput } from "element-plus";
 import { reactive, ref, nextTick, watch } from "vue";
-import useHotRef from '@/composables/useHotRef';
+import useHotRef from "@/composables/useHotRef";
 
-const libID = ref('1')
+const libID = ref("1");
 const options = reactive([
   {
-    ID: '1',
-    name: 'Option1',
+    ID: "1",
+    name: "Option1",
   },
   {
-    ID: '2',
-    name: 'Option2',
+    ID: "2",
+    name: "Option2",
   },
-])
+]);
 
-const showSearchResult = ref(false)
-const searchCount = ref(0)
+const showSearchResult = ref(false);
+const searchCount = ref(0);
 
 // 搜索框的模板引用
 const searchRef = ref<typeof ElInput>();
 
-const searchValue = ref('')
+const searchValue = ref("");
 const handleSearch = () => {
-  console.log('搜索')
+  console.log("搜索");
 
   searchRef.value && searchRef.value.blur();
   searchCount.value = 0;
@@ -31,16 +31,15 @@ const handleSearch = () => {
   // currentIndex = -1;
   showSearchResult.value = true;
   // const searchKey = searchValue.value.toLowerCase();
-}
-
+};
 
 const preMatch = () => {
-  console.log('上一个')
-}
+  console.log("上一个");
+};
 
 const nextMatch = () => {
-  console.log('下一个')
-}
+  console.log("下一个");
+};
 
 const { getHotRef, notNull } = useHotRef();
 const hotRef = getHotRef();
@@ -48,8 +47,8 @@ const hotRef = getHotRef();
 // 重新渲染表格
 const Render = () => {
   hotRef.value && hotRef.value.Render();
-  console.log('std bill render')
-}
+  console.log("std bill render");
+};
 
 // const tableData = []
 
@@ -59,12 +58,12 @@ const Render = () => {
 // 显示或隐藏搜索结果栏,都重新 Render hot
 watch(showSearchResult, async () => {
   await nextTick();
-  Render()
+  Render();
 });
 
 defineExpose({
-  Render
-})
+  Render,
+});
 </script>
 
 <template>
@@ -72,7 +71,12 @@ defineExpose({
     <!-- 过滤栏 -->
     <div class="filter-bar">
       <el-select size="mini" style="width: 100%" v-model="libID">
-        <el-option v-for="item in options" :key="item.ID" :label="item.name" :value="item.ID" />
+        <el-option
+          v-for="item in options"
+          :key="item.ID"
+          :label="item.name"
+          :value="item.ID"
+        />
       </el-select>
       <el-input
         size="mini"
@@ -93,15 +97,21 @@ defineExpose({
     <div class="search-result-nav" v-show="showSearchResult">
       <p class="count">搜索结果: {{ searchCount }}</p>
       <el-button-group class="nav-button-group">
-        <el-button type="primary" size="mini" @click="preMatch">上一个</el-button>
-        <el-button type="primary" size="mini" @click="nextMatch">下一个</el-button>
+        <el-button type="primary" size="mini" @click="preMatch"
+          >上一个</el-button
+        >
+        <el-button type="primary" size="mini" @click="nextMatch"
+          >下一个</el-button
+        >
       </el-button-group>
       <i class="el-icon-close close-button" @click="showSearchResult = false" />
     </div>
     <!-- 表格区域 -->
     <div
       class="table-area"
-      :style="{ height: showSearchResult ? 'calc(100% - 68px)' : 'calc(100% - 36px)' }"
+      :style="{
+        height: showSearchResult ? 'calc(100% - 68px)' : 'calc(100% - 36px)',
+      }"
     >
       <!-- <handsontable :data="tableData" :settings="tableSettings" border="none" ref="hotRef" /> -->
       表格区域

+ 57 - 49
src/views/project/summary/components/subject-tree/SubjectTree.vue

@@ -2,9 +2,9 @@
 // import { ContextMenu } from "@/types/components";
 import { Subject } from "@/types/subject";
 import { ref, PropType, toRaw, onMounted, watch } from "vue";
-import { useRouter, useRoute } from 'vue-router'
-import { isUndefined } from 'lodash'
-import { SubjectStructure } from '@/constants/subject'
+import { useRouter, useRoute } from "vue-router";
+import { isUndefined } from "lodash";
+import { SubjectStructure } from "@/constants/subject";
 import useStructureRouter from "@/composables/useStructureRouter";
 
 const props = defineProps({
@@ -12,27 +12,27 @@ const props = defineProps({
     type: Array as PropType<Subject.ISubjectTreeNode[]>,
     required: true,
   },
-})
+});
 
-const router = useRouter()
-const route = useRoute()
+const router = useRouter();
+const route = useRoute();
 
 // 上下文菜单设置
 const menuGroup: ContextMenu.MenuGroup[] = [
   [
     {
-      text: '菜单项 1{%input[type=text][value=张三]%}行',
-      icon: 'dsk-home-two-add',
+      text: "菜单项 1{%input[type=text][value=张三]%}行",
+      icon: "dsk-home-two-add",
       disable() {
         return false;
       },
       callback(inputVal: any) {
-        console.log('回调', inputVal);
+        console.log("回调", inputVal);
       },
     },
     {
-      text: '菜单项 2',
-      icon: 'dsk-file-addition-one',
+      text: "菜单项 2",
+      icon: "dsk-file-addition-one",
       disable() {
         return Math.random() > 0.5;
       },
@@ -41,19 +41,19 @@ const menuGroup: ContextMenu.MenuGroup[] = [
       },
     },
     {
-      text: '菜单项 3{%input[type=number][value=1][min=1][max=4]%}列',
-      icon: 'dsk-edit',
+      text: "菜单项 3{%input[type=number][value=1][min=1][max=4]%}列",
+      icon: "dsk-edit",
       disable() {
         return false;
       },
       callback(inputVal: any) {
-        console.log('回调', inputVal);
+        console.log("回调", inputVal);
       },
     },
   ],
   [
     {
-      text: '菜单项 4',
+      text: "菜单项 4",
       hidden() {
         return Math.random() > 0.5;
       },
@@ -61,18 +61,18 @@ const menuGroup: ContextMenu.MenuGroup[] = [
         return false;
       },
       callback() {
-        console.log('callback');
+        console.log("callback");
       },
     },
     {
-      text: '菜单项 5',
+      text: "菜单项 5",
       disable() {
         return false;
       },
       submenu: [
         [
           {
-            text: '菜单项 1',
+            text: "菜单项 1",
             hidden() {
               return false;
             },
@@ -80,12 +80,12 @@ const menuGroup: ContextMenu.MenuGroup[] = [
               return false;
             },
             callback() {
-              console.log('callback');
+              console.log("callback");
             },
           },
           {
-            text: '菜单项 2',
-            icon: 'dsk-home-two-add',
+            text: "菜单项 2",
+            icon: "dsk-home-two-add",
             hidden() {
               return false;
             },
@@ -93,14 +93,14 @@ const menuGroup: ContextMenu.MenuGroup[] = [
               return false;
             },
             callback() {
-              console.log('callback');
+              console.log("callback");
             },
           },
         ],
         [
           {
-            text: '菜单项 3',
-            icon: 'dsk-home-two-add',
+            text: "菜单项 3",
+            icon: "dsk-home-two-add",
             hidden() {
               return false;
             },
@@ -108,11 +108,11 @@ const menuGroup: ContextMenu.MenuGroup[] = [
               return true;
             },
             callback() {
-              console.log('callback');
+              console.log("callback");
             },
           },
           {
-            text: '菜单项 4',
+            text: "菜单项 4",
             hidden() {
               return false;
             },
@@ -122,8 +122,8 @@ const menuGroup: ContextMenu.MenuGroup[] = [
             submenu: [
               [
                 {
-                  text: '菜单项 1',
-                  icon: 'dsk-home-two-add',
+                  text: "菜单项 1",
+                  icon: "dsk-home-two-add",
                   hidden() {
                     return false;
                   },
@@ -133,14 +133,14 @@ const menuGroup: ContextMenu.MenuGroup[] = [
                   submenu: [
                     [
                       {
-                        text: '菜单项 1',
-                        icon: 'dsk-home-two-add',
+                        text: "菜单项 1",
+                        icon: "dsk-home-two-add",
                         hidden() {
                           return false;
                         },
                         disable() {
                           return false;
-                        }
+                        },
                       },
                     ],
                   ],
@@ -154,16 +154,16 @@ const menuGroup: ContextMenu.MenuGroup[] = [
   ],
 ];
 
-const loading = ref(false)
+const loading = ref(false);
 
 // el-tree 的最外层 dom
 const $subjectTree = ref<HTMLElement | null>();
 onMounted(() => {
-  $subjectTree.value = document.getElementById('subject-tree');
+  $subjectTree.value = document.getElementById("subject-tree");
 });
 
 // 当前选中的节点
-const currentNodeKey = '1.1.1'
+const currentNodeKey = "1.1.1";
 
 // 点击某个节点的事件
 const handleNodeClick = (nodeData: Subject.ISubjectTreeNode) => {
@@ -172,16 +172,19 @@ const handleNodeClick = (nodeData: Subject.ISubjectTreeNode) => {
     $subjectTree.value.click();
   }
 
-  console.log('当前节点的值:', toRaw(nodeData))
-}
+  console.log("当前节点的值:", toRaw(nodeData));
+};
 
 // 右键点击某个节点的事件
-const handleNodeContextmenu = (event: MouseEvent, nodeData: Subject.ISubjectTreeNode) => {
-  console.log('右键事件对象:', event)
-  console.log('当前节点的值:', toRaw(nodeData))
+const handleNodeContextmenu = (
+  event: MouseEvent,
+  nodeData: Subject.ISubjectTreeNode
+) => {
+  console.log("右键事件对象:", event);
+  console.log("当前节点的值:", toRaw(nodeData));
 
   // 由于 el-tree 默认阻止 contextmenu 事件冒泡,所以此处重新派发一个事件
-  const contextmenuEvent = new MouseEvent('contextmenu', {
+  const contextmenuEvent = new MouseEvent("contextmenu", {
     bubbles: true,
     clientX: event.clientX,
     clientY: event.clientY,
@@ -189,14 +192,13 @@ const handleNodeContextmenu = (event: MouseEvent, nodeData: Subject.ISubjectTree
   if ($subjectTree.value) {
     $subjectTree.value.dispatchEvent(contextmenuEvent);
   }
-}
+};
 
-const structure = useStructureRouter()
+const structure = useStructureRouter();
 // 监听 structure 改变
-watch(structure, val => {
-  console.log('subject tree 结构', val)
-})
-
+watch(structure, (val) => {
+  console.log("subject tree 结构", val);
+});
 </script>
 
 <template>
@@ -206,12 +208,18 @@ watch(structure, val => {
         class="tab"
         :class="{ active: route.query.structure !== SubjectStructure.ARRANGE }"
         @click="router.push({ name: 'Summary' })"
-      >原始结构</li>
+      >
+        原始结构
+      </li>
       <li
         class="tab"
         :class="{ active: route.query.structure === SubjectStructure.ARRANGE }"
-        @click="router.push({ name: 'Summary', query: { structure: 'arrange' } })"
-      >整理结构</li>
+        @click="
+          router.push({ name: 'Summary', query: { structure: 'arrange' } })
+        "
+      >
+        整理结构
+      </li>
     </ul>
     <div class="tree-wrap">
       <context-menu :item-groups="menuGroup" ref="contextMenuRef" auto-size>

+ 41 - 33
src/views/project/summary/components/tool-bar/ToolBar.vue

@@ -1,60 +1,58 @@
 <script setup lang="ts">
 import { onMounted, reactive, ref, computed, watch } from "vue";
-import summaryLayoutStore from '@/store/modules/summaryLayout'
+import summaryLayoutStore from "@/store/modules/summaryLayout";
 import { Subject } from "@/types/subject";
 import useStructureRouter from "@/composables/useStructureRouter";
 
-const { setRightStdBillVisible, setRightLibRationVisible } = summaryLayoutStore
+const { setRightStdBillVisible, setRightLibRationVisible } = summaryLayoutStore;
 
 const rightStdBillVisible = computed({
   get: () => summaryLayoutStore.rightStdBillVisible,
-  set: val => setRightStdBillVisible(val),
+  set: (val) => setRightStdBillVisible(val),
 });
 
 const rightLibRationVisible = computed({
   get: () => summaryLayoutStore.rightLibRationVisible,
-  set: val => setRightLibRationVisible(val),
+  set: (val) => setRightLibRationVisible(val),
 });
 
-const collapseIconDisabled = computed(() => !rightStdBillVisible.value && !rightLibRationVisible.value)
+const collapseIconDisabled = computed(
+  () => !rightStdBillVisible.value && !rightLibRationVisible.value
+);
 
 const emit = defineEmits<{
-  (e: 'right-visible-change', needRender: boolean): void
-}>()
+  (e: "right-visible-change", needRender: boolean): void;
+}>();
 
 const handleStdBillClick = () => {
-  if (rightStdBillVisible.value)
-    return
-  emit('right-visible-change', collapseIconDisabled.value)
+  if (rightStdBillVisible.value) return;
+  emit("right-visible-change", collapseIconDisabled.value);
 
-  rightStdBillVisible.value = true
-  rightLibRationVisible.value = false
-}
+  rightStdBillVisible.value = true;
+  rightLibRationVisible.value = false;
+};
 
 const handleLibRationClick = () => {
-  if (rightLibRationVisible.value)
-    return
-  emit('right-visible-change', collapseIconDisabled.value)
+  if (rightLibRationVisible.value) return;
+  emit("right-visible-change", collapseIconDisabled.value);
 
-  rightLibRationVisible.value = true
-  rightStdBillVisible.value = false
-}
+  rightLibRationVisible.value = true;
+  rightStdBillVisible.value = false;
+};
 
 const hide = () => {
-  if (collapseIconDisabled.value)
-    return
-  emit('right-visible-change', true)
+  if (collapseIconDisabled.value) return;
+  emit("right-visible-change", true);
 
-  rightStdBillVisible.value = false
-  rightLibRationVisible.value = false
-}
+  rightStdBillVisible.value = false;
+  rightLibRationVisible.value = false;
+};
 
-const structure = useStructureRouter()
+const structure = useStructureRouter();
 // 监听 structure 改变
-watch(structure, val => {
-  console.log('tool bar 结构', val)
-})
-
+watch(structure, (val) => {
+  console.log("tool bar 结构", val);
+});
 </script>
 
 <template>
@@ -68,7 +66,9 @@ watch(structure, val => {
         </el-tooltip>
         <template #dropdown>
           <el-dropdown-menu>
-            <el-dropdown-item command="item1">这是一个非常非常非常长的菜单1</el-dropdown-item>
+            <el-dropdown-item command="item1"
+              >这是一个非常非常非常长的菜单1</el-dropdown-item
+            >
             <el-dropdown-item command="item2">这是菜单2</el-dropdown-item>
           </el-dropdown-menu>
         </template>
@@ -100,7 +100,11 @@ watch(structure, val => {
       </el-tooltip>
     </div>
     <div class="menus">
-      <span class="menu-item" :class="{ active: rightStdBillVisible }" @click="handleStdBillClick">
+      <span
+        class="menu-item"
+        :class="{ active: rightStdBillVisible }"
+        @click="handleStdBillClick"
+      >
         <i class="text">标准清单</i>
       </span>
       <span
@@ -110,7 +114,11 @@ watch(structure, val => {
       >
         <i class="text">定额库</i>
       </span>
-      <span class="menu-item" @click="hide" :class="{ disabled: collapseIconDisabled }">
+      <span
+        class="menu-item"
+        @click="hide"
+        :class="{ disabled: collapseIconDisabled }"
+      >
         <iconfont class="icon dsk-menu-unfold" />
       </span>
     </div>

+ 3 - 0
src/views/project/summary/components/tool-bar/style.scss

@@ -57,12 +57,15 @@
           border-bottom: none;
           background-color: #f5f7f9;
         }
+
         color: #409eff;
       }
+
       &.disabled {
         color: #ccc;
         cursor: not-allowed
       }
+
       .text {
         @apply relative;
         z-index: 1;

+ 121 - 121
src/views/project/summary/scripts/useSummaryLayout.ts

@@ -1,127 +1,127 @@
 import { ref, computed } from "vue";
-import summaryLayoutStore from '@/store/modules/summaryLayout'
+import summaryLayoutStore from "@/store/modules/summaryLayout";
 
 type NeedRenderComponent = Common.IRender;
 
 // 布局相关代码
 export default function useSummaryLayout() {
-    const {
-        setSubjectTreeSize,
-        setMainContentSize,
-        setMainLeftSize,
-        setMainRightSize,
-        setMainLeftTopSize,
-        setMainLeftBottomSize,
-        setRightStdBillVisible,
-        setRightLibRationVisible
-    } = summaryLayoutStore
-
-    const subjectTreeSize = computed({
-        get: () => summaryLayoutStore.subjectTreeSize,
-        set: val => setSubjectTreeSize(val),
-    });
-
-    const mainContentSize = computed({
-        get: () => summaryLayoutStore.mainContentSize,
-        set: val => setMainContentSize(val),
-    });
-
-    const mainLeftSize = computed({
-        get: () => summaryLayoutStore.mainLeftSize,
-        set: val => setMainLeftSize(val),
-    });
-
-    const mainRightSize = computed({
-        get: () => summaryLayoutStore.mainRightSize,
-        set: val => setMainRightSize(val),
-    });
-
-    const mainLeftTopSize = computed({
-        get: () => summaryLayoutStore.mainLeftTopSize,
-        set: val => setMainLeftTopSize(val),
-    });
-
-    const mainLeftBottomSize = computed({
-        get: () => summaryLayoutStore.mainLeftBottomSize,
-        set: val => setMainLeftBottomSize(val),
-    });
-
-    const rightStdBillVisible = computed({
-        get: () => summaryLayoutStore.rightStdBillVisible,
-        set: val => setRightStdBillVisible(val),
-    });
-
-    const rightLibRationVisible = computed({
-        get: () => summaryLayoutStore.rightLibRationVisible,
-        set: val => setRightLibRationVisible(val),
-    });
-
-    const costTableRef = ref<NeedRenderComponent>()
-    const bottomTabsRef = ref<NeedRenderComponent>()
-    const stdBillRef = ref<NeedRenderComponent>()
-    const libRationRef = ref<NeedRenderComponent>()
-
-    const handleSubjectTreeSize = (size: number) => {
-        subjectTreeSize.value = size
-    }
-
-    const handleMainContentSize = (size: number) => {
-        mainContentSize.value = size
-
-        // 重新 render 各个子组件
-        costTableRef.value && costTableRef.value.Render()
-        bottomTabsRef.value && bottomTabsRef.value.Render()
-        stdBillRef.value && stdBillRef.value.Render()
-        libRationRef.value && libRationRef.value.Render()
-    }
-
-    const handleMainLeftSize = (size: number) => {
-        mainLeftSize.value = size
-
-        // 重新 render 各个子组件
-        costTableRef.value && costTableRef.value.Render()
-        bottomTabsRef.value && bottomTabsRef.value.Render()
-    }
-
-    const handleMainRightSize = (size: number) => {
-        mainRightSize.value = size
-
-        stdBillRef.value && stdBillRef.value.Render()
-        libRationRef.value && libRationRef.value.Render()
-    }
-
-    const handleMainLeftTopSize = (size: number) => {
-        mainLeftTopSize.value = size
-
-        costTableRef.value && costTableRef.value.Render()
-    }
-
-    const handleMainLeftBottomSize = (size: number) => {
-        mainLeftBottomSize.value = size
-
-        bottomTabsRef.value && bottomTabsRef.value.Render()
-    }
-
-    return {
-        subjectTreeSize,
-        mainContentSize,
-        mainLeftSize,
-        mainRightSize,
-        mainLeftTopSize,
-        mainLeftBottomSize,
-        rightStdBillVisible,
-        rightLibRationVisible,
-
-        costTableRef,
-        bottomTabsRef,
-        stdBillRef,
-        libRationRef,
-
-        handleSubjectTreeSize,
-        handleMainContentSize,
-        handleMainLeftSize,
-        handleMainRightSize,
-        handleMainLeftTopSize,
-        handleMainLeftBottomSize,
-    }
-}
+  const {
+    setSubjectTreeSize,
+    setMainContentSize,
+    setMainLeftSize,
+    setMainRightSize,
+    setMainLeftTopSize,
+    setMainLeftBottomSize,
+    setRightStdBillVisible,
+    setRightLibRationVisible,
+  } = summaryLayoutStore;
+
+  const subjectTreeSize = computed({
+    get: () => summaryLayoutStore.subjectTreeSize,
+    set: (val) => setSubjectTreeSize(val),
+  });
+
+  const mainContentSize = computed({
+    get: () => summaryLayoutStore.mainContentSize,
+    set: (val) => setMainContentSize(val),
+  });
+
+  const mainLeftSize = computed({
+    get: () => summaryLayoutStore.mainLeftSize,
+    set: (val) => setMainLeftSize(val),
+  });
+
+  const mainRightSize = computed({
+    get: () => summaryLayoutStore.mainRightSize,
+    set: (val) => setMainRightSize(val),
+  });
+
+  const mainLeftTopSize = computed({
+    get: () => summaryLayoutStore.mainLeftTopSize,
+    set: (val) => setMainLeftTopSize(val),
+  });
+
+  const mainLeftBottomSize = computed({
+    get: () => summaryLayoutStore.mainLeftBottomSize,
+    set: (val) => setMainLeftBottomSize(val),
+  });
+
+  const rightStdBillVisible = computed({
+    get: () => summaryLayoutStore.rightStdBillVisible,
+    set: (val) => setRightStdBillVisible(val),
+  });
+
+  const rightLibRationVisible = computed({
+    get: () => summaryLayoutStore.rightLibRationVisible,
+    set: (val) => setRightLibRationVisible(val),
+  });
+
+  const costTableRef = ref<NeedRenderComponent>();
+  const bottomTabsRef = ref<NeedRenderComponent>();
+  const stdBillRef = ref<NeedRenderComponent>();
+  const libRationRef = ref<NeedRenderComponent>();
+
+  const handleSubjectTreeSize = (size: number) => {
+    subjectTreeSize.value = size;
+  };
+
+  const handleMainContentSize = (size: number) => {
+    mainContentSize.value = size;
+
+    // 重新 render 各个子组件
+    costTableRef.value && costTableRef.value.Render();
+    bottomTabsRef.value && bottomTabsRef.value.Render();
+    stdBillRef.value && stdBillRef.value.Render();
+    libRationRef.value && libRationRef.value.Render();
+  };
+
+  const handleMainLeftSize = (size: number) => {
+    mainLeftSize.value = size;
+
+    // 重新 render 各个子组件
+    costTableRef.value && costTableRef.value.Render();
+    bottomTabsRef.value && bottomTabsRef.value.Render();
+  };
+
+  const handleMainRightSize = (size: number) => {
+    mainRightSize.value = size;
+
+    stdBillRef.value && stdBillRef.value.Render();
+    libRationRef.value && libRationRef.value.Render();
+  };
+
+  const handleMainLeftTopSize = (size: number) => {
+    mainLeftTopSize.value = size;
+
+    costTableRef.value && costTableRef.value.Render();
+  };
+
+  const handleMainLeftBottomSize = (size: number) => {
+    mainLeftBottomSize.value = size;
+
+    bottomTabsRef.value && bottomTabsRef.value.Render();
+  };
+
+  return {
+    subjectTreeSize,
+    mainContentSize,
+    mainLeftSize,
+    mainRightSize,
+    mainLeftTopSize,
+    mainLeftBottomSize,
+    rightStdBillVisible,
+    rightLibRationVisible,
+
+    costTableRef,
+    bottomTabsRef,
+    stdBillRef,
+    libRationRef,
+
+    handleSubjectTreeSize,
+    handleMainContentSize,
+    handleMainLeftSize,
+    handleMainRightSize,
+    handleMainLeftTopSize,
+    handleMainLeftBottomSize,
+  };
+}

+ 40 - 18
src/views/workbench/Workbench.vue

@@ -1,20 +1,20 @@
 <script setup lang="ts">
 import { onMounted, reactive, ref } from "vue";
-import getPath, { post } from '@/apis/controller/index';
-import breadcrumbStore from '@/store/modules/breadcrumb'
+import getPath, { post } from "@/apis/controller/index";
+import breadcrumbStore from "@/store/modules/breadcrumb";
 
 const handleClick = async () => {
-  console.log(await getPath())
-  console.log('----')
-  console.log(await post('1'))
-}
+  console.log(await getPath());
+  console.log("----");
+  console.log(await post("1"));
+};
 
-const { setBreadcrumb } = breadcrumbStore
+const { setBreadcrumb } = breadcrumbStore;
 setBreadcrumb([
   {
-    label: '工作台',
-  }
-])
+    label: "工作台",
+  },
+]);
 </script>
 
 <template>
@@ -60,7 +60,9 @@ setBreadcrumb([
                 <img src="@/assets/project-icon.svg" alt class="icon" />
                 我的项目
               </span>
-              <router-link class="link" to="/project-list">全部项目</router-link>
+              <router-link class="link" to="/project-list"
+                >全部项目</router-link
+              >
             </div>
           </template>
           <div class="card-body">
@@ -92,7 +94,9 @@ setBreadcrumb([
                   <p class="content">
                     <strong class="name">李四</strong>
                     <span class="do">编辑了</span>
-                    <router-link to="/project" class="link">市妇幼保健医院道路工程</router-link>
+                    <router-link to="/project" class="link"
+                      >市妇幼保健医院道路工程</router-link
+                    >
                   </p>
                   <time class="time">2019-06-01 11:35:20</time>
                 </div>
@@ -115,27 +119,45 @@ setBreadcrumb([
           <div class="card-body">
             <ul class="list">
               <li class="item">
-                <iconfont class="icon dsk-dashboard-one" style="color: rgb(82, 196, 26)" />
+                <iconfont
+                  class="icon dsk-dashboard-one"
+                  style="color: rgb(82, 196, 26)"
+                />
                 <span class="text">主控台</span>
               </li>
               <li class="item">
-                <iconfont class="icon dsk-me" style="color: rgb(24, 144, 255)" />
+                <iconfont
+                  class="icon dsk-me"
+                  style="color: rgb(24, 144, 255)"
+                />
                 <span class="text">个人中心</span>
               </li>
               <li class="item">
-                <iconfont class="icon dsk-config" style="color: rgb(250, 173, 20)" />
+                <iconfont
+                  class="icon dsk-config"
+                  style="color: rgb(250, 173, 20)"
+                />
                 <span class="text">设置</span>
               </li>
               <li class="item">
-                <iconfont class="icon dsk-robot-two" style="color: rgb(114, 46, 209)" />
+                <iconfont
+                  class="icon dsk-robot-two"
+                  style="color: rgb(114, 46, 209)"
+                />
                 <span class="text">定额库</span>
               </li>
               <li class="item">
-                <iconfont class="icon dsk-doc-detail" style="color: rgb(19, 194, 194)" />
+                <iconfont
+                  class="icon dsk-doc-detail"
+                  style="color: rgb(19, 194, 194)"
+                />
                 <span class="text">消息</span>
               </li>
               <li class="item">
-                <iconfont class="icon dsk-search" style="color: rgb(235, 47, 150)" />
+                <iconfont
+                  class="icon dsk-search"
+                  style="color: rgb(235, 47, 150)"
+                />
                 <span class="text">搜索</span>
               </li>
             </ul>

+ 17 - 20
vite.config.ts

@@ -1,28 +1,25 @@
-import { defineConfig } from 'vite';
-import vue from '@vitejs/plugin-vue'
-import hooks from '@midwayjs/vite-plugin-hooks';
+import { defineConfig } from "vite";
+import vue from "@vitejs/plugin-vue";
+import hooks from "@midwayjs/vite-plugin-hooks";
 
-const { resolve } = require('path')
+const { resolve } = require("path");
 
 // https://vitejs.dev/config/
 export default defineConfig({
-    plugins: [
-        hooks(),
-        vue(),
-    ],
-    resolve: {
-        alias: {
-            '@': resolve(__dirname, 'src'),
-        }
+  plugins: [hooks(), vue()],
+  resolve: {
+    alias: {
+      "@": resolve(__dirname, "src"),
     },
-    css: {
-        preprocessorOptions: {
-            scss: {
-                additionalData: `
+  },
+  css: {
+    preprocessorOptions: {
+      scss: {
+        additionalData: `
                 @import "@/styles/_variables.scss";
                 @import "@/styles/_mixin.scss";
-                `
-            }
-        }
-    }
+                `,
+      },
+    },
+  },
 });