Browse Source

更新框架

caner 1 year ago
parent
commit
f5525590b0
75 changed files with 1428 additions and 898 deletions
  1. 2 1
      .env.production
  2. 0 4
      .eslintignore
  3. 0 60
      .eslintrc.cjs
  4. 92 0
      .eslintrc.json
  5. 3 2
      .gitignore
  6. 78 9
      README.md
  7. 1 2
      index.html
  8. 22 21
      package.json
  9. BIN
      public/Dog出游 3.0.1.ipa
  10. 6 0
      src/assets/icons/add.svg
  11. 46 0
      src/assets/naive-theme.ts
  12. 25 0
      src/assets/native-plugin.ts
  13. 27 0
      src/components/icon.vue
  14. 1 2
      src/components/loading.vue
  15. 15 2
      src/pages/App.vue
  16. 39 7
      src/pages/main.ts
  17. 27 8
      src/pages/store/index.ts
  18. 2 2
      src/pages/views/chart/index.vue
  19. BIN
      src/pages/views/draw/img/0.png
  20. BIN
      src/pages/views/draw/img/1-1.png
  21. BIN
      src/pages/views/draw/img/1-2.png
  22. BIN
      src/pages/views/draw/img/1-3.png
  23. BIN
      src/pages/views/draw/img/1.png
  24. BIN
      src/pages/views/draw/img/10.png
  25. BIN
      src/pages/views/draw/img/11.png
  26. BIN
      src/pages/views/draw/img/12.png
  27. BIN
      src/pages/views/draw/img/13.png
  28. BIN
      src/pages/views/draw/img/14.png
  29. BIN
      src/pages/views/draw/img/15.png
  30. BIN
      src/pages/views/draw/img/16.png
  31. BIN
      src/pages/views/draw/img/17.png
  32. BIN
      src/pages/views/draw/img/18.png
  33. BIN
      src/pages/views/draw/img/19.png
  34. BIN
      src/pages/views/draw/img/2.png
  35. BIN
      src/pages/views/draw/img/20.png
  36. BIN
      src/pages/views/draw/img/21.png
  37. BIN
      src/pages/views/draw/img/22.png
  38. BIN
      src/pages/views/draw/img/3.png
  39. BIN
      src/pages/views/draw/img/4.png
  40. BIN
      src/pages/views/draw/img/5.png
  41. BIN
      src/pages/views/draw/img/6.png
  42. BIN
      src/pages/views/draw/img/7.png
  43. BIN
      src/pages/views/draw/img/8.png
  44. BIN
      src/pages/views/draw/img/9.png
  45. 277 0
      src/pages/views/draw/index.vue
  46. 17 0
      src/pages/views/draw/js/NativePlugin.ts
  47. 111 0
      src/pages/views/draw/js/draw.js
  48. 3 2
      src/pages/views/draw/route.ts
  49. 3 1
      src/pages/views/edit/component/editeDemo.vue
  50. 3 3
      src/pages/views/edit/index.vue
  51. 4 2
      src/pages/views/edit/js/registerMenu.ts
  52. 7 7
      src/pages/views/fly/components/FlyMoitor.vue
  53. 1 1
      src/pages/views/fly/index.vue
  54. 3 3
      src/pages/views/home/index.vue
  55. 0 0
      src/pages/views/home/js/Painter.js
  56. 0 0
      src/pages/views/home/js/Recorder.js
  57. 0 0
      src/pages/views/home/route.ts
  58. BIN
      src/pages/views/move/assets/1.png
  59. 0 71
      src/pages/views/move/index.vue
  60. 0 146
      src/pages/views/news/index.vue
  61. 42 46
      src/pages/views/planTool/index.vue
  62. 0 0
      src/pages/views/planTool/js/openseadragon-svg-overlay.js
  63. 3 0
      src/pages/views/test/index.vue
  64. 3 2
      src/pages/views/test/route.ts
  65. 167 0
      src/services/exportFile.ts
  66. 87 0
      src/services/laglat2gauss.ts
  67. 121 0
      src/services/net.service.ts
  68. 40 0
      src/services/registerMenu.ts
  69. 64 0
      src/services/service.ts
  70. 0 20
      src/utils/axios.js
  71. 0 143
      src/utils/html2File.ts
  72. 0 277
      src/utils/move.js
  73. 6 4
      src/vite-env.d.ts
  74. 8 2
      tsconfig.json
  75. 72 48
      vite.config.ts

+ 2 - 1
.env.production

@@ -1 +1,2 @@
-VITE_SOCKET_URL=wss://caner.top
+VITE_SOCKET_URL=wss://caner.top
+VITE_PROXY_URL=''

+ 0 - 4
.eslintignore

@@ -1,4 +0,0 @@
-# 排除eslint检查文件
-/src/utils
-/dist
-/public

+ 0 - 60
.eslintrc.cjs

@@ -1,60 +0,0 @@
-module.exports = {
-  root: true,
-  env: {
-    node: true,
-    browser: true,
-    es2021: true
-  },
-  parserOptions: {
-    ecmaVersion: "latest",
-    parser: '@typescript-eslint/parser',
-    sourceType: "module"
-  },
-  extends: [
-    'plugin:vue/vue3-recommended',
-    'airbnb-base'
-  ],
-  rules: {
-    'no-console': 0, // 禁用打印
-    'comma-dangle': [2, 'never'], // 禁止使用拖尾逗号
-    'no-extra-semi': 2, // 禁止不必要的分号
-    'array-bracket-spacing': [2, 'always'], // 指定数组的元素之间要以空格隔开
-    'jsx-quotes': 0, // 强制使用单引号
-    'max-len': 0, // 强制一行的最大长度
-    semi: [2, 'never'], // 禁止使用分号
-    'no-unused-vars': 2,
-    "no-unneeded-ternary": 2,//禁止不必要的嵌套 var isYes = answer === 1 ? true : false;
-    "no-unreachable": 2,//不能有无法执行的代码
-    "no-unused-expressions": 1,//禁止无用的表达式    
-    'linebreak-style': [0, 'error', 'windows'],
-    'import/no-unresolved': 0,
-    'import/extensions': 0,
-    'import/no-absolute-path': 0,
-    'import/no-extraneous-dependencies': 0,
-    'class-methods-use-this': 0,
-    'no-mixed-operators': 0,
-    'eol-last': 0,
-    'import/newline-after-import': 0,
-    'vue/multi-word-component-names': 0,
-    'no-param-reassign': 0,
-    'no-restricted-syntax': 0,
-    'no-underscore-dangle': 0,
-    'no-plusplus': 0,
-    'no-bitwise': 0,
-    'guard-for-in': 0,
-    'func-names': 0,
-    'import/order': 0,
-    'vue/no-deprecated-slot-attribute': 0,
-    'vue/v-on-event-hyphenation': 0,
-    'vue/no-deprecated-filter': 0,
-    'vue/require-explicit-emits': 0,
-    'vue/no-v-html': 0,
-    'vue/order-in-components': 0,
-    'vue/no-reserved-component-names': 0,
-    'no-promise-executor-return': 0,
-    'no-sparse-arrays': 0,
-    'no-nested-ternary': 0,
-    'no-continue': 0,
-    'prefer-destructuring': 0
-  }
-}

+ 92 - 0
.eslintrc.json

@@ -0,0 +1,92 @@
+{
+  "root": true,
+  "env": {
+    "node": true,
+    "browser": true,
+    "es2021": true
+  },
+  "parserOptions": {
+    "ecmaVersion": "latest",
+    "parser": "@typescript-eslint/parser",
+    "sourceType": "module"
+  },
+  "extends": [
+    "plugin:vue/vue3-recommended",
+    "airbnb-base"
+  ],
+  "rules": {
+    "import/prefer-default-export": "off",
+    "no-use-before-define": "off",
+    "no-console": 0, // 禁用打印
+    "comma-dangle": [
+      2,
+      "never"
+    ], // 禁止使用拖尾逗号
+    "no-extra-semi": 2, // 禁止不必要的分号
+    "array-bracket-spacing": [
+      2,
+      "always"
+    ], // 指定数组的元素之间要以空格隔开
+    "jsx-quotes": 0, // 强制使用单引号
+    "max-len": 0, // 强制一行的最大长度
+    "semi": [
+      2,
+      "never"
+    ], // 禁止使用分号
+    "no-unused-vars": 0,
+    "no-unneeded-ternary": 2, // 禁止不必要的嵌套 var isYes = answer === 1 ? true : false;
+    "no-unreachable": 2, // 不能有无法执行的代码
+    "no-unused-expressions": 1, // 禁止无用的表达式
+    "linebreak-style": [
+      0,
+      "error",
+      "windows"
+    ],
+    "import/no-unresolved": 0,
+    "import/extensions": 0,
+    "import/no-absolute-path": 0,
+    "import/no-extraneous-dependencies": [
+      "error",
+      {
+        "devDependencies": true
+      }
+    ],
+    "class-methods-use-this": 0,
+    "no-mixed-operators": 0,
+    "eol-last": 0,
+    "import/newline-after-import": 0,
+    "vue/multi-word-component-names": 0,
+    "no-param-reassign": 0,
+    "no-restricted-syntax": 0,
+    "no-underscore-dangle": 0,
+    "no-plusplus": 0,
+    "no-bitwise": 0,
+    "guard-for-in": 0,
+    "func-names": 0,
+    "import/order": 0,
+    "vue/no-deprecated-slot-attribute": 0,
+    "vue/v-on-event-hyphenation": 0,
+    "vue/no-deprecated-filter": 0,
+    "vue/require-explicit-emits": 0,
+    "vue/no-v-html": 0,
+    "vue/order-in-components": 0,
+    "vue/no-reserved-component-names": 0,
+    "no-promise-executor-return": 0,
+    "no-sparse-arrays": 0,
+    "no-nested-ternary": 0,
+    "no-continue": 0,
+    "complexity": 0,
+    "no-return-await": 0,
+    "max-classes-per-file": 0,
+    "consistent-return": 0,
+    "no-shadow": 0,
+    "no-undef": 0,
+    "no-throw-literal": 0,
+    "no-loss-of-precision": 0,
+    "no-prototype-builtins": 0,
+    "no-fallthrough": 0,
+    "no-case-declarations": 0,
+    "no-cond-assign": 0,
+    "prefer-destructuring": 1
+  }
+}

+ 3 - 2
.gitignore

@@ -27,7 +27,8 @@ build/Release
 # Dependency directory
 # Dependency directory
 # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
 # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
 node_modules
 node_modules
-.env.development
 dist
 dist
+.env.development
+.DS_Store
+package-lock.json
 *.lock
 *.lock
-*.DS*

+ 78 - 9
README.md

@@ -1,11 +1,80 @@
-# Blog
+## 目录结构
+```
+| - `src`
+|   - `pages`                     入口目录
+|           - `assets`            静态文件
+|           - `components`        组件
+|           - `store`             存储
+|           - `views`             页面
+|           - `service`           服务
+|           - `App.vue`           模板
+|           - `main.ts`           入口文件
+|   - `components`                全局组件
+|   - `services`                  全局服务
+|   - `assets`                    全局静态文件
+```
+## 编写规范
+```
+import { onMounted, ref, computed} from 'vue'
+<script setup>
+    <!-- 函数new区  -->
+    const test = new DataServer()
+
+    <!-- data 声明区 -->
+    const test=ref(1)
+    const test1:computed(()=>test)
 
 
+    <!-- fn 声明区 -->
+    function name(){
+      console.log(123)
+    }
+    test().then(res=>{})
+
+    <!-- vue 方法区 -->
+    onMounted(() => {test()})
+
+</script>
+<template></template>
+<style></style>
 ```
 ```
-1. '/' 多人画板
-2. '/chart' echart 码数表
-3. '/edit' 富文本编辑
-4. '/fly' 二维动态导向
-5. '/move' 移动组件
-6. '/news' 实时新闻
-7. '/plantool' 平面图缩放
-```
+### TS
+* 不允许的操作
+  * `any` 类型
+  * `JSON.parse` 等危险操作时不嵌套异常处理
+  * 单个文件中的脚本代码总行数不允许超过`1024`行
+* 命名
+  * 文件 小写字母命名,多个词之间以 `-`连接,不允许大写字母及驼峰式
+  * 变量
+    * 小写字母开头的驼峰式,如 `userName`
+    * 必须使用英文单词或有意义的拼音
+    * 单字符变量名只允许在循环、循环回调中使用,可使用 `i,j,k,m,n,t,v`等
+  * 函数
+    * 小写字母开头的驼峰式,如 `shouUserName`
+    * `.service.ts` 文件中方法命名建议:
+      * 集合类数据获取采用 `loadUsers` 之类的命名,即以 `load`开头并以获取数据名结尾
+      * 单个数据获取采用 `fetchTemplate` 之类的命名,以`fetch`开头并以数据名结尾
+      * 保存数据采用 `saveFlow` 之类的命名
+      * 删除数据采用 `removeTemplate` 之类的命名
+  * 类及类型
+    * 大写字母开头的驼峰式,如 `UserService`
+    * 私有变量以下划线接小写字母开头的驼峰式,如 `_innerType`
+  * 全局常量,下划线连接大写字母,如 `GROUP_TYPES`
+* 类型及注释
+  * 注释写法分以下几类
+  /** 这种用于简单描述函数作用 或 类成员变量用处 */
+  // 这种用于描述函数内变量或代码段作用
+  /**
+   * 这种用于描述类、复杂函数用途及参数等
+   */
+* 函数调用
+  * async 在没有其它函数调用的情况下,写成.then
+
+### CSS
+* 不允许使用无封装或不唯一的全局类样式,必须使用时需备注说明并慎重选择类名
+* 颜色赋值使用 `var(--color-a)` 写法,无特殊说明不允许直接赋值
+* `class, id` 命名必须使用短线连接单词方式,如 `form-label`, `list-item-title` 等
+* 多层级类名嵌套时,必须使用`scss`嵌套写法,以免污染其他样式
+
+### Notice
+* 框架使用解构,注入方式
+* 自行增加.env.development 测试环境变量

+ 1 - 2
index.html

@@ -2,9 +2,8 @@
 <html lang="en">
 <html lang="en">
   <head>
   <head>
     <meta charset="UTF-8" />
     <meta charset="UTF-8" />
-    <link rel="icon" href="/favicon.ico" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>Interesting</title>
+    <title>home</title>
   </head>
   </head>
   <body>
   <body>
     <div id="app"></div>
     <div id="app"></div>

+ 22 - 21
package.json

@@ -1,5 +1,5 @@
 {
 {
-  "name": "vite-project",
+  "name": "vite-vue3-ts-template",
   "private": true,
   "private": true,
   "version": "0.0.0",
   "version": "0.0.0",
   "type": "module",
   "type": "module",
@@ -11,31 +11,32 @@
   "dependencies": {
   "dependencies": {
     "@wangeditor/editor": "^5.1.18",
     "@wangeditor/editor": "^5.1.18",
     "@wangeditor/editor-for-vue": "^5.1.12",
     "@wangeditor/editor-for-vue": "^5.1.12",
-    "axios": "^1.2.2",
-    "echarts": "^5.4.1",
+    "echarts": "^5.5.1",
     "html2canvas": "^1.4.1",
     "html2canvas": "^1.4.1",
-    "image-size": "^1.0.1",
     "jspdf": "^2.5.1",
     "jspdf": "^2.5.1",
-    "openseadragon": "^4.0.0",
-    "pinia": "^2.0.18",
-    "socket.io-client": "^4.5.4",
-    "view-ui-plus": "^1.2.0",
-    "vue": "^3.2.37",
-    "vue-router": "^4.1.3"
+    "naive-ui": "^2.38.2",
+    "openseadragon": "^4.1.1",
+    "pinia": "^2.1.7",
+    "pinia-plugin-persist": "^1.0.0",
+    "socket.io-client": "^4.7.5",
+    "vue": "^3.4.31",
+    "vue-router": "^4.4.0",
+    "xlsx": "^0.18.5"
   },
   },
   "devDependencies": {
   "devDependencies": {
-    "@types/node": "^18.11.18",
-    "@typescript-eslint/parser": "^5.40.0",
-    "@vitejs/plugin-vue": "^3.1.2",
-    "eslint": "^8.25.0",
+    "@types/node": "^20.10.4",
+    "@typescript-eslint/parser": "^7.16.0",
+    "@vitejs/plugin-vue": "^5.0.5",
+    "eslint": "^8.57.0",
     "eslint-config-airbnb-base": "^15.0.0",
     "eslint-config-airbnb-base": "^15.0.0",
-    "eslint-plugin-import": "^2.26.0",
-    "eslint-plugin-vue": "^9.6.0",
-    "less": "^4.1.3",
-    "typescript": "^4.8.4",
-    "vite": "^3.1.8",
+    "eslint-plugin-import": "^2.29.1",
+    "eslint-plugin-vue": "^9.27.0",
+    "sass": "^1.77.8",
+    "typescript": "^5.5.3",
+    "vite": "^5.3.3",
     "vite-plugin-compression": "^0.5.1",
     "vite-plugin-compression": "^0.5.1",
-    "vite-plugin-eslint": "^1.8.0",
-    "vue-tsc": "^1.0.8"
+    "vite-plugin-eslint": "^1.8.1",
+    "vite-plugin-svg-icons": "^2.0.1",
+    "vue-tsc": "^2.0.26"
   }
   }
 }
 }

BIN
public/Dog出游 3.0.1.ipa


+ 6 - 0
src/assets/icons/add.svg

@@ -0,0 +1,6 @@
+<svg t="1699277626262" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5500"
+  width="200" height="200">
+  <path
+    d="M939.939489 459.072557 562.339502 459.072557 562.339502 83.519182 462.055494 83.519182 462.055494 459.072557 84.455507 459.072557 84.455507 559.356564 462.055494 559.356564 462.055494 939.003164 562.339502 939.003164 562.339502 559.356564 939.939489 559.356564Z"
+    fill="#1AB99B" p-id="5501"></path>
+</svg>

+ 46 - 0
src/assets/naive-theme.ts

@@ -0,0 +1,46 @@
+import { GlobalThemeOverrides } from 'naive-ui'
+const themeOverrides: GlobalThemeOverrides = {
+  common: {
+    primaryColor: '#2791FEFF',
+    primaryColorHover: '#67B2FEFF',
+    primaryColorPressed: '#1F74CBFF',
+    primaryColorSuppl: '#93C8FEFF',
+    errorColorHover: '#EC787BFF',
+    errorColor: '#E8575AFF',
+    errorColorPressed: '#B94548FF',
+    errorColorSuppl: '#EE898BFF',
+    warningColor: '#FAAD38FF',
+    warningColorPressed: '#C88A2CFF',
+    textColorBase: '#17233EFF',
+    textColor1: 'rgba(80, 90, 110, 1)',
+    textColor2: 'rgba(128, 134, 148, 1)',
+    textColor3: 'rgba(196, 200, 206, 1)',
+    placeholderColor: 'rgba(196, 200, 206, 1)',
+    iconColor: 'rgba(196, 200, 206, 1)',
+    iconColorHover: 'rgba(103, 178, 254, 1)',
+    iconColorPressed: 'rgba(31, 116, 203, 1)',
+    iconColorDisabled: 'rgba(196, 200, 206, 1)',
+    dividerColor: 'rgba(220, 222, 226, 1)',
+    borderColor: 'rgba(196, 200, 206, 1)',
+    closeIconColor: 'rgba(80, 90, 110, 1)',
+    closeIconColorHover: 'rgba(103, 178, 254, 1)',
+    closeIconColorPressed: 'rgba(31, 116, 203, 1)',
+    closeColorHover: 'rgba(0, 0, 0, 0.1)',
+    closeColorPressed: 'rgba(0, 0, 0, 0.15)',
+    scrollbarColor: 'rgba(126, 133, 160, 1)',
+    scrollbarColorHover: 'rgba(103, 178, 254, 1)',
+    tagColor: '#F5F5F5FF',
+    inputColorDisabled: 'rgba(233, 234, 236, 1)',
+    fontSize: '14px',
+    fontSizeMini: '12px',
+    fontSizeTiny: '12px',
+    fontSizeSmall: '14px',
+    fontSizeMedium: '14px',
+    fontSizeLarge: '15px',
+    fontSizeHuge: '16px'
+  },
+  Icon: {
+    color: 'white'
+  }
+}
+export default themeOverrides

+ 25 - 0
src/assets/native-plugin.ts

@@ -0,0 +1,25 @@
+import {
+  create,
+  NConfigProvider,
+  NNotificationProvider,
+  NButton,
+  NInputGroup,
+  NInputGroupLabel,
+  NInput,
+  NInputNumber
+} from 'naive-ui'
+
+const naive = create({
+  components: [
+    NConfigProvider,
+    NNotificationProvider,
+    NButton,
+    NInputGroup,
+    NInput,
+    NInputGroupLabel,
+    NInputNumber
+
+  ]
+})
+
+export default naive

+ 27 - 0
src/components/icon.vue

@@ -0,0 +1,27 @@
+<script setup lang="ts">
+import { computed } from 'vue'
+
+const props = defineProps<{
+  name: string,
+  size?: number,
+  color?: string
+}>()
+const symbolId = computed(() => `#icon-${props.name}`)
+const newColor = computed(() => `${props.color ?? '#ccc'}`)
+const newSize = computed(() => `${props.size ?? 16}`)
+</script>
+<template>
+  <svg
+    aria-hidden="true"
+    :font-size="newSize"
+    :width="newSize"
+    :height="newSize"
+  >
+
+    <use
+      :href="symbolId"
+      :fill="newColor"
+      :fill-rule="undefined"
+    />
+  </svg>
+</template>

+ 1 - 2
src/components/loading.vue

@@ -3,7 +3,7 @@
     <div class="loader" />
     <div class="loader" />
   </div>
   </div>
 </template>
 </template>
-<style lang="less" scoped>
+<style lang="scss" scoped>
     .bg{
     .bg{
         width: 100vw;
         width: 100vw;
         height: 100vh;
         height: 100vh;
@@ -14,7 +14,6 @@
         align-items: center;
         align-items: center;
         justify-content: center;
         justify-content: center;
         background: rgba(0, 0, 0, 0.5);
         background: rgba(0, 0, 0, 0.5);
-        z-index: 999999;
     }
     }
     .loader {
     .loader {
 
 

+ 15 - 2
src/pages/App.vue

@@ -1,14 +1,27 @@
 <template>
 <template>
   <loading v-if="show" />
   <loading v-if="show" />
-  <router-view />
+  <n-config-provider
+    preflight-style-disabled
+    inline-theme-disabled
+    :theme-overrides="themeOverrides"
+    :locale="zhCN"
+    :date-locale="dateZhCN"
+  >
+    <n-notification-provider>
+      <router-view />
+    </n-notification-provider>
+  </n-config-provider>
 </template>
 </template>
 <script setup lang='ts'>
 <script setup lang='ts'>
 import loading from '@/components/loading.vue'
 import loading from '@/components/loading.vue'
 import useStore from './store/index'
 import useStore from './store/index'
 import { computed } from 'vue'
 import { computed } from 'vue'
+import { zhCN, dateZhCN } from 'naive-ui'
+import Theme from '@/assets/naive-theme'
 
 
 const store = useStore()
 const store = useStore()
 const show = computed(() => store.loading)
 const show = computed(() => store.loading)
+const themeOverrides = Theme
 console.log(
 console.log(
   `More:
   `More:
 1. '/' 多人画板
 1. '/' 多人画板
@@ -19,12 +32,12 @@ console.log(
 6. '/news' 实时新闻
 6. '/news' 实时新闻
 7. '/plantool' 平面图缩放`
 7. '/plantool' 平面图缩放`
 )
 )
-
 </script>
 </script>
 <style>
 <style>
 html,
 html,
 body {
 body {
   margin: 0;
   margin: 0;
   padding: 0;
   padding: 0;
+  overflow: hidden;
 }
 }
 </style>
 </style>

+ 39 - 7
src/pages/main.ts

@@ -1,19 +1,51 @@
 import { createApp } from 'vue'
 import { createApp } from 'vue'
 import App from './App.vue'
 import App from './App.vue'
 import { createPinia } from 'pinia'
 import { createPinia } from 'pinia'
-import { createRouter, createWebHashHistory } from 'vue-router'
-// 富文本注册自定义按钮
-import '@/utils/registerMenu'
+import naive from '@/assets/native-plugin'
+import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
+import Icon from '@/components/icon.vue'
+import 'virtual:svg-icons-register'
+import piniaPersist from 'pinia-plugin-persist'
+
+const store = createPinia()
+store.use(piniaPersist)
+
 // 动态路由
 // 动态路由
-const routes = Object.values(import.meta.glob('./views/*/route.ts', { eager: true })).map((m) => (m as any).default || m)
+const routes = Object.values(import.meta.glob('./views/*/route.ts', { eager: true, import: 'default' })) as unknown as RouteRecordRaw[]
 routes.push({ path: '/:path(.*)', redirect: '/' })
 routes.push({ path: '/:path(.*)', redirect: '/' })
-const store = createPinia()
+
 const app = createApp(App)
 const app = createApp(App)
 const router = createRouter({
 const router = createRouter({
   history: createWebHashHistory(),
   history: createWebHashHistory(),
   routes
   routes
 })
 })
-
+app.component('Icon', Icon)
+// 路由守卫
+// router.beforeEach((to, from, next) => {
+//   // do something
+//   next()
+// })
 app.use(store)
 app.use(store)
+  .use(naive)
   .use(router)
   .use(router)
-  .mount('#app')
+
+router.isReady().then(() => {
+  const vm = app.mount('#app')
+  app.config.errorHandler = (err: any) => {
+    if (err.reason === 401) {
+      router.replace('/')
+    } else {
+      console.log('错误', err)
+    }
+  }
+  window.addEventListener('unhandledrejection', (evt) => {
+    console.error(evt)
+    evt.preventDefault()
+    app.config.errorHandler?.(evt, vm, '')
+  })
+  window.addEventListener('error', (evt) => {
+    console.error(evt)
+    evt.preventDefault()
+    app.config.errorHandler?.(evt.error, vm, '')
+  })
+})

+ 27 - 8
src/pages/store/index.ts

@@ -1,12 +1,31 @@
 import { defineStore } from 'pinia'
 import { defineStore } from 'pinia'
-// id必填,且需要唯一
-import { ref } from 'vue'
-const useStore = defineStore('index', () => {
-  const loading = ref(false)
 
 
-  const setLoading = (data:boolean) => {
-    loading.value = data
+export interface UserInfo {
+  id: number,
+  name: string,
+  opmId: number,
+  satoken: string
+}
+
+// id必填,且需要唯一
+const useStore = defineStore('index', {
+  state: () => ({
+    userInfro: {} as UserInfo,
+    token: '',
+    isCheckPermission: false,
+    loading: false
+  }),
+  actions: {
+    setUserInfo(data: UserInfo) {
+      this.userInfro = data
+      this.token = data.satoken || ''
+    },
+    setCheckPermission(data: boolean) {
+      this.isCheckPermission = data
+    }
+  },
+  persist: {
+    enabled: true // true 表示开启持久化保存
   }
   }
-  return { loading, setLoading }
 })
 })
-export default useStore
+export default useStore

+ 2 - 2
src/pages/views/chart/index.vue

@@ -398,7 +398,7 @@ onMounted(() => {
   const isIOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
   const isIOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
   const isAndroid = navigator.userAgent.includes('Android') || navigator.userAgent.includes('Linux') // g
   const isAndroid = navigator.userAgent.includes('Android') || navigator.userAgent.includes('Linux') // g
   if (isIOS || isAndroid) {
   if (isIOS || isAndroid) {
-    alert('建议用电脑打开')
+    window.alert('建议用电脑打开')
   }
   }
 })
 })
 
 
@@ -409,7 +409,7 @@ onUnmounted(() => {
   charts.dispose()
   charts.dispose()
 })
 })
 </script>
 </script>
-<style scoped lang="less">
+<style scoped lang="scss">
 @font-face {
 @font-face {
   font-family: "LCD";
   font-family: "LCD";
   src: url("./assets/font/LCD.ttf") format("truetype");
   src: url("./assets/font/LCD.ttf") format("truetype");

BIN
src/pages/views/draw/img/0.png


BIN
src/pages/views/draw/img/1-1.png


BIN
src/pages/views/draw/img/1-2.png


BIN
src/pages/views/draw/img/1-3.png


BIN
src/pages/views/draw/img/1.png


BIN
src/pages/views/draw/img/10.png


BIN
src/pages/views/draw/img/11.png


BIN
src/pages/views/draw/img/12.png


BIN
src/pages/views/draw/img/13.png


BIN
src/pages/views/draw/img/14.png


BIN
src/pages/views/draw/img/15.png


BIN
src/pages/views/draw/img/16.png


BIN
src/pages/views/draw/img/17.png


BIN
src/pages/views/draw/img/18.png


BIN
src/pages/views/draw/img/19.png


BIN
src/pages/views/draw/img/2.png


BIN
src/pages/views/draw/img/20.png


BIN
src/pages/views/draw/img/21.png


BIN
src/pages/views/draw/img/22.png


BIN
src/pages/views/draw/img/3.png


BIN
src/pages/views/draw/img/4.png


BIN
src/pages/views/draw/img/5.png


BIN
src/pages/views/draw/img/6.png


BIN
src/pages/views/draw/img/7.png


BIN
src/pages/views/draw/img/8.png


BIN
src/pages/views/draw/img/9.png


+ 277 - 0
src/pages/views/draw/index.vue

@@ -0,0 +1,277 @@
+<template>
+  <div class="draw">
+    <canvas
+      id="CANVAS"
+      class="canvas"
+    />
+    <n-select
+      v-model:value="check"
+      :options="options"
+      :render-label="renderLabel"
+      @update:value="changeOption"
+    />
+    <label>
+      旋转角度º:
+      <input type="number">
+    </label>
+    <n-button
+      type="tertiary"
+      block
+    >
+      撤销
+    </n-button>
+    <n-button
+      type="tertiary"
+      block
+    >
+      清空
+    </n-button>
+    <n-button
+      type="info"
+      block
+    >
+      保存
+    </n-button>
+  </div>
+</template>
+<script setup lang='ts'>
+import { h, onMounted, ref } from 'vue'
+import { DrawCanvas } from './js/draw'
+
+const drawCanvas = new DrawCanvas()
+const options = [
+  {
+    label: '边界线',
+    icon: './img/0.png',
+    value: 0,
+    w: 5,
+    h: 3
+  },
+  {
+    label: '灰岩',
+    icon: './img/1.png',
+    value: 1,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '第四系全新统残坡积',
+    icon: './img/2.png',
+    value: 2,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '第四系全新统崩坡积',
+    icon: './img/3.png',
+    value: 3,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '震旦系上统灯影组',
+    icon: './img/4.png',
+    value: 4,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '志留系中统石门坎组',
+    icon: './img/5.png',
+    value: 5,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '寒武系中统西王庙组',
+    icon: './img/6.png',
+    value: 6,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '粉砂岩',
+    icon: './img/7.png',
+    value: 7,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '页岩',
+    icon: './img/8.png',
+    value: 8,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '粉砂质泥岩',
+    icon: './img/9.png',
+    value: 9,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '泥岩',
+    icon: './img/10.png',
+    value: 10,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '断层破碎带',
+    icon: './img/11.png',
+    value: 11,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '块石土',
+    icon: './img/12.png',
+    value: 12,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '白云质灰岩',
+    icon: './img/13.png',
+    value: 13,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '炭质页岩',
+    icon: './img/14.png',
+    value: 14,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '推测地层界线',
+    icon: './img/15.png',
+    value: 15,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '推测岩,土层界线',
+    icon: './img/16.png',
+    value: 16,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '细砂岩',
+    icon: './img/17.png',
+    value: 17,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '花岗闪长岩',
+    icon: './img/18.png',
+    value: 18,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '千枚岩',
+    icon: './img/19.png',
+    value: 19,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '钙质千枚岩',
+    icon: './img/20.png',
+    value: 20,
+    w: 10,
+    h: 6
+  },
+  {
+    label: '碳质板岩',
+    icon: './img/21.png',
+    value: 21,
+    w: 10,
+    h: 6
+  }
+]
+const check = ref(0)
+const dicTypePath = {
+  2: 'M174.562965,0.513209692 C221.690071,-0.00711210434 258.74832,14.9447077 286.260378,35.6782336 C324.994127,64.8686054 344.820323,105.514125 347.165866,130.556406 C351.169981,173.306492 350.923005,204.505495 338.863366,216.40901 C332.465594,222.723955 293.34237,247.50004 156.505785,247.50004 C124.380762,247.273198 88.5993566,242.423806 60.1185245,235.625016 C31.7537688,228.853934 10.5049705,220.211836 7.77411598,212.201523 C0.968039201,195.148672 -3.37568328,153.116559 5.40190246,119.570011 C11.4412002,98.8625327 30.5685051,60.0564728 69.9004626,32.3721832 C95.541554,14.3243807 129.772401,1.00773417 174.562965,0.513209692 Z',
+  1: 'M69.4545878,34.6718448 C96.0319839,14.5464002 130.907219,-0.146079872 174.56443,0.522007913 C220.382312,1.22316053 255.607386,15.5063115 281.851378,35.1514114 C318.898628,62.8833568 338.052622,101.292047 343.850748,127.226896 C348.964999,150.102793 350.773132,170.630546 348.624737,186.798399 C346.628206,201.8234 341.223483,213.080679 331.813382,218.873688 C331.442887,219.101769 331.054704,219.344664 330.644655,219.601247 C319.902715,226.322867 294.07793,242.444674 177.407992,247.500112 C92.0383303,246.776789 19.7179823,226.018176 9.91797058,212.791135 C-0.632619328,198.551039 -1.84542038,163.783447 3.98419444,129.673937 C7.51590663,109.009626 28.7726098,65.4778309 69.4545878,34.6718448 Z',
+  0: 'M175.000036,0.5 C222.664535,0.5 265.865535,21.1909654 297.358963,54.7296453 C328.90593,88.3253418 348.705559,134.812441 349.476653,186.303442 L349.490723,188.280824 L349.5,247.5 L0.5,247.5 L0.5,188.283766 C0.787224943,136.359137 20.4197058,89.3998566 51.9881066,55.4283849 C83.5364037,21.4785471 127.005458,0.5 175.000036,0.5 Z'
+}
+
+function renderLabel(option) {
+  return h('div', {
+    style: {
+      display: 'flex',
+      alignItems: 'center'
+    }
+  }, [
+    h('img', {
+      src: new URL(option.icon, import.meta.url).href,
+      style: {
+        width: '20px',
+        height: '20px',
+        marginRight: '5px'
+      }
+    }),
+    h('div', {
+      style: {
+        fontSize: '14px'
+      }
+    }, { default: () => option.label })
+  ])
+}
+
+function changeOption(v, option) {
+  console.log('切换', v, option)
+  drawCanvas._executionArr.type = v
+}
+
+onMounted(() => {
+  const canvas = document.getElementById('CANVAS')
+  drawCanvas._init({
+    canvas,
+    dicTypePath: dicTypePath[0],
+    callBack: () => {
+      changeOption(null, options[check.value])
+    }
+  })
+})
+</script>
+<style lang="scss">
+.draw {
+  max-width: 800px;
+  min-width: 370px;
+  margin: 0 auto;
+  overflow: hidden;
+  box-sizing: border-box;
+  padding: 0 10px;
+
+  .canvas {
+    display: block;
+    margin: 10px auto;
+    width: 350px;
+    height: 248px;
+  }
+
+  .n-button {
+    margin-bottom: 10px;
+  }
+
+  label {
+    display: block;
+    font-size: 14px;
+    margin: 10px 0;
+    border: 1px solid rgba(196, 200, 206, 1);
+    padding: 6px 10px;
+  }
+
+  label>input {
+    border: none;
+    outline: none;
+  }
+}
+</style>

+ 17 - 0
src/pages/views/draw/js/NativePlugin.ts

@@ -0,0 +1,17 @@
+import {
+  create,
+  NButton,
+  NSelect,
+  NConfigProvider
+
+} from 'naive-ui'
+
+const naive = create({
+  components: [
+    NButton,
+    NSelect,
+    NConfigProvider
+  ]
+})
+
+export default naive

+ 111 - 0
src/pages/views/draw/js/draw.js

@@ -0,0 +1,111 @@
+class DrawCanvas {
+
+  constructor() {
+    this._ctx = null
+    this._canvas = null
+    this._executionArr = { s: 0, e: 0, arr: [], type: 1 } //每移动一笔的数据
+    this._pathArr = [] //抬起落下为一笔
+    this._fillStyle = null // 每笔的样式
+    this._matrix = new DOMMatrix() //旋转矩阵
+
+  }
+
+  _init({ canvas, dicTypePath = '', callBack }) {
+    if (!canvas) return
+    const domRect = canvas.getBoundingClientRect()
+    const dpr = window.devicePixelRatio
+    const ctx = canvas.getContext('2d')
+    canvas.width = domRect.width * dpr
+    canvas.height = domRect.height * dpr
+    ctx.scale(dpr, dpr)
+    this._canvas = canvas
+    this._ctx = ctx
+    // 加个背景
+    this._ctx.fillStyle = "#FFFFFF";
+    this._ctx.fillRect(0, 0, canvas.width, canvas.height);
+    // 添加路径底图 
+    const path = this.sPath2cPath(dicTypePath)
+    if (path) {
+      this._ctx.stroke(path)
+      this._ctx.clip(path) //IOS真机裁切后,导致无法画图
+      this._path = path
+    }
+    // 事件监听
+    canvas.addEventListener('touchstart', this.touchStart.bind(this))
+    canvas.addEventListener('touchmove', this.touchMove.bind(this))
+    canvas.addEventListener('touchend', this.touchEnd.bind(this))
+    callBack()
+    console.log('初始化完成', this);
+  }
+
+  touchStart(event) {
+    if (!this._executionArr.type) {
+      const { clientX, clientY, target: { offsetLeft, offsetTop } } = event.targetTouches[0]
+      this._executionArr.s = clientX - offsetLeft
+      this._executionArr.e = clientY - offsetTop
+    }
+    this._executionArr.arr = []
+  }
+
+  touchMove(event) {
+    const { clientX, clientY, target: { offsetLeft, offsetTop } } = event.targetTouches[0]
+    const x = clientX - offsetLeft
+    const y = clientY - offsetTop
+    this._executionArr.arr.push([x, y])
+    this.drawLine(x, y)
+  }
+
+  touchEnd() {
+    this._pathArr.push({
+      ...this._fillStyle,
+      path: this._executionArr
+    })
+  }
+
+
+  // 画线
+  drawLine(x = 0, y = 0) {
+    if (!this._ctx || this._executionArr.type) return
+    this._ctx.beginPath();
+    this._ctx.strokeStyle = '#2080f0'
+    this._ctx.moveTo(this._executionArr.s, this._executionArr.e);
+    this._ctx.lineTo(x, y);
+    this._ctx.stroke();
+    this._executionArr.s = x
+    this._executionArr.e = y
+    console.log('画线', this._executionArr);
+  }
+
+  // svg 路径转 canvas 路径
+  sPath2cPath(path = '') {
+    if (!path || !this._canvas) return null
+    const arr = path.split(/(^|\s+)(?=[A-Z])/).filter(el => el !== ' ')
+    const PATH = new Path2D();
+    for (let k = 0; k < arr.length; k++) {
+      const el = arr[k].replace(/\s+/g, ',');
+      const key = el.replace(/[^A-Z]/g, '')
+      const value = el.replace(/[A-Z]/g, '').split(',')
+      if (key === 'M') {
+        PATH.moveTo(value[0], value[1]);
+      } else if (key === 'C') {
+        PATH.bezierCurveTo(value[0], value[1], value[2], value[3], value[4], value[5]);
+      } else if (key === 'L') {
+        PATH.lineTo(value[0], value[1]);
+      }
+    }
+    return PATH
+  }
+
+  // 销毁
+  destory() {
+    this._ctx = null
+    this._canvas = null
+    this._executionArr = []
+    this._pathArr = []
+    this._style = null
+    this._matrix = null
+    this._path = null
+  }
+}
+
+export { DrawCanvas }

+ 3 - 2
src/pages/views/move/route.ts → src/pages/views/draw/route.ts

@@ -1,9 +1,10 @@
 import { RouteRecordRaw } from 'vue-router'
 import { RouteRecordRaw } from 'vue-router'
+import home from './index.vue'
 
 
 export default {
 export default {
-  path: '/move',
+  path: '/draw',
   meta: {
   meta: {
     authorize: true
     authorize: true
   },
   },
-  component: () => import('./index.vue')
+  component: home
 } as RouteRecordRaw
 } as RouteRecordRaw

+ 3 - 1
src/components/editeDemo.vue → src/pages/views/edit/component/editeDemo.vue

@@ -28,6 +28,8 @@
 </template>
 </template>
 
 
 <script setup lang='ts'>
 <script setup lang='ts'>
+// 富文本注册自定义按钮
+import '@/services/registerMenu'
 import { onBeforeUnmount, ref, shallowRef } from 'vue'
 import { onBeforeUnmount, ref, shallowRef } from 'vue'
 import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
 import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
 import '@wangeditor/editor/dist/css/style.css'
 import '@wangeditor/editor/dist/css/style.css'
@@ -123,7 +125,7 @@ onBeforeUnmount(() => {
 
 
 </script>
 </script>
 
 
-<style lang="less" scoped>
+<style lang="scss" scoped>
 .EditorTop {
 .EditorTop {
   background: white;
   background: white;
 
 

+ 3 - 3
src/pages/views/edit/index.vue

@@ -5,16 +5,16 @@
 </template>
 </template>
 <script lang="ts" setup>
 <script lang="ts" setup>
 import { onMounted } from 'vue'
 import { onMounted } from 'vue'
-import RichEdit from '@/components/editeDemo.vue'
+import RichEdit from './component/editeDemo.vue'
 onMounted(() => {
 onMounted(() => {
   const isIOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
   const isIOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
   const isAndroid = navigator.userAgent.includes('Android') || navigator.userAgent.includes('Linux') // g
   const isAndroid = navigator.userAgent.includes('Android') || navigator.userAgent.includes('Linux') // g
   if (isIOS || isAndroid) {
   if (isIOS || isAndroid) {
-    alert('建议用电脑打开')
+    window.alert('建议用电脑打开')
   }
   }
 })
 })
 </script>
 </script>
-<style lang="less" scoped>
+<style lang="scss" scoped>
 .box {
 .box {
     width: 1000px;
     width: 1000px;
     height: 100vh;
     height: 100vh;

+ 4 - 2
src/utils/registerMenu.js → src/pages/views/edit/js/registerMenu.ts

@@ -1,9 +1,11 @@
 import { Boot } from '@wangeditor/editor'
 import { Boot } from '@wangeditor/editor'
-import { exp2pdf } from '@/utils/html2File'
+import { exp2pdf } from '@/services/exportFile'
 console.warn('此插件注册富文本自定义按钮')
 console.warn('此插件注册富文本自定义按钮')
 // 注册一个保存按钮
 // 注册一个保存按钮
 class SaveBtn {
 class SaveBtn {
-
+    title = ''
+    iconSvg = ''
+    tag = ''
     constructor() {
     constructor() {
         this.title = '导出PDF'
         this.title = '导出PDF'
         this.iconSvg = '<svg viewBox="0 0 1024 1024" style="width:22px;height:22px;" version="1.1" xmlns="http://www.w3.org/2000/svg" ><path d="M773.696 134.812444l-509.155556 0c-69.76 0-126.520889 56.760889-126.520889 126.542222l0 501.326222c0 69.781333 56.760889 126.499556 126.520889 126.499556l509.141333 0c69.781333 0 126.520889-56.718222 126.520889-126.499556L900.202667 261.361778C900.202667 191.573333 843.441778 134.833778 773.696 134.812444zM324.437333 184.213333l389.347556 0 0 279.608889L324.437333 463.822222 324.437333 184.213333zM850.872889 762.680889c0 42.552889-34.616889 77.191111-77.169778 77.191111l-509.155556 0c-42.552889 0-77.169778-34.638222-77.169778-77.191111L187.377778 261.383111c0-42.574222 34.616889-77.169778 77.169778-77.169778l0-0.021333 10.567111 0 0 329.009778 488.007111 0 0.021333 0L763.143111 184.184889l10.567111 0c42.56 0 77.169778 34.595556 77.169778 77.169778L850.88 762.680889zM591.772444 256.832l49.329778 0 0 164.522667-49.329778 0 0-164.522667ZM591.772444 256.832"></path></svg>'
         this.iconSvg = '<svg viewBox="0 0 1024 1024" style="width:22px;height:22px;" version="1.1" xmlns="http://www.w3.org/2000/svg" ><path d="M773.696 134.812444l-509.155556 0c-69.76 0-126.520889 56.760889-126.520889 126.542222l0 501.326222c0 69.781333 56.760889 126.499556 126.520889 126.499556l509.141333 0c69.781333 0 126.520889-56.718222 126.520889-126.499556L900.202667 261.361778C900.202667 191.573333 843.441778 134.833778 773.696 134.812444zM324.437333 184.213333l389.347556 0 0 279.608889L324.437333 463.822222 324.437333 184.213333zM850.872889 762.680889c0 42.552889-34.616889 77.191111-77.169778 77.191111l-509.155556 0c-42.552889 0-77.169778-34.638222-77.169778-77.191111L187.377778 261.383111c0-42.574222 34.616889-77.169778 77.169778-77.169778l0-0.021333 10.567111 0 0 329.009778 488.007111 0 0.021333 0L763.143111 184.184889l10.567111 0c42.56 0 77.169778 34.595556 77.169778 77.169778L850.88 762.680889zM591.772444 256.832l49.329778 0 0 164.522667-49.329778 0 0-164.522667ZM591.772444 256.832"></path></svg>'

+ 7 - 7
src/pages/views/fly/components/FlyMoitor.vue

@@ -199,7 +199,7 @@ const MathFlyAddres = (
     }
     }
   }
   }
   // 算出4机翼,飞机直径25,按机尾算出机翼位置
   // 算出4机翼,飞机直径25,按机尾算出机翼位置
-  const alldata = []
+  const alldata = [] as { x: { x: number, y: number }, y: { x: number, y: number } }[]
   for (let i = 0; i < 4; i++) {
   for (let i = 0; i < 4; i++) {
     const db = {
     const db = {
       x: {
       x: {
@@ -249,10 +249,10 @@ onMounted(() => {
 })
 })
 
 
 </script>
 </script>
-<style lang="less" scoped>
-  .svg{
-    width: 100%;
-    height: 100%;
-    background: rgba(28, 83, 121, 0.3)
-  }
+<style lang="scss" scoped>
+.svg {
+  width: 100%;
+  height: 100%;
+  background: rgba(28, 83, 121, 0.3)
+}
 </style>
 </style>

+ 1 - 1
src/pages/views/fly/index.vue

@@ -29,7 +29,7 @@ onUnmounted(() => {
   clearInterval(timer)
   clearInterval(timer)
 })
 })
 </script>
 </script>
-<style lang="less" scoped>
+<style lang="scss" scoped>
   .box{
   .box{
     width: 100vw;
     width: 100vw;
     height: 100vh;
     height: 100vh;

+ 3 - 3
src/pages/views/index/index.vue → src/pages/views/home/index.vue

@@ -29,8 +29,8 @@
   </div>
   </div>
 </template>
 </template>
 <script lang="ts" setup>
 <script lang="ts" setup>
-import { Painter } from '@/utils/Painter'
-import { Recorder } from '@/utils/Recorder'
+import { Painter } from './js/Painter.js'
+import { Recorder } from './js/Recorder.js'
 import {
 import {
   onMounted, ref, nextTick, onUnmounted
   onMounted, ref, nextTick, onUnmounted
 } from 'vue'
 } from 'vue'
@@ -137,7 +137,7 @@ onUnmounted(() => {
   recorder = null
   recorder = null
 })
 })
 </script>
 </script>
-<style lang="less" scoped>
+<style lang="scss" scoped>
 .box {
 .box {
   background: #eeeeee;
   background: #eeeeee;
   font-size: 12px;
   font-size: 12px;

+ 0 - 0
src/utils/Painter.js → src/pages/views/home/js/Painter.js


+ 0 - 0
src/utils/Recorder.js → src/pages/views/home/js/Recorder.js


+ 0 - 0
src/pages/views/index/route.ts → src/pages/views/home/route.ts


BIN
src/pages/views/move/assets/1.png


+ 0 - 71
src/pages/views/move/index.vue

@@ -1,71 +0,0 @@
-<template>
-  <div class="box">
-    <svg
-      id="moveBox"
-      viewBox="0 0 700 656"
-      width="700"
-      height="656"
-    >
-      <!-- 隧道底图缩小1/4倍 -->
-      <image
-        xlink:href="./assets/1.png"
-        x="87.5"
-        y="82"
-        height="492"
-        width="525"
-      />
-      <!-- 可自定义传感器样式|所有传感器列表 -->
-      <text
-        x="600"
-        y="20"
-        fill="red"
-        type="transducer"
-      >传感器1</text>
-      <text
-        x="600"
-        y="40"
-        fill="red"
-        type="transducer"
-      >传感器2</text>
-      <text
-        x="600"
-        y="60"
-        fill="red"
-        type="transducer"
-      >传感器3</text>
-      <text
-        x="600"
-        y="80"
-        fill="red"
-        type="transducer"
-      >传感器4</text>
-    </svg>
-  </div>
-</template>
-<script lang="ts" setup>
-import { onMounted } from 'vue'
-import move from '@/utils/move'
-
-const callBack = (data: any) => {
-  console.log('我是回调', data)
-}
-onMounted(() => {
-  const dom = document.getElementById('moveBox')
-  move.on(dom, callBack)
-  const isIOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
-  const isAndroid = navigator.userAgent.includes('Android') || navigator.userAgent.includes('Linux') // g
-  if (isIOS || isAndroid) {
-    alert('建议用电脑打开')
-  }
-})
-</script>
-<style lang="less" scoped>
-.box {
-    position: relative;
-    text-align: center;
-}
-
-svg {
-    border: solid 1px red;
-}
-</style>

+ 0 - 146
src/pages/views/news/index.vue

@@ -1,146 +0,0 @@
-<template>
-  <div class="box">
-    <p class="head">
-      <span>Hot List</span>
-    </p>
-    <ul class="content">
-      <li
-        v-for="(item, index) in msg"
-        :key="index"
-      >
-        <a
-          :href="item.url"
-          target="_blank"
-        >
-          <img
-            :src="item.imgSrc"
-            alt="图片"
-          >
-          <span>{{ item.name }}</span>
-          <span :style="`color:${color(index)}`">{{ item.strnum }}</span>
-        </a>
-      </li>
-    </ul>
-  </div>
-</template>
-<script lang="ts" setup>
-import { ref } from 'vue'
-import axios from '@/utils/axios'
-const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
-const msg: any = ref([])
-const uvList = ref()
-const getDB = async () => {
-  const data = await axios.get('/static/test.json')
-  msg.value = data || []
-  await sleep(10 * 1000)
-  getDB()
-}
-const getInfo = async () => {
-  const data = await axios.get('/static/info.json')
-  uvList.value = data || []
-  await sleep(10 * 1000)
-  getInfo()
-}
-const color = (num: number) => {
-  if (num < 10) {
-    return `rgba(255,152,18,${Math.abs(num - 10) / 20 + 0.5})`
-  }
-  return `rgba(145,149,163,${Math.abs(msg.value.length - num) / msg.value.length + 0.3})`
-}
-getDB()
-getInfo()
-</script>
-<style lang="less" scoped>
-.box {
-    ul,
-    li {
-        list-style: none;
-        text-align: center;
-        padding: 0;
-        margin: 0;
-    }
-
-    a {
-        display: inline-flex;
-        width: 350px;
-        color: #2c3e50;
-        text-decoration: none;
-        margin: 5px auto;
-        text-align: left;
-        letter-spacing: 1px;
-        justify-content: flex-start;
-        align-items: center;
-    }
-
-    img {
-        width: 64px;
-        height: 42px;
-        border-radius: 6px;
-    }
-
-    a:hover {
-        color: rgba(160, 179, 232, 0.9);
-    }
-
-    .head {
-        margin: 0;
-        height: 32px;
-        line-height: 32px;
-        text-align: center;
-    }
-
-    .head span:first-child {
-        font-weight: 600;
-        font-size: 25px;
-        margin: 5px 0;
-        cursor: pointer;
-        background-image: -webkit-linear-gradient(bottom, red, #ff5f60, #f0c41b);
-        background-clip: text;
-        -webkit-background-clip: text;
-        -webkit-text-fill-color: transparent;
-    }
-
-    a>span:nth-child(2) {
-        width: 230px;
-        margin-left: 10px;
-    }
-
-    a>span:last-child {
-        font-size: 13px;
-    }
-
-    .content {
-        height: 96vh;
-        overflow-y: auto;
-    }
-}
-
-/* 设置滚动条的样式 */
-::-webkit-scrollbar {
-    width: 5px;
-    height: 5px;
-    position: fixed;
-    background: transparent;
-}
-
-/* 滚动槽 */
-::-webkit-scrollbar-track {
-    background: transparent;
-    border-radius: 5px;
-    width: 5px;
-    position: fixed;
-}
-
-/* 滚动条滑块 */
-::-webkit-scrollbar-thumb {
-    border-radius: 5px;
-    background: #ccc;
-    box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.5);
-    position: fixed;
-    right: 0;
-}
-
-::-webkit-scrollbar-thumb:window-inactive {
-    background: #ccc;
-}
-</style>

+ 42 - 46
src/pages/views/planTool/index.vue

@@ -4,36 +4,30 @@
     <div id="openseadragon" />
     <div id="openseadragon" />
     <!-- 参数调试 -->
     <!-- 参数调试 -->
     <div class="params">
     <div class="params">
-      <label>
-        <Input
+      <n-input-group>
+        <n-input-group-label>CAD宽度</n-input-group-label>
+        <n-input
           v-model="Width"
           v-model="Width"
           readonly
           readonly
-        >
-          <template #prepend>
-            <span>CAD宽度</span>
-          </template>
-        </Input>
-      </label>
-      <label>
-        <Input
+          style="width: 70%"
+        />
+      </n-input-group>
+      <n-input-group>
+        <n-input-group-label>CAD高度</n-input-group-label>
+        <n-input
           v-model="Height"
           v-model="Height"
           readonly
           readonly
-        >
-          <template #prepend>
-            <span>CAD高度</span>
-          </template>
-        </Input>
-      </label>
-      <label>
-        <Input
+          style="width: 70%"
+        />
+      </n-input-group>
+      <n-input-group>
+        <n-input-group-label>隧道比例</n-input-group-label>
+        <n-input-number
           v-model="scale"
           v-model="scale"
+          style="width: 70%"
           @on-blur="initViewer"
           @on-blur="initViewer"
-        >
-          <template #prepend>
-            <span>隧道比例</span>
-          </template>
-        </Input>
-      </label>
+        />
+      </n-input-group>
     </div>
     </div>
     <div class="text">
     <div class="text">
       <p style="font-size: 17px">
       <p style="font-size: 17px">
@@ -47,11 +41,9 @@
 
 
 <script setup>
 <script setup>
 import { onMounted, ref, watchEffect } from 'vue'
 import { onMounted, ref, watchEffect } from 'vue'
-import { Input } from 'view-ui-plus'
-import 'view-ui-plus/dist/styles/viewuiplus.css'
 import OpenSeadragon from 'openseadragon'
 import OpenSeadragon from 'openseadragon'
-import { svgOverlay } from '@/utils/openseadragon-svg-overlay'
-import axios from '@/utils/axios'
+import { svgOverlay } from './js/openseadragon-svg-overlay'
+
 // 数据
 // 数据
 const scale = ref(0)
 const scale = ref(0)
 const Width = ref(process.env.imgSize.W)
 const Width = ref(process.env.imgSize.W)
@@ -69,17 +61,19 @@ const MAXZOOM = process.env.imgSize.M
 let tunnelPath = null
 let tunnelPath = null
 
 
 // 获取svg路径
 // 获取svg路径
-const getTunnelPath = async () => {
-  const txt = await axios.get(SVGPATH)
-  const objE = document.createElement('div')
-  objE.innerHTML = txt
-  let svg = objE.lastElementChild
-  svg = document.importNode(svg, true)
-  const path = svg.getElementsByTagName('path')
-  // 隧道比例默认SVG宽度
-  const num = +svg.getAttribute('width').replace(/[^0-9]/gi, '')
-  scale.value = num
-  tunnelPath = path
+const getTunnelPath = () => {
+  fetch(SVGPATH).then((res) => res.text()).then((txt) => {
+    const objE = document.createElement('div')
+    objE.innerHTML = txt
+    let svg = objE.lastElementChild
+    svg = document.importNode(svg, true)
+    const path = svg.getElementsByTagName('path')
+    // 隧道比例默认SVG宽度
+    const num = +svg.getAttribute('width').replace(/[^0-9]/gi, '')
+    scale.value = num
+    tunnelPath = path
+    initViewer()
+  })
 }
 }
 
 
 /**
 /**
@@ -307,12 +301,9 @@ watchEffect(() => {
 })
 })
 
 
 // 生命周期
 // 生命周期
-onMounted(async () => {
-  await getTunnelPath()
-  initViewer()
-})
+onMounted(() => getTunnelPath())
 </script>
 </script>
-<style lang="less" scoped>
+<style lang="scss" scoped>
 #apps {
 #apps {
   width: 1000px;
   width: 1000px;
   height: 800px;
   height: 800px;
@@ -320,26 +311,31 @@ onMounted(async () => {
   text-align: center;
   text-align: center;
   color: #2c3e50;
   color: #2c3e50;
   user-select: none;
   user-select: none;
+
   #openseadragon {
   #openseadragon {
     width: 1000px;
     width: 1000px;
     height: 600px;
     height: 600px;
     border: solid 1px #ccc;
     border: solid 1px #ccc;
   }
   }
+
   .params {
   .params {
     width: 100%;
     width: 100%;
     display: flex;
     display: flex;
     margin-top: 10px;
     margin-top: 10px;
+
     // justify-content: center;
     // justify-content: center;
-    & > label {
+    &>label {
       margin-right: 10px;
       margin-right: 10px;
     }
     }
   }
   }
+
   .text {
   .text {
     color: red;
     color: red;
     font-size: 13px;
     font-size: 13px;
     margin-top: 10px;
     margin-top: 10px;
     text-align: left;
     text-align: left;
-    & > p:not(:first-child) {
+
+    &>p:not(:first-child) {
       text-indent: 20px;
       text-indent: 20px;
     }
     }
   }
   }

+ 0 - 0
src/utils/openseadragon-svg-overlay.js → src/pages/views/planTool/js/openseadragon-svg-overlay.js


+ 3 - 0
src/pages/views/test/index.vue

@@ -0,0 +1,3 @@
+<template>
+  <div>3D测试</div>
+</template>

+ 3 - 2
src/pages/views/news/route.ts → src/pages/views/test/route.ts

@@ -1,9 +1,10 @@
 import { RouteRecordRaw } from 'vue-router'
 import { RouteRecordRaw } from 'vue-router'
 
 
 export default {
 export default {
-  path: '/news',
+  path: '/test',
   meta: {
   meta: {
     authorize: true
     authorize: true
   },
   },
-  component: () => import('./index.vue')
+  component: () => import('./index.vue'),
+  children: []
 } as RouteRecordRaw
 } as RouteRecordRaw

+ 167 - 0
src/services/exportFile.ts

@@ -0,0 +1,167 @@
+import html2canvas from 'html2canvas'
+import JSPDF from 'jspdf'
+import * as XLSX from 'xlsx'
+
+/**
+ * 导出PDF
+ * @param domID 需要输出PDF的页面id
+ * @param fileName 文件名
+ * @param type  默认A4分页
+ * @param wMultiple 宽倍数
+ * @param hMultiple 高倍数
+ * @returns
+ */
+export const exp2pdf = async (domID: string, fileName: string, type = 'A4', wMultiple = null, hMultiple = null) => {
+  const dom = document.getElementById(domID)
+  if (!dom) return
+  // loading
+  const domHeight = dom.offsetHeight // 获取DOM高度
+  const domWidth = dom.offsetWidth // 获取DOM宽度
+  const canvas = await html2canvas(dom, {
+    logging: false,
+    useCORS: true, // 允许图片跨域
+    scale: 1.5,
+    width: wMultiple ? wMultiple * domWidth : undefined,
+    height: hMultiple ? hMultiple * domHeight : undefined
+  })
+
+  if (type === 'A4') {
+    // A4分页
+    const pdf = new JSPDF('p', 'mm', 'a4') // A4纸,纵向
+    const ctx = canvas.getContext('2d') as any
+    const a4w = 200
+    const a4h = 277 // A4大小,210mm x 297mm,四边各保留20mm的边距
+    const imgHeight = Math.floor(a4h * canvas.width / a4w) // 按A4显示比例换算一页图像的像素高度
+    let renderedHeight = 0
+    while (renderedHeight < canvas.height) {
+      const page = document.createElement('canvas')
+      page.width = canvas.width
+      page.height = Math.min(imgHeight, canvas.height - renderedHeight) // 可能内容不足一页
+      // 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
+      page.getContext('2d')?.putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0)
+      pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width)) // 添加图像到页面,保留10mm边距
+      renderedHeight += imgHeight
+      if (renderedHeight < canvas.height) { pdf.addPage() } // 如果后面还有内容,添加一个空页
+      // delete page;
+    }
+    pdf.save(fileName)
+  } else {
+    // 整张
+    const pdf = new JSPDF('p', 'px', [ domWidth, domHeight ])
+    pdf.addImage(canvas.toDataURL('image/jpeg', 1.0), 'JPEG', 10, 10, domWidth, domHeight)
+    pdf.save(fileName)
+  }
+  // loading
+}
+
+/**
+ * 导出PNG
+ * @param domID 需要输出PDF的页面id
+ * @param fileName 文件名
+ * @param bkcolor 背景色
+ */
+export const exp2png = async (domID: string, fileName: string, bkcolor: string) => {
+  // loading
+  window.scroll(0, 0) // 首先先顶部
+  const design = document.getElementById(domID) as HTMLElement
+  if (!design) return
+  const imgHeight = design.offsetHeight // 获取DOM高度
+  const imgWidth = design.offsetWidth // 获取DOM宽度
+  const scale = window.devicePixelRatio <= 3 ? 3 : window.devicePixelRatio // 获取设备像素比
+  const canvas = await html2canvas(design, {
+    backgroundColor: bkcolor, // 设置背景颜色
+    useCORS: true, // 允许图片跨域
+    scale, // 缩放3倍,使得图片更加清晰=>越清晰图片越大
+    width: imgWidth,
+    height: imgHeight,
+    imageTimeout: 5000 // 设置图片的超时,设置0为禁用
+  })
+  const imgURL = canvas.toDataURL('image/png')
+  return imgURL
+  // loading
+}
+
+/**
+ * 解析excel表格
+ * @param file 文件
+ * @returns
+ */
+export const exp2json = async (file: File) => await new Promise((resolve, reject) => {
+  try {
+    const reader = new FileReader()
+    reader.onload = (e) => {
+      const wb = XLSX.read(e.target?.result, {
+        type: 'binary'
+      }) // 读取完成的数据
+      // 转成json header解析第一行标题
+      const data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], { header: 1 })
+      resolve(data)
+    }
+    reader.readAsBinaryString(file)
+  } catch (error) {
+    console.log('解析错误')
+    reject(error)
+  }
+})
+
+/**
+ * dom导出excel
+ * @param domID domID
+ * @param fileName 文件名
+ */
+export const dom2excel = (domID: string, fileName: string) => {
+  const dom = document.getElementsByTagName(domID)
+  if (!dom) return
+  const wb = XLSX.utils.table_to_book(dom[0])
+  const baty = XLSX.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' })
+  // 字符串转ArrayBuffer
+  const s2ab = (s: any) => {
+    const buf = new ArrayBuffer(s.length)
+    const view = new Uint8Array(buf)
+    for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF
+    return buf
+  }
+  const blob = new Blob([ s2ab(baty) ], { type: 'application/octet-stream' })
+  return blob
+}
+
+/**
+ * array导出excel表格
+ * @param arr 数据是数组包含的对象
+ * @param fileName 名字
+ */
+export const exp2excel = (arr: object[], fileName: string, cellMerges?: Array<any>) => {
+  const sheet = XLSX.utils.json_to_sheet(arr)
+  // excel宽高设置
+  sheet['!cols'] = arr.map(() => ({ wch: 30 }))
+  if (cellMerges) {
+    sheet['!merges'] = cellMerges // <====合并单元格
+  }
+  // 转blob
+  const sheet2blob = (sheet: any, sheetName = 'sheet1') => {
+    const workbook = {
+      SheetNames: [ sheetName ],
+      Sheets: {} as any
+    }
+    workbook.Sheets[sheetName] = sheet
+    // 生成excel的配置项
+    const wopts = {
+      bookType: 'xlsx', // 要生成的文件类型
+      bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
+      type: 'binary'
+    } as any
+    const wbout = XLSX.write(workbook, wopts)
+    // 字符串转ArrayBuffer
+    const s2ab = (s: string) => {
+      const buf = new ArrayBuffer(s.length)
+      const view = new Uint8Array(buf)
+      for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF
+      return buf
+    }
+    const blob = new Blob([ s2ab(wbout) ], { type: 'application/octet-stream' })
+
+    return blob
+  }
+
+  return sheet2blob(sheet)
+}

+ 87 - 0
src/services/laglat2gauss.ts

@@ -0,0 +1,87 @@
+// 大地坐标与经纬度坐标互转
+
+
+function GaussToBL(X: number,Y: number){
+    let ProjNo;
+    let ZoneWide; //带宽
+    let output = new Array(2);
+    let longitude1,latitude1, longitude0, X0,Y0, xval,yval;//latitude0,
+    let e1,e2,f,a, ee, NN, T,C, M, D,R,u,fai, iPI;
+    iPI = 3.14159265358979324/180.0; 3.1415926535898/180.0;
+    // a = 6378245.0; f = 1.0/298.3; //54年北京坐标系参数
+    a=6378140.0; f=1.0/298.257; //80年西安坐标系参数
+    ZoneWide = 6; //6度带宽
+    ProjNo = Math.floor(X/1000000) ; //查找带号
+    longitude0 = (ProjNo-1) * ZoneWide + ZoneWide / 2;
+    longitude0 = longitude0 * iPI ; //中央经线
+
+
+    X0 = ProjNo*1000000+500000;
+    Y0 = 0;
+    xval = X-X0; yval = Y-Y0; //带内大地坐标
+    e2 = 2*f-f*f;
+    e1 = (1.0-Math.sqrt(1-e2))/(1.0+Math.sqrt(1-e2));
+    ee = e2/(1-e2);
+    M = yval;
+    u = M/(a*(1-e2/4-3*e2*e2/64-5*e2*e2*e2/256));
+    fai = u+(3*e1/2-27*e1*e1*e1/32)*Math.sin(2*u)+(21*e1*e1/16-55*e1*e1*e1*e1/32)*Math.sin(4*u) +(151*e1*e1*e1/96)*
+        Math.sin(6*u)+(1097*e1*e1*e1*e1/512)*Math.sin(8*u);
+    C = ee*Math.cos(fai)*Math.cos(fai);
+    T = Math.tan(fai)*Math.tan(fai);
+    NN = a/Math.sqrt(1.0-e2*Math.sin(fai)*Math.sin(fai));
+    R = a*(1-e2)/Math.sqrt((1-e2*Math.sin(fai)*Math.sin(fai))*(1-e2*Math.sin(fai)*Math.sin(fai))*(1-e2*Math.sin
+    (fai)*Math.sin(fai)));
+    D = xval/NN;
+    //计算经度(Longitude) 纬度(Latitude)
+    longitude1 = longitude0+(D-(1+2*T+C)*D*D*D/6+(5-2*C+28*T-3*C*C+8*ee+24*T*T)*D
+        *D*D*D*D/120)/Math.cos(fai);
+    latitude1 = fai -(NN*Math.tan(fai)/R)*(D*D/2-(5+3*T+10*C-4*C*C-9*ee)*D*D*D*D/24
+        +(61+90*T+298*C+45*T*T-256*ee-3*C*C)*D*D*D*D*D*D/720);
+    //转换为度 DD
+    output[0] = longitude1 / iPI;
+    output[1] = latitude1 / iPI;
+    return output;
+}
+
+//经纬度=>高斯投影
+function BLToGauss(longitude: number, latitude: number){
+    let ProjNo=0;
+    let ZoneWide; //带宽
+    let ret=Array(2);
+    let longitude1,latitude1, longitude0,latitude0, X0,Y0, xval,yval;
+    let a,f, e2,ee, NN, T,C,A, M, iPI;
+    iPI = 0.0174532925199433; 3.1415926535898/180.0;
+    ZoneWide = 6; //6度带宽
+    // a=6378245.0; f=1.0/298.3; //54年北京坐标系参数
+    a=6378140.0; f=1/298.257; //80年西安坐标系参数
+    ProjNo = Math.floor(longitude / ZoneWide) ;
+    longitude0 = ProjNo * ZoneWide + ZoneWide / 2;
+    longitude0 = longitude0 * iPI ;
+    latitude0 = 0;
+    longitude1 = longitude * iPI ; //经度转换为弧度
+    latitude1 = latitude * iPI ; //纬度转换为弧度
+    e2=2*f-f*f;
+    ee=e2*(1.0-e2);
+    NN=a/Math.sqrt(1.0-e2*Math.sin(latitude1)*Math.sin(latitude1));
+    T=Math.tan(latitude1)*Math.tan(latitude1);
+    C=ee*Math.cos(latitude1)*Math.cos(latitude1);
+    A=(longitude1-longitude0)*Math.cos(latitude1);
+    M=a*((1-e2/4-3*e2*e2/64-5*e2*e2*e2/256)*latitude1-(3*e2/8+3*e2*e2/32+45*e2*e2
+        *e2/1024)*Math.sin(2*latitude1)
+        +(15*e2*e2/256+45*e2*e2*e2/1024)*Math.sin(4*latitude1)-(35*e2*e2*e2/3072)*Math.sin(6*latitude1));
+    xval = NN*(A+(1-T+C)*A*A*A/6+(5-18*T+T*T+72*C-58*ee)*A*A*A*A*A/120);
+    yval = M+NN*Math.tan(latitude1)*(A*A/2+(5-T+9*C+4*C*C)*A*A*A*A/24
+        +(61-58*T+T*T+600*C-330*ee)*A*A*A*A*A*A/720);
+    X0 = 1000000*(ProjNo+1)+500000;
+    Y0 = 0;
+    xval = xval+X0; yval = yval+Y0;
+    ret[0]=xval;
+    ret[1]=yval;
+
+    return ret;
+}
+
+export default {
+    GaussToBL,
+    BLToGauss,
+}

+ 121 - 0
src/services/net.service.ts

@@ -0,0 +1,121 @@
+import { injectable, Service } from './service'
+
+/** api接口返回值类型 */
+declare type NetResult = {
+  success: boolean,
+  data: Any
+}
+
+/**
+ * API网络请求服务
+ */
+@injectable
+export default class NetService extends Service {
+  protected url = import.meta.env.VITE_PROXY_URL
+
+  /**
+   * post方法请求接口
+   * @param url 接口地址
+   * @param params 接口参数
+   */
+  post(url: string, params: Any = {}, timeout = 6000): Promise<any> {
+    return this.fetch(url, { method: 'POST', body: JSON.stringify(params) }, timeout)
+  }
+
+  /**
+   * get请求api接口
+   * @param url 接口地址
+   */
+  get(url: string, timeout = 6000): Promise<NetResult> {
+    return this.fetch(url, { method: 'GET' }, timeout)
+  }
+
+  /**
+   * del请求api接口
+   * @param url 接口地址
+   */
+  del(url: string, timeout = 6000): Promise<NetResult> {
+    return this.fetch(url, { method: 'DELETE' }, timeout)
+  }
+
+  /**
+   * post方法请求接口
+   * @param url 接口地址
+   * @param params 接口参数
+   */
+  put(url: string, params: Any = {}, timeout = 6000): Promise<NetResult> {
+    return this.fetch(url, { method: 'PUT', body: JSON.stringify(params) }, timeout)
+  }
+
+  /**
+   * 下载文件
+   * @param url url|blob
+   * @param fileName
+   */
+  downloadFile(url: string | Blob, fileName: string) {
+    const download = (blob: Blob, fileName: string) => {
+      const a = document.createElement('a')
+      document.body.appendChild(a)
+      a.style.display = 'none'
+      // 使用获取到的blob对象创建的url
+      const url = window.URL.createObjectURL(blob)
+      a.href = url
+      // 指定下载的文件名
+      a.download = fileName
+      a.click()
+      document.body.removeChild(a)
+      // 移除blob对象的url
+      window.URL.revokeObjectURL(url)
+    }
+    return new Promise<void>((resolve, reject) => {
+      if (url instanceof Blob) {
+        download(url, fileName)
+        resolve()
+      } else {
+        fetch(url).then((res) => res.blob()).then((blob) => download(blob, fileName)).finally(() => resolve())
+      }
+    })
+  }
+
+  /** token 续期 */
+  async refresh(token: string) {
+    this.post('', { token }).then((res) => {
+      console.log('刷新token', res)
+    })
+  }
+
+  /**
+   * fetch
+   * @param url
+   * @param opt
+   * @param timeout 0 默认不超时
+   * @returns
+   */
+  private fetch(url: string, opt: RequestInit, timeout = 0): Promise<NetResult> {
+    return new Promise((resolve) => {
+      const controller = new AbortController()
+      const { signal } = controller
+      if (timeout) {
+        setTimeout(() => {
+          controller.abort()
+        }, timeout)
+      }
+      fetch(this.url + url, {
+        signal,
+        ...opt,
+        headers: opt.headers || { 'Content-Type': 'application/json' }
+      }).then((res) => {
+        if (res.status === 500) return { success: false, data: '请求错误' }
+        return res.json()
+      }).then((res) => {
+        const obj = { data: res.data, success: res.data instanceof Object }
+        if (!obj.success && obj.data.includes('need authrize')) {
+          throw 401
+        }
+        resolve(obj)
+      }).catch((er) => {
+        throw er
+      })
+    })
+  }
+}

+ 40 - 0
src/services/registerMenu.ts

@@ -0,0 +1,40 @@
+import { Boot } from '@wangeditor/editor'
+import { exp2pdf } from './exportFile'
+console.warn('此插件注册富文本自定义按钮')
+// 注册一个保存按钮
+class SaveBtn {
+  title = ''
+
+  iconSvg = ''
+
+  tag = ''
+
+  constructor() {
+    this.title = '导出PDF'
+    this.iconSvg = '<svg viewBox="0 0 1024 1024" style="width:22px;height:22px;" version="1.1" xmlns="http://www.w3.org/2000/svg" ><path d="M773.696 134.812444l-509.155556 0c-69.76 0-126.520889 56.760889-126.520889 126.542222l0 501.326222c0 69.781333 56.760889 126.499556 126.520889 126.499556l509.141333 0c69.781333 0 126.520889-56.718222 126.520889-126.499556L900.202667 261.361778C900.202667 191.573333 843.441778 134.833778 773.696 134.812444zM324.437333 184.213333l389.347556 0 0 279.608889L324.437333 463.822222 324.437333 184.213333zM850.872889 762.680889c0 42.552889-34.616889 77.191111-77.169778 77.191111l-509.155556 0c-42.552889 0-77.169778-34.638222-77.169778-77.191111L187.377778 261.383111c0-42.574222 34.616889-77.169778 77.169778-77.169778l0-0.021333 10.567111 0 0 329.009778 488.007111 0 0.021333 0L763.143111 184.184889l10.567111 0c42.56 0 77.169778 34.595556 77.169778 77.169778L850.88 762.680889zM591.772444 256.832l49.329778 0 0 164.522667-49.329778 0 0-164.522667ZM591.772444 256.832"></path></svg>'
+    this.tag = 'button'
+  }
+
+  getValue() {
+    return ''
+  }
+
+  isActive() {
+    return false
+  }
+
+  isDisabled() {
+    return false
+  }
+
+  exec() {
+    exp2pdf('exportPDF', `测试${new Date().toLocaleDateString()}`)
+    console.log('导出')
+  }
+}
+Boot.registerMenu({
+  key: 'SaveBtn',
+  factory() {
+    return new SaveBtn()
+  }
+})

+ 64 - 0
src/services/service.ts

@@ -0,0 +1,64 @@
+export class ServiceError extends Error {
+  code?: number
+
+  origin?: string
+
+  constructor(message: string, origin?: string, code?: number) {
+    super(message)
+    this.code = code
+    this.origin = origin
+    this.stack = `${this.message}\n${this.origin}\n${this.code || ''}`
+  }
+
+  toString() {
+    return this.message
+  }
+}
+
+export class Service {
+  throw(message: string, origin?: string, code?: number) {
+    throw new ServiceError(message, origin, code)
+  }
+}
+
+export function injectable<T extends { new(..._args: any[]): {} }> (Ctor: T) {
+  let instance!: any
+  return new Proxy(Ctor, {
+    construct(t, args) {
+      if (!instance) {
+        instance = new Ctor(args)
+        // console.log('instance ' + Ctor.name)
+      }
+      return instance
+    }
+  })
+}
+const runnerMap: { [key: string]: ((_res: any) => void)[] | undefined } = {}
+/**
+   * 互斥注解
+   * 用于保证某个方法同一时间只有单次调用
+   */
+export function mutex(target: any, property: string) {
+  const oriFn = target[property]
+  const funcKey = `${target.constructor.name}-${property}`
+  Object.defineProperty(target, property, {
+    async value(...args: any[]) {
+      const key = funcKey + JSON.stringify(args)
+      if (runnerMap[key]) {
+        return await new Promise((res) => {
+          runnerMap[key]?.push((result: any) => res(result))
+        })
+      }
+      runnerMap[key] = []
+
+      setTimeout(() => {
+        runnerMap[key] = undefined
+      }, 4000)
+      const res = await Reflect.apply(oriFn, this, args || [])
+      runnerMap[key]?.forEach((fn) => fn(res))
+      runnerMap[key] = undefined
+      return res
+    }
+  })
+  return target[property]
+}

+ 0 - 20
src/utils/axios.js

@@ -1,20 +0,0 @@
-import axios from 'axios'
-// http request 拦截
-axios.interceptors.request.use(
-  config => {
-    return config
-  },
-  err => {
-    return Promise.reject(err)
-  }
-)
-// http response 拦截
-axios.interceptors.response.use(
-  response => {
-    return response.data
-  },
-  error => {
-    return Promise.reject(error)
-  }
-)
-export default axios

+ 0 - 143
src/utils/html2File.ts

@@ -1,143 +0,0 @@
-import html2canvas from "html2canvas";
-import JSPDF from "jspdf";
-import { getActivePinia } from "pinia";
-
-/**
- * loading
- * @param type 是否显示
- */
-const resetLoaing = (type: boolean) => {
-    const store = getActivePinia()
-    if (!store) return
-    const obj = store.state.value
-    for (const key in obj) {
-        const el = obj[key]
-        if ('loading' in el) {
-            el.loading = type
-            break
-        }
-    }
-
-}
-
-/**
- * 导出PDF
- * @param domID 需要输出PDF的页面id
- * @param fileName 文件名
- * @param type  默认A4分页
- * @returns 
- */
-export const exp2pdf = async (domID: string, fileName: string, type = 'A4') => {
-    const dom = document.getElementById(domID)
-    if (!dom) return
-    resetLoaing(true)
-    const canvas = await html2canvas(dom, {
-        logging: false,
-        useCORS: true, // 允许图片跨域   
-        scale: 1.5
-    })
-
-    if (type === 'A4') {
-        // A4分页
-        const pdf = new JSPDF("p", "mm", "a4") // A4纸,纵向
-        const ctx = canvas.getContext("2d") as any
-        const a4w = 200;
-        const a4h = 277 // A4大小,210mm x 297mm,四边各保留20mm的边距
-        const imgHeight = Math.floor(a4h * canvas.width / a4w) // 按A4显示比例换算一页图像的像素高度
-        let renderedHeight = 0
-        while (renderedHeight < canvas.height) {
-            const page = document.createElement("canvas")
-            page.width = canvas.width
-            page.height = Math.min(imgHeight, canvas.height - renderedHeight) // 可能内容不足一页
-            // 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
-            page.getContext("2d", { willReadFrequently: true })?.putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0)
-            pdf.addImage(page.toDataURL("image/jpeg", 1.0), "JPEG", 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width)) // 添加图像到页面,保留10mm边距
-            renderedHeight += imgHeight
-            if (renderedHeight < canvas.height) { pdf.addPage() } // 如果后面还有内容,添加一个空页
-            // delete page;
-        }
-        pdf.save(fileName)
-
-    } else {
-        // 整张
-        const domHeight = dom.offsetHeight // 获取DOM高度
-        const domWidth = dom.offsetWidth // 获取DOM宽度        
-        const pdf = new JSPDF('p', 'px', [domWidth, domHeight])
-        pdf.addImage(canvas.toDataURL("image/jpeg", 1.0), "JPEG", 10, 10, domWidth, domHeight)
-        pdf.save(fileName)
-    }
-    resetLoaing(false)
-}
-
-/**
- * 导出PNG
- * @param domID 需要输出PNG的页面id
- * @param fileName 文件名
- * @param bkcolor 背景色
- */
-export const exp2png = async (domID: string, fileName: string, bkcolor: string) => {
-    resetLoaing(true)
-    window.scroll(0, 0) // 首先先顶部
-    const design = document.getElementById(domID) as HTMLElement
-    if (!design) return
-    const imgHeight = design.offsetHeight // 获取DOM高度
-    const imgWidth = design.offsetWidth // 获取DOM宽度
-    const scale = window.devicePixelRatio <= 3 ? 3 : window.devicePixelRatio // 获取设备像素比
-    const canvas = await html2canvas(design, {
-        backgroundColor: bkcolor, // 设置背景颜色
-        useCORS: true, // 允许图片跨域
-        scale: scale, // 缩放3倍,使得图片更加清晰=>越清晰图片越大
-        width: imgWidth,
-        height: imgHeight,
-        imageTimeout: 5000 // 设置图片的超时,设置0为禁用
-    })
-    const download = (url: string, fileName: string) => {
-        let aLink = document.createElement('a')
-        aLink.href = url
-        aLink.download = fileName || '' // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
-        let event
-        if (window.MouseEvent) event = new MouseEvent('click')
-        else {
-            event = document.createEvent('MouseEvents')
-            event.initMouseEvent(
-                'click',
-                true,
-                false,
-                window,
-                0,
-                0,
-                0,
-                0,
-                0,
-                false,
-                false,
-                false,
-                false,
-                0,
-                null
-            )
-        }
-        aLink.dispatchEvent(event)
-    }
-    // 两种下载方式url + blob
-    let imgURL = canvas.toDataURL('image/png') as any
-    if (typeof imgURL === 'object' && imgURL instanceof Blob) {
-        imgURL = URL.createObjectURL(imgURL) // 创建blob地址
-        download(imgURL, fileName)
-    } else {
-        // url  +  请求得到blob
-        let htmlrq = new XMLHttpRequest() as any
-        htmlrq.open('GET', imgURL, true)
-        htmlrq.responseType = 'blob'
-        htmlrq.onload = function (e: any) {
-            if (e.target.status === 200) {
-                imgURL = URL.createObjectURL(e.target.response) // 创建blob地址
-                download(imgURL, fileName)
-            } else {
-                console.error('下载错误')
-            }
-        }
-        htmlrq.send()
-    }
-    resetLoaing(false)
-}

+ 0 - 277
src/utils/move.js

@@ -1,277 +0,0 @@
-class moveServer {
-    constructor() {
-        this.movedom = null
-        this.showdom = null
-        this.movedomPos = null
-        this.rightDom = null
-        this.callBack = null
-        this.num = 0
-        this.tranList = []
-    }
-
-    /**
-     * 鼠标按下
-     * @param {Object} event 
-     */
-    mousdown(event) {
-        try {
-            const e = event || window.event
-            this.movedomPos = this.movedom.getBoundingClientRect()
-            const x = e.pageX - this.movedomPos.left
-            const y = e.pageY - this.movedomPos.top
-            const dom = e.target
-            const type = dom.getAttribute('type')
-            // 区分左右键
-            if (e.button !== 2) {
-
-                // 传感器点击
-                if (type === 'transducer' || type === 'transItem') {
-                    if (type === 'transducer') {
-
-                        // 新增移动样式可修改成元器件样式
-                        const txt = document.createElementNS('http://www.w3.org/2000/svg', 'text')
-                        txt.innerHTML = dom.innerHTML
-
-                        // 当前元素的宽
-                        const t = txt.getBoundingClientRect()
-                        const tw = x - t.width / 2
-                        const th = y + t.height / 2
-                        const transform = `translate(${tw},${th}) rotate(0)`
-                        txt.setAttributeNS(null, 'transform', transform)
-                        txt.setAttributeNS(null, 'type', 'transItem')
-                        txt.setAttributeNS(null, '_id', this.num) //唯一ID
-                        this.movedom.appendChild(txt)
-                        this.showdom = txt
-
-                        // 传感器信息
-                        const obj = {
-                            name: dom.innerHTML,
-                            transform: transform,
-                            _id: this.num
-                        }
-                        this.tranList.push(obj)
-                        this.num += 1
-
-                    } else if (type === 'transItem') {
-                        // 切换showdom
-                        this.showdom = dom
-                        const transform = dom.getAttribute('transform')
-                        const arr = transform.split(' ')
-
-                        const newtransform = `translate(${x},${y}) ${arr[1]}`
-                        this.showdom.setAttributeNS(null, 'transform', newtransform)
-
-                    }
-                    // 监听移动
-                    this.movedom.onmousemove = this.mousmove.bind(this)
-                    this.movedom.onmouseup = this.mousup.bind(this)
-
-                } else if (type === 'RmenuButton') {
-
-                    // 右键确认点击
-                    const id = +this.showdom.getAttribute('_id')
-                    const rotate = this.rightDom.getElementsByTagName("input")[0].value
-                    const transform = this.showdom.getAttribute('transform')
-                    const arr = transform.split(' ')
-
-                    let newStr = arr[0]
-                    newStr = newStr.replace('translate(', '').replace(')', '')
-                    const newArr = newStr.split(',')
-
-                    const txtW = +(this.showdom.getBoundingClientRect().width) / 2
-                    const h1 = txtW * Math.cos(rotate / 180 * Math.PI)
-                    const h2 = txtW * Math.sin(rotate / 180 * Math.PI)
-                    const newX = txtW - h1 + +newArr[0]
-                    const newY = +newArr[1] - h2
-
-                    const newtransform = `translate(${newX},${newY}) rotate(${rotate})`
-                    this.showdom.setAttributeNS(null, 'transform', newtransform)
-
-
-                    this.tranList.forEach(el => {
-                        if (el._id === id) {
-                            el.transform = newtransform
-                        }
-                    })
-
-                    // 清除
-                    this.movedom.parentNode.removeChild(this.rightDom)
-                    this.rightDom.onmousedown = null
-                    this.rightDom.oncontextmenu = null
-                    this.rightDom = null
-
-                    // 回调
-                    this.callBack(this.tranList)
-
-
-                } else if (type === 'Rmenu') {
-
-
-                    this.movedom.parentNode.removeChild(this.rightDom)
-                    this.rightDom.onmousedown = null
-                    this.rightDom.oncontextmenu = null
-                    this.rightDom = null
-                }
-
-            } else {
-                // 右键菜单
-                if (type === 'transItem') {
-                    if (this.rightDom) {
-                        this.movedom.parentNode.removeChild(this.rightDom)
-                        this.rightDom = null
-                    }
-
-                    this.rightDom = document.createElement('div')
-                    this.rightDom.style.position = 'absolute'
-                    this.rightDom.style.background = 'black'
-                    this.rightDom.style.borderRadius = '5px'
-                    this.rightDom.style.padding = '5px'
-                    this.rightDom.style.color = 'red'
-                    this.rightDom.innerText = '旋转角度:'
-                    this.rightDom.style.left = e.pageX + 'px'
-                    this.rightDom.style.top = e.pageY + 'px'
-                    this.rightDom.setAttribute('type', 'Rmenu')
-                    this.rightDom.style.zIndex = 9
-
-                    const input = document.createElement('input')
-                    input.style.width = '80px'
-                    input.setAttribute('type', 'number')
-                    input.setAttribute('id', 'inputNumber')
-                    this.rightDom.appendChild(input)
-
-                    const button = document.createElement('button')
-                    button.innerText = '确定'
-                    button.style.margin = '0 0 0 10px'
-                    button.style.color = 'white'
-                    button.style.background = '#2db7f5'
-                    button.style.border = 'none'
-                    button.style.borderRadius = '5px'
-
-                    button.setAttribute('type', 'RmenuButton')
-                    this.rightDom.appendChild(button)
-                    // 单独增加点击事件
-                    this.rightDom.onmousedown = this.mousdown.bind(this)
-                    this.rightDom.oncontextmenu = function (e) {
-                        e.preventDefault()
-                    };
-                    this.showdom = dom
-                    // 父级DIV添加
-                    this.movedom.parentNode.appendChild(this.rightDom)
-                }
-            }
-
-        } catch (error) {
-            console.error('鼠标按下', error);
-        }
-    }
-
-    /**
-     * 移动
-     * 实时获取dom
-     * @param event
-     */
-    mousmove(event) {
-        const e = event || window.event
-        const x = e.pageX - this.movedomPos.left
-        const y = e.pageY - this.movedomPos.top
-        const id = +this.showdom.getAttribute('_id')
-
-        // 移除
-        if (x >= this.movedomPos.width - 10 || y >= this.movedomPos.height - 10) {
-
-            let newarr = []
-            this.tranList.forEach(el => {
-                if (el._id !== id) {
-                    newarr.push(el)
-                }
-            })
-
-            this.callBack(newarr)
-            this.tranList = newarr
-            this.movedom.removeChild(this.showdom)
-            this.movedom.onmousemove = null
-            this.movedom.onmouseup = null
-        }
-
-        // 位置
-        const transform = this.showdom.getAttribute('transform')
-        const arr = transform.split(' ')
-
-        const newtransform = `translate(${x},${y}) ${arr[1]}`
-        this.showdom.setAttributeNS(null, 'transform', newtransform)
-
-    }
-
-    /**
-     * 鼠标松开
-     * @param event
-     */
-    mousup(event) {
-        try {
-            const e = event || window.event
-            const id = +(this.showdom.getAttribute('_id'))
-            const transform = this.showdom.getAttribute('transform')
-
-            this.tranList.forEach(el => {
-                if (el._id === id) {
-                    el.transform = transform
-                }
-            })
-
-            this.movedom.onmousemove = null
-            this.movedom.onmouseup = null
-            // 回调
-            this.callBack(this.tranList)
-        } catch (error) {
-            console.error('鼠标松开', error);
-        }
-    }
-
-    /**
-     * 监听dom
-     * @param {HTMLElement} dom 监听元素
-     * @param {Function} callBack 回调函数
-     */
-    on(dom, callBack) {
-        const isdom = this.isElement(dom)
-        if (isdom) {
-            this.callBack = callBack
-            this.movedom = dom
-            this.movedomPos = dom.getBoundingClientRect()
-            // 去掉右键
-            this.movedom.oncontextmenu = function (e) {
-                e.preventDefault()
-            };
-            this.movedom.onmousedown = this.mousdown.bind(this)
-        } else {
-            alert('无效的dom元素')
-        }
-    }
-
-    /**
-     * 清除
-     */
-    off() {
-        this.movedom.onmousedown = null
-        this.movedom.onmousemove = null
-        this.movedom.onmouseup = null
-        this.movedom.oncontextmenu = null
-        this.movedom = null
-        this.showdom = null
-        this.movedomPos = null
-        this.rightDom = null
-        this.callBack = null
-        this.num = 0
-        this.tranList = []
-    }
-
-    /**
-     * 判断是否是DOM
-     */
-    isElement(obj) {
-        return (typeof HTMLElement === 'object')
-            ? (obj instanceof HTMLElement)
-            : !!(obj && typeof obj === 'object' && (obj.nodeType === 1 || obj.nodeType === 9) && typeof obj.nodeName === 'string');
-    }
-}
-export default new moveServer()

+ 6 - 4
src/vite-env.d.ts

@@ -1,10 +1,12 @@
 /// <reference types="vite/client" />
 /// <reference types="vite/client" />
 
 
+/** 代指任意类型 请不要随意使用 */
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+declare type Any = any
+
 declare module '*.vue' {
 declare module '*.vue' {
   import type { DefineComponent } from 'vue'
   import type { DefineComponent } from 'vue'
-  const component: DefineComponent<{}, {}, any>
+  const component: DefineComponent<{}, {}, Any>
   export default component
   export default component
 }
 }
-declare module 'js-md5'
-declare module '@/utils/*'
-declare module 'socket.io-client'
+

+ 8 - 2
tsconfig.json

@@ -2,6 +2,7 @@
   "compilerOptions": {
   "compilerOptions": {
     "target": "ESNext",
     "target": "ESNext",
     "useDefineForClassFields": true,
     "useDefineForClassFields": true,
+    "experimentalDecorators": true,
     "module": "ESNext",
     "module": "ESNext",
     "moduleResolution": "Node",
     "moduleResolution": "Node",
     "strict": true,
     "strict": true,
@@ -10,12 +11,17 @@
     "resolveJsonModule": true,
     "resolveJsonModule": true,
     "isolatedModules": true,
     "isolatedModules": true,
     "esModuleInterop": true,
     "esModuleInterop": true,
-    "allowJs": true,
     "lib": [
     "lib": [
       "ESNext",
       "ESNext",
       "DOM"
       "DOM"
     ],
     ],
-    "skipLibCheck": true
+    "skipLibCheck": true,
+    "baseUrl": "./",
+    "paths": {
+      "@/*": [
+        "src/*"
+      ]
+    },
   },
   },
   "include": [
   "include": [
     "src/**/*.ts",
     "src/**/*.ts",

+ 72 - 48
vite.config.ts

@@ -1,14 +1,16 @@
-import { defineConfig } from 'vite'
+/* eslint-disable import/no-extraneous-dependencies */
+import { defineConfig, loadEnv } from 'vite'
 import vue from '@vitejs/plugin-vue'
 import vue from '@vitejs/plugin-vue'
 import eslint from 'vite-plugin-eslint'
 import eslint from 'vite-plugin-eslint'
 import viteCompression from 'vite-plugin-compression'
 import viteCompression from 'vite-plugin-compression'
-import path from 'path'
+import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
+import { resolve } from 'path'
 import fs from 'fs'
 import fs from 'fs'
 import sizeOf from 'image-size'
 import sizeOf from 'image-size'
 // 获取CAD图片大小
 // 获取CAD图片大小
-const getImgSize =  ()=> {
+const getImgSize = () => {
   try {
   try {
-    const divs = path.resolve('./public/CAD_1')
+    const divs = resolve('./public/CAD_1')
     const fileName = fs.readdirSync(divs) as any
     const fileName = fs.readdirSync(divs) as any
     if (!fileName || !fileName.length) return {}
     if (!fileName || !fileName.length) return {}
     const max = Math.max(...fileName)
     const max = Math.max(...fileName)
@@ -35,54 +37,76 @@ const getImgSize =  ()=> {
     }
     }
     return obj
     return obj
   } catch (error) {
   } catch (error) {
-    return {W:0,H:0,S:0,M:0}
+    return { W: 0, H: 0, S: 0, M: 0 }
   }
   }
 }
 }
 // https://vitejs.dev/config/
 // https://vitejs.dev/config/
-export default defineConfig({
-  base: './',
-  resolve: {
-    alias: {
-      /*
-        路径别名
-        若为文件系统路径必须是绝对路径的形式,否则将以别名原样呈现,不会解析为文件系统路径路径
-      */
-      '@': path.resolve(__dirname, './src')
-    }
-  },
-  plugins: [vue(), viteCompression(), eslint({ fix: true, include: ['**/*.ts', '**/*.vue'] })],
-  server: {
-    host: '0.0.0.0',
-    port: 8585,
-    open: true,
-    strictPort: false,
-    https: false
-  },
-  esbuild: {
-    drop: ['debugger'] //build 移除打印
-  },
-  build: {
-    rollupOptions: {
-      input: {
-        index: path.resolve(__dirname, 'index.html')
-      },
-      output: { // 静态资源分类打包
-        chunkFileNames: 'js/[hash].js',
-        entryFileNames: 'js/[hash].js',
-        assetFileNames: 'assets/[ext]/[hash].[ext]',
-        // 拆分node_modules包
-        manualChunks: (id: any) => {
-          if (id.includes("node_modules")) {
-            return id.toString().split("node_modules/")[1].split("/")[0].toString()
+export default ({ mode }) => {
+  const env = loadEnv(mode, process.cwd())
+  return defineConfig({
+    base: './',
+    resolve: {
+      alias: {
+        /*
+          路径别名
+          若为文件系统路径必须是绝对路径的形式,否则将以别名原样呈现,不会解析为文件系统路径路径
+        */
+        '@': resolve(__dirname, './src')
+      }
+    },
+    plugins: [
+      vue(), viteCompression(),
+      eslint({ fix: true, include: ['**/*.ts', '**/*.vue'] }),
+      createSvgIconsPlugin({
+        iconDirs: [resolve(__dirname, './src/assets/icons')],
+        // Specify symbolId format
+        symbolId: 'icon-[dir]-[name]'
+      })
+    ],
+    server: {
+      host: '0.0.0.0',
+      port: 6888,
+      open: true,
+      strictPort: false,
+      // proxy: {
+      //   '/api': {
+      //     target: env.VITE_PROXY_URL,
+      //     changeOrigin: true,
+      //     rewrite: (path) => path.replace(/^\/api/, ''),
+      //     secure: false,
+      //     headers: {
+      //       Referer: 'https://example.com'
+      //     }
+      //   }
+      // }
+    },
+    esbuild: {
+      drop: ['debugger'] // build 移除打印
+    },
+    build: {
+      rollupOptions: {
+        input: {
+          index: resolve(__dirname, 'index.html')
+        },
+        output: { // 静态资源分类打包
+          chunkFileNames: 'js/[hash].js',
+          entryFileNames: 'js/[hash].js',
+          assetFileNames: 'assets/[ext]/[hash].[ext]',
+          // 拆分node_modules包
+          manualChunks: (id: any) => {
+            if (id.includes('node_modules')) {
+              return id.toString().split('node_modules/')[1].split('/')[0].toString()
+            }
+            return ''
           }
           }
         }
         }
       }
       }
-    }
-  },
-  define: {
-    'process.env': {
-      imgSize: getImgSize()
     },
     },
-    __VUE_OPTIONS_API__: true
-  }
-})
+    define: {
+      'process.env': {
+        imgSize: getImgSize()
+      },
+      __VUE_OPTIONS_API__: false
+    }
+  })
+}