li.shaoyi 3 anni fa
parent
commit
70e32a3378
100 ha cambiato i file con 2217 aggiunte e 462 eliminazioni
  1. 337 91
      package-lock.json
  2. 3 1
      package.json
  3. 5 0
      public/language/en.json
  4. 5 0
      public/language/zh-cn.json
  5. 0 0
      public/tinymce/icons/default/icons.min.js
  6. 3 0
      public/tinymce/langs/README.md
  7. 6 0
      public/tinymce/langs/zh-Hans.js
  8. 21 0
      public/tinymce/license.txt
  9. 3 0
      public/tinymce/models/dom/model.min.js
  10. 3 0
      public/tinymce/plugins/advlist/plugin.min.js
  11. 3 0
      public/tinymce/plugins/anchor/plugin.min.js
  12. 3 0
      public/tinymce/plugins/autolink/plugin.min.js
  13. 3 0
      public/tinymce/plugins/autoresize/plugin.min.js
  14. 3 0
      public/tinymce/plugins/autosave/plugin.min.js
  15. 3 0
      public/tinymce/plugins/charmap/plugin.min.js
  16. 4 0
      public/tinymce/plugins/code/plugin.min.js
  17. 3 0
      public/tinymce/plugins/codesample/plugin.min.js
  18. 3 0
      public/tinymce/plugins/directionality/plugin.min.js
  19. 0 0
      public/tinymce/plugins/emoticons/js/emojiimages.js
  20. 2 0
      public/tinymce/plugins/emoticons/js/emojiimages.min.js
  21. 0 0
      public/tinymce/plugins/emoticons/js/emojis.js
  22. 1 0
      public/tinymce/plugins/emoticons/js/emojis.min.js
  23. 3 0
      public/tinymce/plugins/emoticons/plugin.min.js
  24. 3 0
      public/tinymce/plugins/fullscreen/plugin.min.js
  25. 3 0
      public/tinymce/plugins/help/plugin.min.js
  26. 3 0
      public/tinymce/plugins/image/plugin.min.js
  27. 3 0
      public/tinymce/plugins/importcss/plugin.min.js
  28. 3 0
      public/tinymce/plugins/insertdatetime/plugin.min.js
  29. 3 0
      public/tinymce/plugins/link/plugin.min.js
  30. 3 0
      public/tinymce/plugins/lists/plugin.min.js
  31. 3 0
      public/tinymce/plugins/media/plugin.min.js
  32. 4 0
      public/tinymce/plugins/nonbreaking/plugin.min.js
  33. 4 0
      public/tinymce/plugins/pagebreak/plugin.min.js
  34. 4 0
      public/tinymce/plugins/preview/plugin.min.js
  35. 3 0
      public/tinymce/plugins/quickbars/plugin.min.js
  36. 4 0
      public/tinymce/plugins/save/plugin.min.js
  37. 3 0
      public/tinymce/plugins/searchreplace/plugin.min.js
  38. 3 0
      public/tinymce/plugins/table/plugin.min.js
  39. 3 0
      public/tinymce/plugins/template/plugin.min.js
  40. 4 0
      public/tinymce/plugins/visualblocks/plugin.min.js
  41. 3 0
      public/tinymce/plugins/visualchars/plugin.min.js
  42. 3 0
      public/tinymce/plugins/wordcount/plugin.min.js
  43. 1 0
      public/tinymce/skins/content/dark/content.min.css
  44. 1 0
      public/tinymce/skins/content/default/content.min.css
  45. 1 0
      public/tinymce/skins/content/document/content.min.css
  46. 1 0
      public/tinymce/skins/content/tinymce-5-dark/content.min.css
  47. 1 0
      public/tinymce/skins/content/tinymce-5/content.min.css
  48. 1 0
      public/tinymce/skins/content/writer/content.min.css
  49. 0 0
      public/tinymce/skins/ui/oxide-dark/content.inline.min.css
  50. 0 0
      public/tinymce/skins/ui/oxide-dark/content.min.css
  51. 0 0
      public/tinymce/skins/ui/oxide-dark/skin.min.css
  52. 1 0
      public/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css
  53. 0 0
      public/tinymce/skins/ui/oxide/content.inline.min.css
  54. 0 0
      public/tinymce/skins/ui/oxide/content.min.css
  55. 0 0
      public/tinymce/skins/ui/oxide/skin.min.css
  56. 1 0
      public/tinymce/skins/ui/oxide/skin.shadowdom.min.css
  57. 0 0
      public/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css
  58. 0 0
      public/tinymce/skins/ui/tinymce-5-dark/content.min.css
  59. 0 0
      public/tinymce/skins/ui/tinymce-5-dark/skin.min.css
  60. 1 0
      public/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.min.css
  61. 0 0
      public/tinymce/skins/ui/tinymce-5/content.inline.min.css
  62. 0 0
      public/tinymce/skins/ui/tinymce-5/content.min.css
  63. 0 0
      public/tinymce/skins/ui/tinymce-5/skin.min.css
  64. 1 0
      public/tinymce/skins/ui/tinymce-5/skin.shadowdom.min.css
  65. 3 0
      public/tinymce/themes/silver/theme.min.js
  66. 977 0
      public/tinymce/tinymce.d.ts
  67. 3 0
      public/tinymce/tinymce.min.js
  68. 4 14
      src/business/account/index.ts
  69. 18 0
      src/business/admin/index.ts
  70. 47 2
      src/business/common/index.ts
  71. 49 0
      src/business/customer/index.ts
  72. 15 7
      src/components/base/modal/index.less
  73. 40 14
      src/components/base/modal/index.vue
  74. 0 79
      src/components/base/tab-component/index.ts
  75. 0 36
      src/components/base/tab-component/index.vue
  76. 0 12
      src/components/base/tab-component/interface.ts
  77. 11 11
      src/components/base/tab/index.less
  78. 3 3
      src/components/base/tab/index.vue
  79. 47 0
      src/components/base/table/index.vue
  80. 14 14
      src/constants/enum/chart.ts
  81. 9 0
      src/constants/enum/customer.ts
  82. 5 2
      src/constants/enum/index.ts
  83. 18 0
      src/constants/enum/language.ts
  84. 61 0
      src/constants/enum/menu.ts
  85. 4 4
      src/constants/enum/theme.ts
  86. 18 2
      src/filters/index.ts
  87. 123 0
      src/hooks/auth/index.ts
  88. 23 0
      src/hooks/auth/interface.ts
  89. 3 3
      src/hooks/component/index.ts
  90. 85 0
      src/hooks/datatable/index.ts
  91. 11 8
      src/hooks/datatable/interface.ts
  92. 1 4
      src/hooks/echarts/candlestick/dataset.ts
  93. 6 6
      src/hooks/echarts/candlestick/index.ts
  94. 38 11
      src/hooks/echarts/candlestick/options.ts
  95. 1 4
      src/hooks/echarts/timeline/dataset.ts
  96. 34 20
      src/hooks/echarts/timeline/options.ts
  97. 0 79
      src/hooks/menu/index.ts
  98. 0 10
      src/hooks/menu/interface.ts
  99. 19 12
      src/hooks/theme/index.ts
  100. 38 13
      src/mock/account.ts

+ 337 - 91
package-lock.json

@@ -8,12 +8,13 @@
       "name": "mtp2_h5_plus",
       "version": "0.1.0",
       "dependencies": {
+        "@tinymce/tinymce-vue": "^5.0.0",
         "axios": "^0.26.1",
         "core-js": "^3.8.3",
         "crypto-js": "^4.1.1",
         "default-passive-events": "^2.0.0",
         "echarts": "^5.3.2",
-        "element-plus": "^2.1.9",
+        "element-plus": "^2.2.8",
         "long": "^5.2.0",
         "moment": "^2.29.3",
         "protobufjs": "^6.11.2",
@@ -22,6 +23,7 @@
         "vant": "^3.4.8",
         "vue": "^3.2.13",
         "vue-class-component": "^8.0.0-0",
+        "vue-i18n": "^9.1.10",
         "vue-router": "^4.0.3",
         "vuedraggable": "^4.1.0"
       },
@@ -1695,9 +1697,9 @@
       }
     },
     "node_modules/@element-plus/icons-vue": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-1.1.4.tgz",
-      "integrity": "sha512-Iz/nHqdp1sFPmdzRwHkEQQA3lKvoObk8azgABZ81QUOpW9s/lUyQVUSh0tNtEPZXQlKwlSh7SPgoVxzrE0uuVQ==",
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.0.6.tgz",
+      "integrity": "sha512-lPpG8hYkjL/Z97DH5Ei6w6o22Z4YdNglWCNYOPcB33JCF2A4wye6HFgSI7hEt9zdLyxlSpiqtgf9XcYU+m5mew==",
       "peerDependencies": {
         "vue": "^3.2.0"
       }
@@ -1759,16 +1761,16 @@
       }
     },
     "node_modules/@floating-ui/core": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.6.1.tgz",
-      "integrity": "sha512-Y30eVMcZva8o84c0HcXAtDO4BEzPJMvF6+B7x7urL2xbAqVsGJhojOyHLaoQHQYjb6OkqRq5kO+zeySycQwKqg=="
+      "version": "0.7.3",
+      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz",
+      "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg=="
     },
     "node_modules/@floating-ui/dom": {
-      "version": "0.4.4",
-      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.4.4.tgz",
-      "integrity": "sha512-0Ulu3B/dqQplUUSqnTx0foSrlYuMN+GTtlJWvNJwt6Fr7/PqmlR/Y08o6/+bxDWr6p3roBJRaQ51MDZsNmEhhw==",
+      "version": "0.5.4",
+      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz",
+      "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==",
       "dependencies": {
-        "@floating-ui/core": "^0.6.1"
+        "@floating-ui/core": "^0.7.3"
       }
     },
     "node_modules/@hapi/hoek": {
@@ -1806,6 +1808,96 @@
       "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
       "dev": true
     },
+    "node_modules/@intlify/core-base": {
+      "version": "9.1.10",
+      "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.10.tgz",
+      "integrity": "sha512-So9CNUavB/IsZ+zBmk2Cv6McQp6vc2wbGi1S0XQmJ8Vz+UFcNn9MFXAe9gY67PreIHrbLsLxDD0cwo1qsxM1Nw==",
+      "dependencies": {
+        "@intlify/devtools-if": "9.1.10",
+        "@intlify/message-compiler": "9.1.10",
+        "@intlify/message-resolver": "9.1.10",
+        "@intlify/runtime": "9.1.10",
+        "@intlify/shared": "9.1.10",
+        "@intlify/vue-devtools": "9.1.10"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@intlify/devtools-if": {
+      "version": "9.1.10",
+      "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.1.10.tgz",
+      "integrity": "sha512-SHaKoYu6sog3+Q8js1y3oXLywuogbH1sKuc7NSYkN3GElvXSBaMoCzW+we0ZSFqj/6c7vTNLg9nQ6rxhKqYwnQ==",
+      "dependencies": {
+        "@intlify/shared": "9.1.10"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@intlify/message-compiler": {
+      "version": "9.1.10",
+      "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.1.10.tgz",
+      "integrity": "sha512-+JiJpXff/XTb0EadYwdxOyRTB0hXNd4n1HaJ/a4yuV960uRmPXaklJsedW0LNdcptd/hYUZtCkI7Lc9J5C1gxg==",
+      "dependencies": {
+        "@intlify/message-resolver": "9.1.10",
+        "@intlify/shared": "9.1.10",
+        "source-map": "0.6.1"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@intlify/message-compiler/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/@intlify/message-resolver": {
+      "version": "9.1.10",
+      "resolved": "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.10.tgz",
+      "integrity": "sha512-5YixMG/M05m0cn9+gOzd4EZQTFRUu8RGhzxJbR1DWN21x/Z3bJ8QpDYj6hC4FwBj5uKsRfKpJQ3Xqg98KWoA+w==",
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@intlify/runtime": {
+      "version": "9.1.10",
+      "resolved": "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.1.10.tgz",
+      "integrity": "sha512-7QsuByNzpe3Gfmhwq6hzgXcMPpxz8Zxb/XFI6s9lQdPLPe5Lgw4U1ovRPZTOs6Y2hwitR3j/HD8BJNGWpJnOFA==",
+      "dependencies": {
+        "@intlify/message-compiler": "9.1.10",
+        "@intlify/message-resolver": "9.1.10",
+        "@intlify/shared": "9.1.10"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@intlify/shared": {
+      "version": "9.1.10",
+      "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.10.tgz",
+      "integrity": "sha512-Om54xJeo1Vw+K1+wHYyXngE8cAbrxZHpWjYzMR9wCkqbhGtRV5VLhVc214Ze2YatPrWlS2WSMOWXR8JktX/IgA==",
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@intlify/vue-devtools": {
+      "version": "9.1.10",
+      "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.1.10.tgz",
+      "integrity": "sha512-5l3qYARVbkWAkagLu1XbDUWRJSL8br1Dj60wgMaKB0+HswVsrR6LloYZTg7ozyvM621V6+zsmwzbQxbVQyrytQ==",
+      "dependencies": {
+        "@intlify/message-resolver": "9.1.10",
+        "@intlify/runtime": "9.1.10",
+        "@intlify/shared": "9.1.10"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
     "node_modules/@jridgewell/resolve-uri": {
       "version": "3.0.5",
       "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz",
@@ -2065,6 +2157,17 @@
       "integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==",
       "dev": true
     },
+    "node_modules/@tinymce/tinymce-vue": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/@tinymce/tinymce-vue/-/tinymce-vue-5.0.0.tgz",
+      "integrity": "sha512-1HRCNa2eGdztOKShYAiHIry50LTU6YJG//qSP9AJElrXhb3BIBN0Bef6E56nZObVgwCgSmI4cnX35VU9D49aow==",
+      "dependencies": {
+        "tinymce": "^6.0.0 || ^5.5.1"
+      },
+      "peerDependencies": {
+        "vue": "^3.0.0"
+      }
+    },
     "node_modules/@trysound/sax": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
@@ -2189,9 +2292,9 @@
       "dev": true
     },
     "node_modules/@types/lodash": {
-      "version": "4.14.181",
-      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.181.tgz",
-      "integrity": "sha512-n3tyKthHJbkiWhDZs3DkhkCzt2MexYHXlX0td5iMplyfwketaOeKboEVBqzceH7juqvEg3q5oUoBFxSLu7zFag=="
+      "version": "4.14.182",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
+      "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q=="
     },
     "node_modules/@types/lodash-es": {
       "version": "4.17.6",
@@ -2293,6 +2396,11 @@
       "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
       "dev": true
     },
+    "node_modules/@types/web-bluetooth": {
+      "version": "0.0.14",
+      "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.14.tgz",
+      "integrity": "sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A=="
+    },
     "node_modules/@types/webpack-env": {
       "version": "1.16.4",
       "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.16.4.tgz",
@@ -3323,12 +3431,13 @@
       "dev": true
     },
     "node_modules/@vueuse/core": {
-      "version": "8.2.6",
-      "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-8.2.6.tgz",
-      "integrity": "sha512-fzlpM3B5oVe+UhCT1mXlhG1Zxdq2lq1Z2AvddSB8+RxrsSFzII7DKfsQEz8Vop7Lzc++4m8drTNbhPovYoFqHw==",
+      "version": "8.7.5",
+      "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-8.7.5.tgz",
+      "integrity": "sha512-tqgzeZGoZcXzoit4kOGLWJibDMLp0vdm6ZO41SSUQhkhtrPhAg6dbIEPiahhUu6sZAmSYvVrZgEr5aKD51nrLA==",
       "dependencies": {
-        "@vueuse/metadata": "8.2.6",
-        "@vueuse/shared": "8.2.6",
+        "@types/web-bluetooth": "^0.0.14",
+        "@vueuse/metadata": "8.7.5",
+        "@vueuse/shared": "8.7.5",
         "vue-demi": "*"
       },
       "funding": {
@@ -3348,9 +3457,9 @@
       }
     },
     "node_modules/@vueuse/core/node_modules/@vueuse/shared": {
-      "version": "8.2.6",
-      "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-8.2.6.tgz",
-      "integrity": "sha512-J/W4CMfdL8TahELuSOgtfVO4eQXTjhigp7dVWIBsLUVFCeY9d49gvHUcQN3y5xYLZ6iNP57TjTQjMMT/zhklkw==",
+      "version": "8.7.5",
+      "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-8.7.5.tgz",
+      "integrity": "sha512-THXPvMBFmg6Gf6AwRn/EdTh2mhqwjGsB2Yfp374LNQSQVKRHtnJ0I42bsZTn7nuEliBxqUrGQm/lN6qUHmhJLw==",
       "dependencies": {
         "vue-demi": "*"
       },
@@ -3371,9 +3480,9 @@
       }
     },
     "node_modules/@vueuse/core/node_modules/vue-demi": {
-      "version": "0.12.5",
-      "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.12.5.tgz",
-      "integrity": "sha512-BREuTgTYlUr0zw0EZn3hnhC3I6gPWv+Kwh4MCih6QcAeaTlaIX0DwOVN0wHej7hSvDPecz4jygy/idsgKfW58Q==",
+      "version": "0.13.2",
+      "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.2.tgz",
+      "integrity": "sha512-41ukrclEbMddAyP7PvxMSYqnOSzPV6r7GNnyTSKSCNTaz19GehxmTiXyP9kwHSUv2+Dr6hHqiUiF7L1VAw2KdQ==",
       "hasInstallScript": true,
       "bin": {
         "vue-demi-fix": "bin/vue-demi-fix.js",
@@ -3396,9 +3505,9 @@
       }
     },
     "node_modules/@vueuse/metadata": {
-      "version": "8.2.6",
-      "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.2.6.tgz",
-      "integrity": "sha512-OBKtafCt+4RcEJlYDCjp1vl65pBCL2g4TmipEtdZ8/qphKlW6nakJbkY7XRN5grPmjqU99/ahJGtyGk5NHS2hw==",
+      "version": "8.7.5",
+      "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.7.5.tgz",
+      "integrity": "sha512-emJZKRQSaEnVqmlu39NpNp8iaW+bPC2kWykWoWOZMSlO/0QVEmO/rt8A5VhOEJTKLX3vwTevqbiRy9WJRwVOQg==",
       "funding": {
         "url": "https://github.com/sponsors/antfu"
       }
@@ -3819,9 +3928,9 @@
       }
     },
     "node_modules/async-validator": {
-      "version": "4.0.7",
-      "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.0.7.tgz",
-      "integrity": "sha512-Pj2IR7u8hmUEDOwB++su6baaRi+QvsgajuFB9j95foM1N2gy5HM4z60hfusIO0fBPG5uLAEl6yCJr1jNSVugEQ=="
+      "version": "4.2.5",
+      "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
+      "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
     },
     "node_modules/at-least-node": {
       "version": "1.0.0",
@@ -5155,9 +5264,9 @@
       "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA=="
     },
     "node_modules/dayjs": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.1.tgz",
-      "integrity": "sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA=="
+      "version": "1.11.3",
+      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.3.tgz",
+      "integrity": "sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A=="
     },
     "node_modules/debug": {
       "version": "4.3.4",
@@ -5554,19 +5663,19 @@
       "dev": true
     },
     "node_modules/element-plus": {
-      "version": "2.1.9",
-      "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.1.9.tgz",
-      "integrity": "sha512-6mWqS3YrmJPnouWP4otzL8+MehfOnDFqDbcIdnmC07p+Z0JkWe/CVKc4Wky8AYC8nyDMUQyiZYvooCbqGuM7pg==",
-      "dependencies": {
-        "@ctrl/tinycolor": "^3.4.0",
-        "@element-plus/icons-vue": "^1.1.4",
-        "@floating-ui/dom": "^0.4.2",
-        "@popperjs/core": "^2.11.4",
-        "@types/lodash": "^4.14.181",
+      "version": "2.2.8",
+      "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.2.8.tgz",
+      "integrity": "sha512-+cubFh1rgeGcc2LeBm7hv/1BKFJre/LIIdRntm9OLaIhysCxigjEwcxk9gbVT4KsbcjmoqZUr4/mwhIhQV6mvw==",
+      "dependencies": {
+        "@ctrl/tinycolor": "^3.4.1",
+        "@element-plus/icons-vue": "^2.0.6",
+        "@floating-ui/dom": "^0.5.4",
+        "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
+        "@types/lodash": "^4.14.182",
         "@types/lodash-es": "^4.17.6",
-        "@vueuse/core": "^8.2.4",
-        "async-validator": "^4.0.7",
-        "dayjs": "^1.11.0",
+        "@vueuse/core": "^8.7.5",
+        "async-validator": "^4.2.5",
+        "dayjs": "^1.11.3",
         "escape-html": "^1.0.3",
         "lodash": "^4.17.21",
         "lodash-es": "^4.17.21",
@@ -5578,6 +5687,16 @@
         "vue": "^3.2.0"
       }
     },
+    "node_modules/element-plus/node_modules/@popperjs/core": {
+      "name": "@sxzz/popperjs-es",
+      "version": "2.11.7",
+      "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
+      "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/popperjs"
+      }
+    },
     "node_modules/emoji-regex": {
       "version": "8.0.0",
       "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -11159,6 +11278,11 @@
       "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
       "dev": true
     },
+    "node_modules/tinymce": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-6.0.3.tgz",
+      "integrity": "sha512-4cu80kWF7nRGhviE10poZtjTkl3jNL+lycilCMfdm3KU5V7FtiQQrKbEo6GInXT05RY78Ha/NFP0gOBELcSpfg=="
+    },
     "node_modules/to-fast-properties": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@@ -11642,6 +11766,23 @@
       "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==",
       "dev": true
     },
+    "node_modules/vue-i18n": {
+      "version": "9.1.10",
+      "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.1.10.tgz",
+      "integrity": "sha512-jpr7gV5KPk4n+sSPdpZT8Qx3XzTcNDWffRlHV/cT2NUyEf+sEgTTmLvnBAibjOFJ0zsUyZlVTAWH5DDnYep+1g==",
+      "dependencies": {
+        "@intlify/core-base": "9.1.10",
+        "@intlify/shared": "9.1.10",
+        "@intlify/vue-devtools": "9.1.10",
+        "@vue/devtools-api": "^6.0.0-beta.7"
+      },
+      "engines": {
+        "node": ">= 10"
+      },
+      "peerDependencies": {
+        "vue": "^3.0.0"
+      }
+    },
     "node_modules/vue-loader": {
       "version": "17.0.0",
       "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.0.0.tgz",
@@ -13686,9 +13827,9 @@
       "integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw=="
     },
     "@element-plus/icons-vue": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-1.1.4.tgz",
-      "integrity": "sha512-Iz/nHqdp1sFPmdzRwHkEQQA3lKvoObk8azgABZ81QUOpW9s/lUyQVUSh0tNtEPZXQlKwlSh7SPgoVxzrE0uuVQ==",
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.0.6.tgz",
+      "integrity": "sha512-lPpG8hYkjL/Z97DH5Ei6w6o22Z4YdNglWCNYOPcB33JCF2A4wye6HFgSI7hEt9zdLyxlSpiqtgf9XcYU+m5mew==",
       "requires": {}
     },
     "@eslint/eslintrc": {
@@ -13732,16 +13873,16 @@
       }
     },
     "@floating-ui/core": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.6.1.tgz",
-      "integrity": "sha512-Y30eVMcZva8o84c0HcXAtDO4BEzPJMvF6+B7x7urL2xbAqVsGJhojOyHLaoQHQYjb6OkqRq5kO+zeySycQwKqg=="
+      "version": "0.7.3",
+      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz",
+      "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg=="
     },
     "@floating-ui/dom": {
-      "version": "0.4.4",
-      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.4.4.tgz",
-      "integrity": "sha512-0Ulu3B/dqQplUUSqnTx0foSrlYuMN+GTtlJWvNJwt6Fr7/PqmlR/Y08o6/+bxDWr6p3roBJRaQ51MDZsNmEhhw==",
+      "version": "0.5.4",
+      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz",
+      "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==",
       "requires": {
-        "@floating-ui/core": "^0.6.1"
+        "@floating-ui/core": "^0.7.3"
       }
     },
     "@hapi/hoek": {
@@ -13776,6 +13917,74 @@
       "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
       "dev": true
     },
+    "@intlify/core-base": {
+      "version": "9.1.10",
+      "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.10.tgz",
+      "integrity": "sha512-So9CNUavB/IsZ+zBmk2Cv6McQp6vc2wbGi1S0XQmJ8Vz+UFcNn9MFXAe9gY67PreIHrbLsLxDD0cwo1qsxM1Nw==",
+      "requires": {
+        "@intlify/devtools-if": "9.1.10",
+        "@intlify/message-compiler": "9.1.10",
+        "@intlify/message-resolver": "9.1.10",
+        "@intlify/runtime": "9.1.10",
+        "@intlify/shared": "9.1.10",
+        "@intlify/vue-devtools": "9.1.10"
+      }
+    },
+    "@intlify/devtools-if": {
+      "version": "9.1.10",
+      "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.1.10.tgz",
+      "integrity": "sha512-SHaKoYu6sog3+Q8js1y3oXLywuogbH1sKuc7NSYkN3GElvXSBaMoCzW+we0ZSFqj/6c7vTNLg9nQ6rxhKqYwnQ==",
+      "requires": {
+        "@intlify/shared": "9.1.10"
+      }
+    },
+    "@intlify/message-compiler": {
+      "version": "9.1.10",
+      "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.1.10.tgz",
+      "integrity": "sha512-+JiJpXff/XTb0EadYwdxOyRTB0hXNd4n1HaJ/a4yuV960uRmPXaklJsedW0LNdcptd/hYUZtCkI7Lc9J5C1gxg==",
+      "requires": {
+        "@intlify/message-resolver": "9.1.10",
+        "@intlify/shared": "9.1.10",
+        "source-map": "0.6.1"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+        }
+      }
+    },
+    "@intlify/message-resolver": {
+      "version": "9.1.10",
+      "resolved": "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.10.tgz",
+      "integrity": "sha512-5YixMG/M05m0cn9+gOzd4EZQTFRUu8RGhzxJbR1DWN21x/Z3bJ8QpDYj6hC4FwBj5uKsRfKpJQ3Xqg98KWoA+w=="
+    },
+    "@intlify/runtime": {
+      "version": "9.1.10",
+      "resolved": "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.1.10.tgz",
+      "integrity": "sha512-7QsuByNzpe3Gfmhwq6hzgXcMPpxz8Zxb/XFI6s9lQdPLPe5Lgw4U1ovRPZTOs6Y2hwitR3j/HD8BJNGWpJnOFA==",
+      "requires": {
+        "@intlify/message-compiler": "9.1.10",
+        "@intlify/message-resolver": "9.1.10",
+        "@intlify/shared": "9.1.10"
+      }
+    },
+    "@intlify/shared": {
+      "version": "9.1.10",
+      "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.10.tgz",
+      "integrity": "sha512-Om54xJeo1Vw+K1+wHYyXngE8cAbrxZHpWjYzMR9wCkqbhGtRV5VLhVc214Ze2YatPrWlS2WSMOWXR8JktX/IgA=="
+    },
+    "@intlify/vue-devtools": {
+      "version": "9.1.10",
+      "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.1.10.tgz",
+      "integrity": "sha512-5l3qYARVbkWAkagLu1XbDUWRJSL8br1Dj60wgMaKB0+HswVsrR6LloYZTg7ozyvM621V6+zsmwzbQxbVQyrytQ==",
+      "requires": {
+        "@intlify/message-resolver": "9.1.10",
+        "@intlify/runtime": "9.1.10",
+        "@intlify/shared": "9.1.10"
+      }
+    },
     "@jridgewell/resolve-uri": {
       "version": "3.0.5",
       "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz",
@@ -13994,6 +14203,14 @@
       "integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==",
       "dev": true
     },
+    "@tinymce/tinymce-vue": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/@tinymce/tinymce-vue/-/tinymce-vue-5.0.0.tgz",
+      "integrity": "sha512-1HRCNa2eGdztOKShYAiHIry50LTU6YJG//qSP9AJElrXhb3BIBN0Bef6E56nZObVgwCgSmI4cnX35VU9D49aow==",
+      "requires": {
+        "tinymce": "^6.0.0 || ^5.5.1"
+      }
+    },
     "@trysound/sax": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
@@ -14115,9 +14332,9 @@
       "dev": true
     },
     "@types/lodash": {
-      "version": "4.14.181",
-      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.181.tgz",
-      "integrity": "sha512-n3tyKthHJbkiWhDZs3DkhkCzt2MexYHXlX0td5iMplyfwketaOeKboEVBqzceH7juqvEg3q5oUoBFxSLu7zFag=="
+      "version": "4.14.182",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
+      "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q=="
     },
     "@types/lodash-es": {
       "version": "4.17.6",
@@ -14219,6 +14436,11 @@
       "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
       "dev": true
     },
+    "@types/web-bluetooth": {
+      "version": "0.0.14",
+      "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.14.tgz",
+      "integrity": "sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A=="
+    },
     "@types/webpack-env": {
       "version": "1.16.4",
       "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.16.4.tgz",
@@ -14982,35 +15204,36 @@
       "dev": true
     },
     "@vueuse/core": {
-      "version": "8.2.6",
-      "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-8.2.6.tgz",
-      "integrity": "sha512-fzlpM3B5oVe+UhCT1mXlhG1Zxdq2lq1Z2AvddSB8+RxrsSFzII7DKfsQEz8Vop7Lzc++4m8drTNbhPovYoFqHw==",
+      "version": "8.7.5",
+      "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-8.7.5.tgz",
+      "integrity": "sha512-tqgzeZGoZcXzoit4kOGLWJibDMLp0vdm6ZO41SSUQhkhtrPhAg6dbIEPiahhUu6sZAmSYvVrZgEr5aKD51nrLA==",
       "requires": {
-        "@vueuse/metadata": "8.2.6",
-        "@vueuse/shared": "8.2.6",
+        "@types/web-bluetooth": "^0.0.14",
+        "@vueuse/metadata": "8.7.5",
+        "@vueuse/shared": "8.7.5",
         "vue-demi": "*"
       },
       "dependencies": {
         "@vueuse/shared": {
-          "version": "8.2.6",
-          "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-8.2.6.tgz",
-          "integrity": "sha512-J/W4CMfdL8TahELuSOgtfVO4eQXTjhigp7dVWIBsLUVFCeY9d49gvHUcQN3y5xYLZ6iNP57TjTQjMMT/zhklkw==",
+          "version": "8.7.5",
+          "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-8.7.5.tgz",
+          "integrity": "sha512-THXPvMBFmg6Gf6AwRn/EdTh2mhqwjGsB2Yfp374LNQSQVKRHtnJ0I42bsZTn7nuEliBxqUrGQm/lN6qUHmhJLw==",
           "requires": {
             "vue-demi": "*"
           }
         },
         "vue-demi": {
-          "version": "0.12.5",
-          "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.12.5.tgz",
-          "integrity": "sha512-BREuTgTYlUr0zw0EZn3hnhC3I6gPWv+Kwh4MCih6QcAeaTlaIX0DwOVN0wHej7hSvDPecz4jygy/idsgKfW58Q==",
+          "version": "0.13.2",
+          "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.2.tgz",
+          "integrity": "sha512-41ukrclEbMddAyP7PvxMSYqnOSzPV6r7GNnyTSKSCNTaz19GehxmTiXyP9kwHSUv2+Dr6hHqiUiF7L1VAw2KdQ==",
           "requires": {}
         }
       }
     },
     "@vueuse/metadata": {
-      "version": "8.2.6",
-      "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.2.6.tgz",
-      "integrity": "sha512-OBKtafCt+4RcEJlYDCjp1vl65pBCL2g4TmipEtdZ8/qphKlW6nakJbkY7XRN5grPmjqU99/ahJGtyGk5NHS2hw=="
+      "version": "8.7.5",
+      "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.7.5.tgz",
+      "integrity": "sha512-emJZKRQSaEnVqmlu39NpNp8iaW+bPC2kWykWoWOZMSlO/0QVEmO/rt8A5VhOEJTKLX3vwTevqbiRy9WJRwVOQg=="
     },
     "@webassemblyjs/ast": {
       "version": "1.11.1",
@@ -15352,9 +15575,9 @@
       }
     },
     "async-validator": {
-      "version": "4.0.7",
-      "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.0.7.tgz",
-      "integrity": "sha512-Pj2IR7u8hmUEDOwB++su6baaRi+QvsgajuFB9j95foM1N2gy5HM4z60hfusIO0fBPG5uLAEl6yCJr1jNSVugEQ=="
+      "version": "4.2.5",
+      "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
+      "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
     },
     "at-least-node": {
       "version": "1.0.0",
@@ -16319,9 +16542,9 @@
       "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA=="
     },
     "dayjs": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.1.tgz",
-      "integrity": "sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA=="
+      "version": "1.11.3",
+      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.3.tgz",
+      "integrity": "sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A=="
     },
     "debug": {
       "version": "4.3.4",
@@ -16624,25 +16847,32 @@
       "dev": true
     },
     "element-plus": {
-      "version": "2.1.9",
-      "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.1.9.tgz",
-      "integrity": "sha512-6mWqS3YrmJPnouWP4otzL8+MehfOnDFqDbcIdnmC07p+Z0JkWe/CVKc4Wky8AYC8nyDMUQyiZYvooCbqGuM7pg==",
-      "requires": {
-        "@ctrl/tinycolor": "^3.4.0",
-        "@element-plus/icons-vue": "^1.1.4",
-        "@floating-ui/dom": "^0.4.2",
-        "@popperjs/core": "^2.11.4",
-        "@types/lodash": "^4.14.181",
+      "version": "2.2.8",
+      "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.2.8.tgz",
+      "integrity": "sha512-+cubFh1rgeGcc2LeBm7hv/1BKFJre/LIIdRntm9OLaIhysCxigjEwcxk9gbVT4KsbcjmoqZUr4/mwhIhQV6mvw==",
+      "requires": {
+        "@ctrl/tinycolor": "^3.4.1",
+        "@element-plus/icons-vue": "^2.0.6",
+        "@floating-ui/dom": "^0.5.4",
+        "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
+        "@types/lodash": "^4.14.182",
         "@types/lodash-es": "^4.17.6",
-        "@vueuse/core": "^8.2.4",
-        "async-validator": "^4.0.7",
-        "dayjs": "^1.11.0",
+        "@vueuse/core": "^8.7.5",
+        "async-validator": "^4.2.5",
+        "dayjs": "^1.11.3",
         "escape-html": "^1.0.3",
         "lodash": "^4.17.21",
         "lodash-es": "^4.17.21",
         "lodash-unified": "^1.0.2",
         "memoize-one": "^6.0.0",
         "normalize-wheel-es": "^1.1.2"
+      },
+      "dependencies": {
+        "@popperjs/core": {
+          "version": "npm:@sxzz/popperjs-es@2.11.7",
+          "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
+          "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ=="
+        }
       }
     },
     "emoji-regex": {
@@ -20781,6 +21011,11 @@
       "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
       "dev": true
     },
+    "tinymce": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-6.0.3.tgz",
+      "integrity": "sha512-4cu80kWF7nRGhviE10poZtjTkl3jNL+lycilCMfdm3KU5V7FtiQQrKbEo6GInXT05RY78Ha/NFP0gOBELcSpfg=="
+    },
     "to-fast-properties": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@@ -21140,6 +21375,17 @@
       "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==",
       "dev": true
     },
+    "vue-i18n": {
+      "version": "9.1.10",
+      "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.1.10.tgz",
+      "integrity": "sha512-jpr7gV5KPk4n+sSPdpZT8Qx3XzTcNDWffRlHV/cT2NUyEf+sEgTTmLvnBAibjOFJ0zsUyZlVTAWH5DDnYep+1g==",
+      "requires": {
+        "@intlify/core-base": "9.1.10",
+        "@intlify/shared": "9.1.10",
+        "@intlify/vue-devtools": "9.1.10",
+        "@vue/devtools-api": "^6.0.0-beta.7"
+      }
+    },
     "vue-loader": {
       "version": "17.0.0",
       "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.0.0.tgz",

+ 3 - 1
package.json

@@ -10,12 +10,13 @@
     "lint": "vue-cli-service lint"
   },
   "dependencies": {
+    "@tinymce/tinymce-vue": "^5.0.0",
     "axios": "^0.26.1",
     "core-js": "^3.8.3",
     "crypto-js": "^4.1.1",
     "default-passive-events": "^2.0.0",
     "echarts": "^5.3.2",
-    "element-plus": "^2.1.9",
+    "element-plus": "^2.2.8",
     "long": "^5.2.0",
     "moment": "^2.29.3",
     "protobufjs": "^6.11.2",
@@ -24,6 +25,7 @@
     "vant": "^3.4.8",
     "vue": "^3.2.13",
     "vue-class-component": "^8.0.0-0",
+    "vue-i18n": "^9.1.10",
     "vue-router": "^4.0.3",
     "vuedraggable": "^4.1.0"
   },

+ 5 - 0
public/language/en.json

@@ -0,0 +1,5 @@
+{
+    "app": {
+        "name": "Muchinfo"
+    }
+}

+ 5 - 0
public/language/zh-cn.json

@@ -0,0 +1,5 @@
+{
+    "app": {
+        "name": "企业风管"
+    }
+}

File diff suppressed because it is too large
+ 0 - 0
public/tinymce/icons/default/icons.min.js


+ 3 - 0
public/tinymce/langs/README.md

@@ -0,0 +1,3 @@
+This is where language files should be placed.
+
+Please DO NOT translate these directly use this service: https://www.transifex.com/projects/p/tinymce/

File diff suppressed because it is too large
+ 6 - 0
public/tinymce/langs/zh-Hans.js


+ 21 - 0
public/tinymce/license.txt

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 Ephox Corporation DBA Tiny Technologies, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

File diff suppressed because it is too large
+ 3 - 0
public/tinymce/models/dom/model.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/advlist/plugin.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/anchor/plugin.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/autolink/plugin.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/autoresize/plugin.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/autosave/plugin.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/charmap/plugin.min.js


+ 4 - 0
public/tinymce/plugins/code/plugin.min.js

@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 6.0.3 (2022-05-25)
+ */
+!function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("code",(e=>((e=>{e.addCommand("mceCodeEditor",(()=>{(e=>{const o=(e=>e.getContent({source_view:!0}))(e);e.windowManager.open({title:"Source Code",size:"large",body:{type:"panel",items:[{type:"textarea",name:"code"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{code:o},onSubmit:o=>{((e,o)=>{e.focus(),e.undoManager.transact((()=>{e.setContent(o)})),e.selection.setCursorLocation(),e.nodeChanged()})(e,o.getData().code),o.close()}})})(e)}))})(e),(e=>{const o=()=>e.execCommand("mceCodeEditor");e.ui.registry.addButton("code",{icon:"sourcecode",tooltip:"Source code",onAction:o}),e.ui.registry.addMenuItem("code",{icon:"sourcecode",text:"Source code",onAction:o})})(e),{})))}();

File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/codesample/plugin.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/directionality/plugin.min.js


File diff suppressed because it is too large
+ 0 - 0
public/tinymce/plugins/emoticons/js/emojiimages.js


File diff suppressed because it is too large
+ 2 - 0
public/tinymce/plugins/emoticons/js/emojiimages.min.js


File diff suppressed because it is too large
+ 0 - 0
public/tinymce/plugins/emoticons/js/emojis.js


File diff suppressed because it is too large
+ 1 - 0
public/tinymce/plugins/emoticons/js/emojis.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/emoticons/plugin.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/fullscreen/plugin.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/help/plugin.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/image/plugin.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/importcss/plugin.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/insertdatetime/plugin.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/link/plugin.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/lists/plugin.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/media/plugin.min.js


+ 4 - 0
public/tinymce/plugins/nonbreaking/plugin.min.js

@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 6.0.3 (2022-05-25)
+ */
+!function(){"use strict";var n=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=n=>e=>typeof e===n,a=e("boolean"),o=e("number"),t=n=>e=>e.options.get(n),i=t("nonbreaking_force_tab"),r=t("nonbreaking_wrap"),s=(n,e)=>{let a="";for(let o=0;o<e;o++)a+=n;return a},c=(n,e)=>{const a=r(n)||n.plugins.visualchars?`<span class="${(n=>!!n.plugins.visualchars&&n.plugins.visualchars.isEnabled())(n)?"mce-nbsp-wrap mce-nbsp":"mce-nbsp-wrap"}" contenteditable="false">${s("&nbsp;",e)}</span>`:s("&nbsp;",e);n.undoManager.transact((()=>n.insertContent(a)))};var l=tinymce.util.Tools.resolve("tinymce.util.VK");n.add("nonbreaking",(n=>{(n=>{const e=n.options.register;e("nonbreaking_force_tab",{processor:n=>a(n)?{value:n?3:0,valid:!0}:o(n)?{value:n,valid:!0}:{valid:!1,message:"Must be a boolean or number."},default:!1}),e("nonbreaking_wrap",{processor:"boolean",default:!0})})(n),(n=>{n.addCommand("mceNonBreaking",(()=>{c(n,1)}))})(n),(n=>{const e=()=>n.execCommand("mceNonBreaking");n.ui.registry.addButton("nonbreaking",{icon:"non-breaking",tooltip:"Nonbreaking space",onAction:e}),n.ui.registry.addMenuItem("nonbreaking",{icon:"non-breaking",text:"Nonbreaking space",onAction:e})})(n),(n=>{const e=i(n);e>0&&n.on("keydown",(a=>{if(a.keyCode===l.TAB&&!a.isDefaultPrevented()){if(a.shiftKey)return;a.preventDefault(),a.stopImmediatePropagation(),c(n,e)}}))})(n)}))}();

+ 4 - 0
public/tinymce/plugins/pagebreak/plugin.min.js

@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 6.0.3 (2022-05-25)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),a=tinymce.util.Tools.resolve("tinymce.Env");const t=e=>a=>a.options.get(e),r=t("pagebreak_separator"),n=t("pagebreak_split_block"),o="mce-pagebreak",s=e=>{const t=`<img src="${a.transparentSrc}" class="mce-pagebreak" data-mce-resize="false" data-mce-placeholder />`;return e?`<p>${t}</p>`:t};e.add("pagebreak",(e=>{(e=>{const a=e.options.register;a("pagebreak_separator",{processor:"string",default:"\x3c!-- pagebreak --\x3e"}),a("pagebreak_split_block",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mcePageBreak",(()=>{e.insertContent(s(n(e)))}))})(e),(e=>{const a=()=>e.execCommand("mcePageBreak");e.ui.registry.addButton("pagebreak",{icon:"page-break",tooltip:"Page break",onAction:a}),e.ui.registry.addMenuItem("pagebreak",{text:"Page break",icon:"page-break",onAction:a})})(e),(e=>{const a=r(e),t=()=>n(e),c=new RegExp(a.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,(e=>"\\"+e)),"gi");e.on("BeforeSetContent",(e=>{e.content=e.content.replace(c,s(t()))})),e.on("PreInit",(()=>{e.serializer.addNodeFilter("img",(r=>{let n,s,c=r.length;for(;c--;)if(n=r[c],s=n.attr("class"),s&&-1!==s.indexOf(o)){const r=n.parent;if(e.schema.getBlockElements()[r.name]&&t()){r.type=3,r.value=a,r.raw=!0,n.remove();continue}n.type=3,n.value=a,n.raw=!0}}))}))})(e),(e=>{e.on("ResolveName",(a=>{"IMG"===a.target.nodeName&&e.dom.hasClass(a.target,o)&&(a.name="pagebreak")}))})(e)}))}();

+ 4 - 0
public/tinymce/plugins/preview/plugin.min.js

@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 6.0.3 (2022-05-25)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env"),o=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=e=>t=>t.options.get(e),i=n("content_style"),s=n("content_css_cors"),c=n("body_class"),r=n("body_id");e.add("preview",(e=>{(e=>{e.addCommand("mcePreview",(()=>{(e=>{const n=(e=>{var n;let l="";const a=e.dom.encode,d=null!==(n=i(e))&&void 0!==n?n:"";l+='<base href="'+a(e.documentBaseURI.getURI())+'">';const m=s(e)?' crossorigin="anonymous"':"";o.each(e.contentCSS,(t=>{l+='<link type="text/css" rel="stylesheet" href="'+a(e.documentBaseURI.toAbsolute(t))+'"'+m+">"})),d&&(l+='<style type="text/css">'+d+"</style>");const y=r(e),u=c(e),v='<script>document.addEventListener && document.addEventListener("click", function(e) {for (var elm = e.target; elm; elm = elm.parentNode) {if (elm.nodeName === "A" && !('+(t.os.isMacOS()||t.os.isiOS()?"e.metaKey":"e.ctrlKey && !e.altKey")+")) {e.preventDefault();}}}, false);<\/script> ",p=e.getBody().dir,w=p?' dir="'+a(p)+'"':"";return"<!DOCTYPE html><html><head>"+l+'</head><body id="'+a(y)+'" class="mce-content-body '+a(u)+'"'+w+">"+e.getContent()+v+"</body></html>"})(e);e.windowManager.open({title:"Preview",size:"large",body:{type:"panel",items:[{name:"preview",type:"iframe",sandboxed:!0}]},buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}],initialData:{preview:n}}).focus("close")})(e)}))})(e),(e=>{const t=()=>e.execCommand("mcePreview");e.ui.registry.addButton("preview",{icon:"preview",tooltip:"Preview",onAction:t}),e.ui.registry.addMenuItem("preview",{icon:"preview",text:"Preview",onAction:t})})(e)}))}();

File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/quickbars/plugin.min.js


+ 4 - 0
public/tinymce/plugins/save/plugin.min.js

@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 6.0.3 (2022-05-25)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const n=("function",e=>"function"==typeof e);var o=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),t=tinymce.util.Tools.resolve("tinymce.util.Tools");const a=e=>n=>n.options.get(e),c=a("save_enablewhendirty"),i=a("save_onsavecallback"),s=a("save_oncancelcallback"),r=(e,n)=>{e.notificationManager.open({text:n,type:"error"})},l=e=>n=>{const o=()=>{n.setEnabled(!c(e)||e.isDirty())};return o(),e.on("NodeChange dirty",o),()=>e.off("NodeChange dirty",o)};e.add("save",(e=>{(e=>{const n=e.options.register;n("save_enablewhendirty",{processor:"boolean",default:!0}),n("save_onsavecallback",{processor:"function"}),n("save_oncancelcallback",{processor:"function"})})(e),(e=>{e.ui.registry.addButton("save",{icon:"save",tooltip:"Save",enabled:!1,onAction:()=>e.execCommand("mceSave"),onSetup:l(e)}),e.ui.registry.addButton("cancel",{icon:"cancel",tooltip:"Cancel",enabled:!1,onAction:()=>e.execCommand("mceCancel"),onSetup:l(e)}),e.addShortcut("Meta+S","","mceSave")})(e),(e=>{e.addCommand("mceSave",(()=>{(e=>{const t=o.DOM.getParent(e.id,"form");if(c(e)&&!e.isDirty())return;e.save();const a=i(e);if(n(a))return a.call(e,e),void e.nodeChanged();t?(e.setDirty(!1),t.onsubmit&&!t.onsubmit()||("function"==typeof t.submit?t.submit():r(e,"Error: Form submit field collision.")),e.nodeChanged()):r(e,"Error: No form element found.")})(e)})),e.addCommand("mceCancel",(()=>{(e=>{const o=t.trim(e.startContent),a=s(e);n(a)?a.call(e,e):e.resetContent(o)})(e)}))})(e)}))}();

File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/searchreplace/plugin.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/table/plugin.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/template/plugin.min.js


+ 4 - 0
public/tinymce/plugins/visualblocks/plugin.min.js

@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 6.0.3 (2022-05-25)
+ */
+!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const s=(t,s,o)=>{t.dom.toggleClass(t.getBody(),"mce-visualblocks"),o.set(!o.get()),((t,s)=>{t.dispatch("VisualBlocks",{state:s})})(t,o.get())},o=("visualblocks_default_state",t=>t.options.get("visualblocks_default_state"));const e=(t,s)=>o=>{o.setActive(s.get());const e=t=>o.setActive(t.state);return t.on("VisualBlocks",e),()=>t.off("VisualBlocks",e)};t.add("visualblocks",((t,l)=>{(t=>{(0,t.options.register)("visualblocks_default_state",{processor:"boolean",default:!1})})(t);const a=(t=>{let s=!1;return{get:()=>s,set:t=>{s=t}}})();((t,o,e)=>{t.addCommand("mceVisualBlocks",(()=>{s(t,0,e)}))})(t,0,a),((t,s)=>{const o=()=>t.execCommand("mceVisualBlocks");t.ui.registry.addToggleButton("visualblocks",{icon:"visualblocks",tooltip:"Show blocks",onAction:o,onSetup:e(t,s)}),t.ui.registry.addToggleMenuItem("visualblocks",{text:"Show blocks",icon:"visualblocks",onAction:o,onSetup:e(t,s)})})(t,a),((t,e,l)=>{t.on("PreviewFormats AfterPreviewFormats",(s=>{l.get()&&t.dom.toggleClass(t.getBody(),"mce-visualblocks","afterpreviewformats"===s.type)})),t.on("init",(()=>{o(t)&&s(t,0,l)}))})(t,0,a)}))}();

File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/visualchars/plugin.min.js


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/plugins/wordcount/plugin.min.js


+ 1 - 0
public/tinymce/skins/content/dark/content.min.css

@@ -0,0 +1 @@
+body{background-color:#222f3e;color:#fff;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}a{color:#4099ff}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#6d737b}figure{display:table;margin:1rem auto}figure figcaption{color:#8a8f97;display:block;margin-top:.25rem;text-align:center}hr{border-color:#6d737b;border-style:solid;border-width:1px 0 0 0}code{background-color:#6d737b;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #6d737b;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #6d737b;margin-right:1.5rem;padding-right:1rem}

+ 1 - 0
public/tinymce/skins/content/default/content.min.css

@@ -0,0 +1 @@
+body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}

+ 1 - 0
public/tinymce/skins/content/document/content.min.css

@@ -0,0 +1 @@
+@media screen{html{background:#f4f4f4;min-height:100%}}body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif}@media screen{body{background-color:#fff;box-shadow:0 0 4px rgba(0,0,0,.15);box-sizing:border-box;margin:1rem auto 0;max-width:820px;min-height:calc(100vh - 1rem);padding:4rem 6rem 6rem 6rem}}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure figcaption{color:#999;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}

+ 1 - 0
public/tinymce/skins/content/tinymce-5-dark/content.min.css

@@ -0,0 +1 @@
+body{background-color:#2f3742;color:#dfe0e4;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}a{color:#4099ff}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#6d737b}figure{display:table;margin:1rem auto}figure figcaption{color:#8a8f97;display:block;margin-top:.25rem;text-align:center}hr{border-color:#6d737b;border-style:solid;border-width:1px 0 0 0}code{background-color:#6d737b;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #6d737b;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #6d737b;margin-right:1.5rem;padding-right:1rem}

+ 1 - 0
public/tinymce/skins/content/tinymce-5/content.min.css

@@ -0,0 +1 @@
+body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}

+ 1 - 0
public/tinymce/skins/content/writer/content.min.css

@@ -0,0 +1 @@
+body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem auto;max-width:900px}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}

File diff suppressed because it is too large
+ 0 - 0
public/tinymce/skins/ui/oxide-dark/content.inline.min.css


File diff suppressed because it is too large
+ 0 - 0
public/tinymce/skins/ui/oxide-dark/content.min.css


File diff suppressed because it is too large
+ 0 - 0
public/tinymce/skins/ui/oxide-dark/skin.min.css


+ 1 - 0
public/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css

@@ -0,0 +1 @@
+body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}

File diff suppressed because it is too large
+ 0 - 0
public/tinymce/skins/ui/oxide/content.inline.min.css


File diff suppressed because it is too large
+ 0 - 0
public/tinymce/skins/ui/oxide/content.min.css


File diff suppressed because it is too large
+ 0 - 0
public/tinymce/skins/ui/oxide/skin.min.css


+ 1 - 0
public/tinymce/skins/ui/oxide/skin.shadowdom.min.css

@@ -0,0 +1 @@
+body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}

File diff suppressed because it is too large
+ 0 - 0
public/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css


File diff suppressed because it is too large
+ 0 - 0
public/tinymce/skins/ui/tinymce-5-dark/content.min.css


File diff suppressed because it is too large
+ 0 - 0
public/tinymce/skins/ui/tinymce-5-dark/skin.min.css


+ 1 - 0
public/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.min.css

@@ -0,0 +1 @@
+body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}

File diff suppressed because it is too large
+ 0 - 0
public/tinymce/skins/ui/tinymce-5/content.inline.min.css


File diff suppressed because it is too large
+ 0 - 0
public/tinymce/skins/ui/tinymce-5/content.min.css


File diff suppressed because it is too large
+ 0 - 0
public/tinymce/skins/ui/tinymce-5/skin.min.css


+ 1 - 0
public/tinymce/skins/ui/tinymce-5/skin.shadowdom.min.css

@@ -0,0 +1 @@
+body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}

File diff suppressed because it is too large
+ 3 - 0
public/tinymce/themes/silver/theme.min.js


File diff suppressed because it is too large
+ 977 - 0
public/tinymce/tinymce.d.ts


File diff suppressed because it is too large
+ 3 - 0
public/tinymce/tinymce.min.js


+ 4 - 14
src/business/account/index.ts

@@ -1,6 +1,5 @@
 import { ref, reactive } from 'vue'
 import { v4 } from 'uuid'
-import { useRoute, useRouter } from 'vue-router'
 import { sessionCache } from '@/store'
 import { initBaseData } from '@/business/common'
 import { login, queryLoginId } from '@/services/api/account'
@@ -8,10 +7,7 @@ import cryptojs from 'crypto-js'
 import eventBus from '@/services/bus'
 
 export function useAccount() {
-    const route = useRoute(),
-        router = useRouter(),
-        loading = ref(false);
-
+    const loading = ref(false);
     const account = reactive<Proto.LoginReq>({
         LoginID: 'xyy',
         LoginPWD: '123456',
@@ -24,7 +20,7 @@ export function useAccount() {
 
     // 用户登录
     const userLogin = () => {
-        loading.value = true;
+        loading.value = true
         return new Promise((resolve, reject) => {
             queryLoginId({
                 data: {
@@ -39,15 +35,9 @@ export function useAccount() {
                         },
                         success: (res) => {
                             sessionCache.setValue('loginInfo', res);
-
                             initBaseData(() => {
+                                loading.value = false;
                                 resolve(res);
-                                const redirect = route.query.redirect;
-                                if (redirect) {
-                                    router.replace(redirect.toString());
-                                } else {
-                                    router.replace('/');
-                                }
                             }).catch((err) => {
                                 loading.value = false;
                                 reject(err);
@@ -69,7 +59,7 @@ export function useAccount() {
 
     // 用户登出
     const userlogout = () => {
-        eventBus.$emit('logoutNotify');
+        eventBus.$emit('LogoutNotify');
     }
 
     return {

+ 18 - 0
src/business/admin/index.ts

@@ -0,0 +1,18 @@
+import { reactive } from 'vue'
+
+export function useAdmin() {
+    const admin = reactive({
+        realName: '李兔饼',
+        avatar: '',
+    })
+
+    // 用户登出
+    const logout = () => {
+        console.log('登出')
+    }
+
+    return {
+        admin,
+        logout,
+    }
+}

+ 47 - 2
src/business/common/index.ts

@@ -11,13 +11,13 @@ export const business = new (class {
 
     constructor() {
         // 接收用户登出通知
-        this.logoutNotify = eventBus.$on('logoutNotify', () => {
+        this.logoutNotify = eventBus.$on('LogoutNotify', () => {
             socket.closeQuoteServer();
             socket.closeTradeServer();
         })
 
         // 接收资金变动通知
-        this.moneyChangedNotify = eventBus.$on('moneyChangedNotify', () => {
+        this.moneyChangedNotify = eventBus.$on('MoneyChangedNotify', () => {
             getTaAccounts();
         })
     }
@@ -29,6 +29,9 @@ export const business = new (class {
  */
 export async function initBaseData(callback?: () => void) {
     if (getLoginInfo('Token')) {
+        // 连接交易服务
+        socket.connectTrade();
+
         const getGoodsList = queryGoodsList({
             success: (res) => {
                 globalState.setValue('goodsList', res.data);
@@ -94,4 +97,46 @@ export function getGoodsPriceByCode(goodscode: string) {
         const quote = getQuoteDayInfoByCode(goodscode).value;
         return quote?.last ?? 0;
     })
+}
+
+/**
+ * 获取表头列数据
+ * @param tableName 
+ */
+export function getTableColumns(tableName?: string) {
+    console.log(tableName)
+    return [
+        {
+            prop: 'customername',
+            label: '客户名称',
+            sortable: true,
+            show: true,
+        },
+        {
+            prop: 'userinfotype',
+            label: '客户类型',
+            sortable: true,
+            show: true,
+        },
+        {
+            prop: 'contactname',
+            label: '联系人',
+            show: true,
+        },
+        {
+            prop: 'mobile',
+            label: '手机号码',
+            show: true,
+        },
+        {
+            prop: 'status',
+            label: '状态',
+            show: true,
+        },
+        {
+            prop: 'cardtypename',
+            label: '证件类型',
+            show: true,
+        }
+    ]
 }

+ 49 - 0
src/business/customer/index.ts

@@ -0,0 +1,49 @@
+import { shallowRef } from 'vue'
+import { useDataTable } from '@/hooks/datatable'
+import { queryCustomerInfo } from '@/services/api/customer'
+import { CustomerQueryType } from '@/constants/enum/customer'
+import { getTableColumns } from '../common'
+
+export function useCustomer(queryType: CustomerQueryType) {
+    const { dataList, selectList, inputList, buttonList } = useDataTable<Ermcp.CustomerInfoRsp>()
+    const loading = shallowRef(true)
+    const columns = shallowRef<Ermcp.TableColumn[]>(getTableColumns('table_pcweb_userinfo'))
+
+    selectList.value = [
+        {
+            key: 'userinfotype',
+            placeholder: '客户类型',
+            options: [
+                { label: '个人', value: 1 },
+                { label: '企业', value: 2 }
+            ],
+        },
+    ]
+
+    inputList.value = [
+        { placeholder: '模糊搜索客户名称', keys: ['customername', 'contactname', 'legalpersonname'] },
+    ]
+
+    const onReady = queryCustomerInfo({
+        data: {
+            userid: 1000,
+            querytype: queryType,
+        },
+        success: (res) => {
+            dataList.value = res.data
+        },
+        complete: () => {
+            loading.value = false
+        }
+    })
+
+    return {
+        loading,
+        dataList,
+        columns,
+        selectList,
+        inputList,
+        buttonList,
+        onReady,
+    }
+}

+ 15 - 7
src/components/base/modal/index.less

@@ -5,13 +5,14 @@
     height: 100%;
 
     &__mask {
-        position           : absolute;
-        top                : 0;
-        left               : 0;
-        width              : 100%;
-        height             : 100%;
-        background-color   : rgba(0, 0, 0, .45);
-        transition-property: opacity;
+        position             : absolute;
+        top                  : 0;
+        left                 : 0;
+        width                : 100%;
+        height               : 100%;
+        background-color     : rgba(0, 0, 0, .35);
+        //backdrop-filter    : blur(2px);
+        transition-property  : opacity;
 
         &:not(.is-show) {
             opacity: 0;
@@ -34,6 +35,13 @@
         max-height    : 100%;
     }
 
+    &__container &__header,
+    &__container &__footer {
+        &:empty {
+            display: none;
+        }
+    }
+
     &__container &__body {
         flex      : 1;
         overflow-y: auto;

+ 40 - 14
src/components/base/modal/index.vue

@@ -1,21 +1,23 @@
 <!-- 基础模态框组件 -->
 <template>
-    <div class="app-modal" :style="modalStyles" v-show="visible">
-        <div :class="['app-modal__mask', transitionClass]" :style="transitionStyles"></div>
-        <div :class="['app-modal__wrapper', direction]" @click.self="onMask">
-            <div :class="['app-modal__container', transitionClass]" :style="transitionStyles">
-                <div class="app-modal__header">
-                    <slot name="header"></slot>
-                </div>
-                <div class="app-modal__body">
-                    <slot></slot>
-                </div>
-                <div class="app-modal__footer">
-                    <slot name="footer"></slot>
+    <teleport :to="teleport">
+        <div class="app-modal" v-bind="$attrs" :style="modalStyles" v-show="visible">
+            <div :class="['app-modal__mask', transitionClass]" :style="transitionStyles"></div>
+            <div :class="['app-modal__wrapper', direction]" @click.self="onMask">
+                <div :class="['app-modal__container', transitionClass]" :style="containerStyles">
+                    <div class="app-modal__header">
+                        <slot name="header"></slot>
+                    </div>
+                    <div class="app-modal__body">
+                        <slot></slot>
+                    </div>
+                    <div class="app-modal__footer">
+                        <slot name="footer"></slot>
+                    </div>
                 </div>
             </div>
         </div>
-    </div>
+    </teleport>
 </template>
 
 <script lang="ts" setup>
@@ -34,6 +36,11 @@ const props = defineProps({
         type: Boolean,
         default: true,
     },
+    // 窗口插入到指定元素
+    teleport: {
+        type: String,
+        default: 'body',
+    },
     // 绝对定位
     fixed: {
         type: Boolean,
@@ -47,13 +54,18 @@ const props = defineProps({
     // 窗口动画时间
     delay: {
         type: Number,
-        default: 250,
+        default: 300,
     },
     // 窗口弹出方向
     direction: {
         type: String as PropType<'full' | 'center' | 'left' | 'right' | 'top' | 'bottom' | 'left-top' | 'left-bottom' | 'right-top' | 'right-bottom'>,
         default: 'center',
     },
+    // 窗口宽度
+    width: {
+        type: [Number, String],
+        default: 'auto',
+    },
 })
 
 const { visible, transitionClass, transitionStyles, transition } = useModal(props.show, props.delay);
@@ -63,6 +75,20 @@ const modalStyles = computed(() => ({
     zIndex: props.zIndex,
 }))
 
+const containerStyles = computed(() => {
+    const getWidth = () => {
+        const width = props.width.toString();
+        if (width.endsWith('%')) {
+            return width;
+        }
+        return width === 'auto' ? width : width + 'px';
+    }
+    return {
+        ...transitionStyles.value,
+        width: getWidth(),
+    }
+})
+
 // 点击遮罩事件
 const onMask = () => {
     if (props.closeOnClickMask) {

+ 0 - 79
src/components/base/tab-component/index.ts

@@ -1,79 +0,0 @@
-import { defineAsyncComponent, shallowRef } from 'vue'
-import { useMenu } from '@/hooks/menu'
-import { DynamicComponent } from './interface'
-
-/**
- * @param menucode 
- * @returns 
- */
-export function useDynamicComponent(menucode?: string) {
-    const { getChildrenMenu } = useMenu();
-    const dynamicComponents: DynamicComponent[] = [];
-    const currentAuth: Ermcp.AccountMenu.Auth[] = []; // 当前操作权限
-    const currentTabComponent = shallowRef<DynamicComponent>(); // 当前选中的子组件
-
-    /**
-     * 转换动态组件
-     * @param items 
-     * @returns 
-     */
-    const parseComponent = (items: Ermcp.AccountMenu[]) => {
-        let result: DynamicComponent[] = [];
-
-        items.forEach((menu) => {
-            const { title, code, component, children, auth } = menu;
-            if (component) {
-                const componentString = component.replace(/^\/+/, ''); // 过滤字符串前面所有 '/' 字符
-                const componentPath = componentString.replace(/\.\w+$/, ''); // 过滤后缀名,为了让 import 加入 .vue ,不然会有警告提示...
-                const asyncComponent = defineAsyncComponent(() => import('/' + process.env.VUE_APP_ROOT + componentPath + '.vue'));
-
-                const dynamicComponent: DynamicComponent = {
-                    title: title,
-                    code: code,
-                    auth: auth?.map((e) => ({
-                        label: e.label,
-                        code: e.code,
-                    })) ?? [],
-                    component: asyncComponent
-                }
-
-                if (children?.length) {
-                    dynamicComponent.children = parseComponent(children);
-                }
-
-                result = [...result, dynamicComponent];
-            }
-        })
-
-        return result;
-    }
-
-    /**
-     * 切换组件
-     * @param index 
-     */
-    const componentChange = (index: number) => {
-        currentTabComponent.value = dynamicComponents[index];
-    }
-
-    const childrenMenu = getChildrenMenu(menucode);
-
-    if (childrenMenu) {
-        const { auth, children } = childrenMenu;
-        const components = parseComponent(children ?? []);
-
-        currentAuth.push(...auth ?? []);
-        dynamicComponents.push(...components);
-
-        if (components.length) {
-            componentChange(0);
-        }
-    }
-
-    return {
-        dynamicComponents,
-        currentAuth,
-        currentTabComponent,
-        componentChange,
-    }
-}

+ 0 - 36
src/components/base/tab-component/index.vue

@@ -1,36 +0,0 @@
-<template>
-    <div :class="['app-tab-component', direction]" v-if="dynamicComponents.length">
-        <ul class="tab">
-            <template v-for="(item, index) in dynamicComponents" :key="index">
-                <li class="tab-item" @click="componentChange(index)">
-                    <slot :name="item.code" :item="item" :index="index">{{ item.title }}</slot>
-                </li>
-            </template>
-        </ul>
-        <div class="app-tab-component__container">
-            <component :is="currentTabComponent.component" :name="currentTabComponent.code" v-bind="options"
-                v-if="currentTabComponent" />
-        </div>
-    </div>
-</template>
-
-<script lang="ts" setup>
-import { PropType } from 'vue'
-import { useDynamicComponent } from './index'
-
-const props = defineProps({
-    code: String,
-    options: Object,
-    // 组件内容方向
-    direction: {
-        type: String as PropType<'left' | 'right' | 'top' | 'bottom'>,
-        default: 'top',
-    },
-})
-
-const { dynamicComponents, currentTabComponent, componentChange } = useDynamicComponent(props.code);
-</script>
-
-<style lang="less">
-@import './index.less';
-</style>

+ 0 - 12
src/components/base/tab-component/interface.ts

@@ -1,12 +0,0 @@
-import { Component } from 'vue'
-
-/**
- * 动态组件
- */
-export interface DynamicComponent {
-    title: string,
-    code: string,
-    component: Component,
-    auth: Ermcp.AccountMenu.Auth[],
-    children?: DynamicComponent[]
-}

+ 11 - 11
src/components/base/tab/index.less

@@ -4,22 +4,22 @@
         flex-wrap: wrap;
 
         &-item {
-            display        : flex;
-            justify-content: center;
-            align-items    : center;
-            height         : 22px;
-            color          : #7a8a94;
-            cursor         : pointer;
-            border         : 1px solid #22292c;
-            padding        : 0 16px;
+            display         : flex;
+            justify-content : center;
+            align-items     : center;
+            color           : #626675;
+            cursor          : pointer;
+            border-radius   : 4px;
+            background-color: #f0f0f1;
+            padding         : 8px 16px;
 
             &:not(:first-child) {
-                border-left: 0;
+                margin-left: 10px;
             }
 
             &.active {
-                color           : #0866b8;
-                background-color: #0e2f4c;
+                color      : #222;
+                font-weight: bold;
             }
         }
     }

+ 3 - 3
src/components/base/tab/index.vue

@@ -4,7 +4,7 @@
     <ul class="app-tab__list" v-if="dataList.length">
       <li :class="['app-tab__list-item', selectedIndex === index && 'active']" v-for="(item, index) in dataList"
         :key="index" @click="onChange(index)">
-        {{ prop ? item[prop] : '标签' + index }}
+        {{ propLabel ? item[propLabel] : '标签' + index }}
       </li>
     </ul>
     <slot></slot>
@@ -26,8 +26,8 @@ const props = defineProps({
     type: Number,
     default: 0,
   },
-  // 标签对应的字段名
-  prop: {
+  // 标签显示的属性
+  propLabel: {
     type: String,
     default: 'label',
   },

+ 47 - 0
src/components/base/table/index.vue

@@ -0,0 +1,47 @@
+<template>
+    <div ref="tableElement" class="cat-table">
+        <div class="cat-table__wrapper">
+            <table class="cat-table__header" cellspacing="0" cellpadding="0">
+                <colgroup>
+                    <template v-for="i in 10" :key="i">
+                        <col width="400">
+                    </template>
+                </colgroup>
+                <thead>
+                    <tr>
+                        <template v-for="i in 10" :key="i">
+                            <th>
+                                <div class="cell">标题就是这么长{{ i }}</div>
+                            </th>
+                        </template>
+                    </tr>
+                </thead>
+            </table>
+        </div>
+        <div class="cat-table__wrapper">
+            <table class="cat-table__body" cellspacing="0" cellpadding="0">
+                <colgroup>
+                    <template v-for="i in 10" :key="i">
+                        <col width="400">
+                    </template>
+                </colgroup>
+                <tbody>
+                    <tr v-for="i in 20" :key="i">
+                        <template v-for="n in 10" :key="n">
+                            <td>
+                                <div class="cell">内容{{ i }}{{ n }}</div>
+                            </td>
+                        </template>
+                    </tr>
+                </tbody>
+            </table>
+        </div>
+    </div>
+</template>
+
+<script lang="ts" setup>
+</script>
+
+<style lang="less" scoped>
+@import './index.less';
+</style>

+ 14 - 14
src/constants/enum/chart.ts

@@ -2,14 +2,14 @@
  * 图表周期类型
  */
 export enum ChartCycleType {
-    time = -1, // 分时
-    minutes = 1, // 1分钟
-    minutes5 = 2, // 5分钟
-    minutes30 = 3, // 30分钟
-    minutes60 = 4, // 60分钟
-    hours2 = 120, // 2小时
+    Time = -1, // 分时
+    Minutes = 1, // 1分钟
+    Minutes5 = 2, // 5分钟
+    Minutes30 = 3, // 30分钟
+    Minutes60 = 4, // 60分钟
+    Hours2 = 120, // 2小时
     Hours4 = 240, // 4小时
-    days = 11, // 日线
+    Days = 11, // 日线
 }
 
 /**
@@ -28,14 +28,14 @@ export enum ChartSeriesType {
  */
 export function getChartCycleTypeList() {
     return [
-        { label: '分时', value: ChartCycleType.time },
-        { label: '1分钟', value: ChartCycleType.minutes },
-        { label: '5分钟', value: ChartCycleType.minutes5 },
-        { label: '30分钟', value: ChartCycleType.minutes30 },
-        { label: '60分钟', value: ChartCycleType.minutes60 },
-        { label: '2小时', value: ChartCycleType.hours2 },
+        { label: '分时', value: ChartCycleType.Time },
+        { label: '1分钟', value: ChartCycleType.Minutes },
+        { label: '5分钟', value: ChartCycleType.Minutes5 },
+        { label: '30分钟', value: ChartCycleType.Minutes30 },
+        { label: '60分钟', value: ChartCycleType.Minutes60 },
+        { label: '2小时', value: ChartCycleType.Hours2 },
         { label: '4小时', value: ChartCycleType.Hours4 },
-        { label: '日线', value: ChartCycleType.days },
+        { label: '日线', value: ChartCycleType.Days },
     ]
 }
 

+ 9 - 0
src/constants/enum/customer.ts

@@ -0,0 +1,9 @@
+/**
+ * 客户资料查询类型
+ */
+export enum CustomerQueryType {
+    Unsubmitted = 1, // 未提交
+    Pending = 2, // 待审核
+    Normal = 3, // 正常
+    Disabled = 4, // 停用
+}

+ 5 - 2
src/constants/enum/index.ts

@@ -1,10 +1,13 @@
+/**
+ * 枚举类型
+ */
 export interface EnumType {
     label: string;
     value: number;
 }
 
 /**
- * 获取枚举类型名称
+ * 根据枚举值获取枚举名称
  * @param list 
  * @param value 
  * @returns 
@@ -14,5 +17,5 @@ export function getEnumTypeName(list: EnumType[], value: number) {
     if (item) {
         return item.label;
     }
-    return value.toString();
+    return '--';
 }

+ 18 - 0
src/constants/enum/language.ts

@@ -0,0 +1,18 @@
+/**
+ * 系统语言
+ */
+export enum Language {
+    ZhCN = 'zh-cn',
+    EN = 'en'
+}
+
+/**
+ * 获取语言列表
+ * @returns 
+ */
+export function getLanguageList() {
+    return [
+        { label: '中文', value: Language.ZhCN },
+        { label: '英文', value: Language.EN },
+    ]
+}

+ 61 - 0
src/constants/enum/menu.ts

@@ -0,0 +1,61 @@
+import { getEnumTypeName } from './index'
+
+/**
+ * 权限类型
+ */
+export enum AuthType {
+    Menu = 1, // 菜单
+    Component = 2, // 组件
+    Button = 3, // 按钮
+}
+
+/**
+ * 链接类型
+ */
+export enum UrlType {
+    Path = 1, // 路由
+    Link = 2, // 外链
+    Iframe = 3, // 内联框架
+}
+
+/**
+ * 获取权限类型列表
+ * @returns 
+ */
+export function getAuthTypeList() {
+    return [
+        { label: '菜单', value: AuthType.Menu },
+        { label: '组件', value: AuthType.Component },
+        { label: '按钮', value: AuthType.Button },
+    ]
+}
+
+/**
+ * 获取链接类型列表
+ * @returns 
+ */
+export function getUrlTypeList() {
+    return [
+        { label: '路由', value: UrlType.Path },
+        { label: '外链', value: UrlType.Link },
+        { label: '内联框架', value: UrlType.Iframe },
+    ]
+}
+
+/**
+ * 获取权限类型名称
+ * @param value 
+ * @returns 
+ */
+export function getAuthTypeName(value: number) {
+    return getEnumTypeName(getAuthTypeList(), value);
+}
+
+/**
+ * 获取链接类型名称
+ * @param value 
+ * @returns 
+ */
+export function getUrlTypeName(value: number) {
+    return getEnumTypeName(getUrlTypeList(), value);
+}

+ 4 - 4
src/constants/enum/theme.ts

@@ -1,8 +1,8 @@
 /**
- * 系统主题色,值对应状态栏颜色
+ * 系统主题色
  */
 export enum AppTheme {
-    default = 'light',
-    dark = 'light',
-    light = 'dark'
+    Default = 'default',
+    Dark = 'light',
+    Light = 'dark'
 }

+ 18 - 2
src/filters/index.ts

@@ -12,11 +12,27 @@ export function handlePriceColor(curValue: number, preValue: number) {
 }
 
 /**
- * 处理无效值的情况
+ * 处理值的情况
  * @param value 值
  * @param suffix 后缀名
  * @returns 
  */
 export function handleNoneValue<T>(value: T, suffix = '') {
-    return value ? value + suffix : '--';
+    if (value == null || String(value) === '') {
+        return '--'
+    }
+    return value + suffix
+}
+
+/**
+ * 处理0值的情况
+ * @param value 值
+ * @param suffix 后缀名
+ * @returns 
+ */
+export function handleNumberValue(value: number, suffix = '') {
+    if (value === 0) {
+        return '--'
+    }
+    return value + suffix
 }

+ 123 - 0
src/hooks/auth/index.ts

@@ -0,0 +1,123 @@
+import { defineAsyncComponent, Component } from 'vue'
+import { useRoute } from 'vue-router'
+import { sessionCache } from '@/store'
+import { AuthType } from '@/constants/enum/menu'
+import { AuthMenu } from './interface'
+
+export function useAuth(code?: string) {
+    const route = useRoute();
+    const menus = sessionCache.getValue('menus');
+    const componentMap = new Map<string, Component>();
+
+    /**
+     * 获取权限菜单(只需到二级菜单)
+     * @returns 
+     */
+    const getAuthMenu = () => {
+        const filter = (item: Ermcp.AccountMenu, parentPath = ''): AuthMenu => ({
+            path: (parentPath ? parentPath + '/' : '') + item.url,
+            name: item.code,
+            label: item.title,
+            icon: item.icon,
+        })
+
+        return menus.reduce((res, cur) => {
+            if (cur.authType === AuthType.Menu) {
+                const item = filter(cur);
+                if (cur.children) {
+                    item.children = cur.children.map((e) => filter(e, cur.url));
+                }
+                res.push(item);
+            }
+            return res;
+        }, [] as AuthMenu[])
+    }
+
+    /**
+     * 获取权限子菜单
+     * @returns 
+     */
+    const getChildrenMenu = () => {
+        const filter = (items: Ermcp.AccountMenu[], name?: string): Ermcp.AccountMenu | undefined => {
+            if (name) {
+                for (let i = 0; i < items.length; i++) {
+                    const { code, children } = items[i];
+                    if (code === name) return items[i];
+                    if (children) {
+                        const res = filter(children, name);
+                        if (res) return res;
+                    }
+                }
+            }
+            return undefined;
+        }
+        return filter(menus, code ?? route.name?.toString());
+    }
+
+    /**
+     * 获取操作权限
+     * @returns 
+     */
+    const getAuth = (authType: AuthType) => {
+        const auth = getChildrenMenu();
+        if (auth && auth.children) {
+            return auth.children.reduce((res, cur) => {
+                if (cur.authType === authType) {
+                    if (!componentMap.get(cur.code) && cur.component) {
+                        const componentString = cur.component.replace(/^\/+/, ''); // 过滤字符串前面所有 '/' 字符
+                        const componentPath = componentString.replace(/\.\w+$/, ''); // 过滤后缀名,为了让 import 加入 .vue ,不然会有警告提示...
+                        const asyncComponent = defineAsyncComponent(() => import('/' + process.env.VUE_APP_ROOT + componentPath + '.vue'));
+                        componentMap.set(cur.code, asyncComponent);
+                    }
+                    res.push(cur);
+                }
+                return res;
+            }, [] as Ermcp.AccountMenu[])
+        }
+        return [];
+    }
+
+    /**
+     * 过滤操作权限
+     * @param filtered 过滤的数据项
+     * @param reverse 是否反向过滤
+     * @returns 
+     */
+    const authFilter = (authType: AuthType, filtered: string[], reverse: boolean) => {
+        const auth = getAuth(authType);
+        if (filtered.length) {
+            if (reverse) {
+                // 返回除指定的权限代码
+                return auth.filter((e) => !filtered.includes(e.code));
+            } else {
+                // 返回指定的权限代码
+                return auth.filter((e) => filtered.includes(e.code));
+            }
+        }
+        return auth;
+    }
+
+    /**
+     * 获取权限按钮
+     * @param filtered 
+     * @param reverse 
+     * @returns 
+     */
+    const getAuthButton = (filtered: string[] = [], reverse = false) => authFilter(AuthType.Button, filtered, reverse);
+
+    /**
+     * 获取权限组件
+     * @param filtered 
+     * @param reverse 
+     * @returns 
+     */
+    const getAuthComponent = (filtered: string[] = [], reverse = false) => authFilter(AuthType.Component, filtered, reverse);
+
+    return {
+        menus,
+        componentMap,
+        getAuthMenu,
+        getAuthButton,
+        getAuthComponent,
+    }
+}

+ 23 - 0
src/hooks/auth/interface.ts

@@ -0,0 +1,23 @@
+import { Component } from 'vue'
+
+/** 
+ * 权限菜单
+ */
+export interface AuthMenu {
+    name: string;
+    label: string;
+    path: string;
+    icon: string;
+    children?: AuthMenu[];
+}
+
+/** 
+ * 权限数据
+ */
+export interface AuthData {
+    code: string;
+    title: string;
+    icon: string;
+    buttonType: string;
+    component: Component;
+}

+ 3 - 3
src/hooks/component/index.ts

@@ -4,15 +4,15 @@ import { ref } from 'vue'
  * @param callback 组件关闭时的回调
  * @returns 
  */
-export function useComponent<T>(callback?: () => void) {
+export function useComponent(callback?: () => void) {
     // 组件名
-    const componentId = ref<keyof T>();
+    const componentId = ref<string>();
 
     /**
      * 打开组件
      * @param componentName 
      */
-    const openComponent = (componentName: keyof T) => {
+    const openComponent = (componentName: string) => {
         if (componentName) {
             console.log('打开组件:' + componentName.toString());
             componentId.value = componentName;

+ 85 - 0
src/hooks/datatable/index.ts

@@ -0,0 +1,85 @@
+import { reactive, shallowRef, toRefs, computed } from 'vue'
+import { FilterValue, FilterSelect, FilterInput, FilterButton } from './interface'
+
+export function useDataTable<T>() {
+    // 数据源
+    const dataSource = shallowRef<T[]>([])
+    // 过滤筛选值
+    const filters = shallowRef<FilterValue<T>[]>([])
+    // 过滤选项
+    const filterOptons: { selectList: FilterSelect<T>[], inputList: FilterInput<T>[], buttonList: FilterButton[] } = reactive({
+        selectList: [],
+        inputList: [],
+        buttonList: [
+            { lable: '查询', className: 'el-button--info', onClick: () => onFilter() }, // 这里 className 不应该使用框架样式,以后再处理
+            { lable: '重置', className: 'el-button--info', onClick: () => resetFilter() },
+        ]
+    })
+
+    // 数据列表
+    const dataList = computed<T[]>({
+        get() {
+            return dataSource.value.filter((row) => {
+                // 过滤所有查询条件
+                return filters.value.every((e) => {
+                    return e.keys.some((key) => {
+                        const value = row[key]
+                        if (typeof value === 'number') {
+                            return e.filteredValue.includes(String(value))
+                        }
+                        return e.filteredValue.some((text) => {
+                            return String(value).toLowerCase().indexOf(text) >= 0
+                        })
+                    })
+                })
+            })
+        },
+        set(val) {
+            dataSource.value = val
+        }
+    })
+
+    // 本地过滤,支持多条件查询
+    const onFilter = () => {
+        const options: FilterValue<T>[] = []
+        filterOptons.selectList.forEach((item) => {
+            const { key, selectedValue } = item;
+            if (selectedValue !== undefined) {
+                options.push({
+                    keys: [key],
+                    filteredValue: [selectedValue.toString()],
+                })
+            }
+        })
+        filterOptons.inputList.forEach((item) => {
+            const { keys, value } = item;
+            if (value) {
+                options.push({
+                    keys,
+                    filteredValue: [value],
+                })
+            }
+        })
+        filters.value = options
+        console.log('表格过滤参数', options)
+    }
+
+    // 远程搜索
+    const onSearch = () => {
+        console.log('用于远程搜索')
+    }
+
+    // 重置过滤项
+    const resetFilter = () => {
+        filters.value = []
+        filterOptons.selectList.forEach((e) => e.selectedValue = undefined)
+        filterOptons.inputList.forEach((e) => e.value = undefined)
+    }
+
+    return {
+        dataList,
+        onFilter,
+        onSearch,
+        ...toRefs(filterOptons),
+    }
+}

+ 11 - 8
src/packages/pc/components/base/table-filter/interface.ts → src/hooks/datatable/interface.ts

@@ -1,7 +1,7 @@
 /** 
- * 过滤项
+ * 数据过滤项
  */
-export interface FilterOption<T = unknown> {
+export interface FilterValue<T> {
     keys: (keyof T)[], // 多条件字段
     filteredValue: string[], // 多选过滤或模糊查询
 }
@@ -9,9 +9,11 @@ export interface FilterOption<T = unknown> {
 /** 
  * 过滤选择框
  */
-export interface FilterSelect<T = unknown> {
+export interface FilterSelect<T> {
     key: keyof T,
-    selectedValue: string | number,
+    label?: string,
+    selectedValue?: string | number,
+    placeholder?: string,
     options: {
         label: string,
         value: string | number,
@@ -22,10 +24,11 @@ export interface FilterSelect<T = unknown> {
 /** 
  * 过滤输入框
  */
-export interface FilterInput<T = unknown> {
+export interface FilterInput<T> {
     keys: (keyof T)[],
-    value: string,
-    placeholder: string
+    label?: string,
+    value?: string,
+    placeholder?: string
 }
 
 /** 
@@ -33,6 +36,6 @@ export interface FilterInput<T = unknown> {
  */
 export interface FilterButton {
     lable: string;
-    event: () => void;
     className?: string;
+    onClick: () => void;
 }

+ 1 - 4
src/hooks/echarts/candlestick/dataset.ts

@@ -1,6 +1,5 @@
 import { reactive } from 'vue'
 import { EchartsDataset, Candlestick, MACD } from './interface'
-import moment from 'moment'
 
 export function useDataset() {
     const dataset = reactive<EchartsDataset>({
@@ -40,9 +39,7 @@ export function useDataset() {
     // 处理行情数据
     const handleData = (rawData: Ermcp.QueryHistoryDatasRsp[], onReady?: () => void) => {
         for (let i = 0; i < rawData.length; i++) {
-            const { o, c, h, l, ts, f, tv } = rawData[i];
-            const date = moment(ts).format('YYYY-MM-DD HH:mm:ss');
-
+            const { o, c, h, l, ts: date, f, tv } = rawData[i];
             if (f) dataset.invalid.push(i); // 添加补充数据的索引位置
 
             dataset.candlestick.source.push({

+ 6 - 6
src/hooks/echarts/candlestick/index.ts

@@ -14,7 +14,7 @@ export function useCandlestickChart(goodscode: string) {
     const loading = ref(false);
     const isEmpty = ref(true);
     const dataIndex = ref(-1); // 当前数据索引值
-    const cycleType = ref(ChartCycleType.minutes);
+    const cycleType = ref(ChartCycleType.Minutes);
     const quote = getQuoteDayInfoByCode(goodscode); // 实时行情
 
     // 当前选中的数据项
@@ -87,22 +87,22 @@ export function useCandlestickChart(goodscode: string) {
     const getCycleMilliseconds = () => {
         const milliseconds = 60 * 1000; // 一分钟毫秒数
         switch (cycleType.value) {
-            case ChartCycleType.minutes5: {
+            case ChartCycleType.Minutes5: {
                 return milliseconds * 5;
             }
-            case ChartCycleType.minutes30: {
+            case ChartCycleType.Minutes30: {
                 return milliseconds * 30;
             }
-            case ChartCycleType.minutes60: {
+            case ChartCycleType.Minutes60: {
                 return milliseconds * 60;
             }
-            case ChartCycleType.hours2: {
+            case ChartCycleType.Hours2: {
                 return milliseconds * 2 * 60;
             }
             case ChartCycleType.Hours4: {
                 return milliseconds * 4 * 60;
             }
-            case ChartCycleType.days: {
+            case ChartCycleType.Days: {
                 return milliseconds * 24 * 60;
             }
             default: {

+ 38 - 11
src/hooks/echarts/candlestick/options.ts

@@ -10,10 +10,10 @@ const theme = localCache.getRef('appTheme');
 function getColors() {
     // 默认主题色配置
     const defaultColors: Colors = {
-        upColor: '#eb5454',
-        downColor: '#47b262',
-        xAxisLineColor: '#171b1d',
-        yAxisLineColor: '#171b1d',
+        upColor: '#ff3333',
+        downColor: '#0aab62',
+        xAxisLineColor: 'rgba(128,128,128,.1)',
+        yAxisLineColor: 'rgba(128,128,128,.1)',
     }
 
     const colors = {
@@ -45,6 +45,13 @@ export function useOptions(dataset: EchartsDataset) {
         const { xAxisLineColor } = options.colors;
 
         return {
+            grid: {
+                left: '10px',
+                right: '10px',
+                top: '15px',
+                bottom: '10px',
+                containLabel: true,
+            },
             dataZoom: {
                 type: 'inside',
                 startValue: source.length - 120, // 起始显示K线条数(最新120条)
@@ -52,12 +59,25 @@ export function useOptions(dataset: EchartsDataset) {
                 minValueSpan: 50, // 限制窗口缩放显示最少数据条数
                 maxValueSpan: 400, // 限制窗口缩放显示最大数据条数
             },
+            axisPointer: {
+                label: {
+                    backgroundColor: 'rgba(128,128,128,.75)'
+                }
+            },
             xAxis: {
                 type: 'category',
                 axisLabel: {
                     formatter: (val: string) => moment(val).format('YYYY/MM/DD'),
                     margin: 12,
                 },
+                axisPointer: {
+                    label: {
+                        formatter: (params) => moment(params.value).format('YYYY/MM/DD HH:mm:ss'),
+                    }
+                },
+                axisTick: {
+                    show: false,
+                }
             },
             yAxis: {
                 scale: true,
@@ -74,6 +94,8 @@ export function useOptions(dataset: EchartsDataset) {
     // K线配置项
     const setCandlestickOption = () => {
         const { dimensions, source } = dataset.candlestick;
+        const { upColor, downColor } = options.colors;
+
         options.candlestick = {
             ...getDefaultOption(),
             dataset: {
@@ -84,22 +106,27 @@ export function useOptions(dataset: EchartsDataset) {
                 {
                     name: 'K线',
                     type: 'candlestick',
+                    itemStyle: {
+                        color: upColor,
+                        color0: downColor,
+                        borderColor: upColor,
+                        borderColor0: downColor,
+                    },
                     // 最新价标线
                     markLine: {
-                        // 标线两端图标
-                        symbol: 'none',
+                        symbolSize: 6,
                         // 标线标签样式
                         label: {
-                            color: '#444',
-                            fontWeight: 'bold',
-                            backgroundColor: 'rgba(255,255,255,.75)',
+                            color: '#fff',
+                            backgroundColor: 'rgba(128,128,128,.75)',
                             padding: 5,
-                            borderRadius: 3
+                            borderRadius: 3,
+                            position: 'insideStartTop',
                         },
                         // 标线样式
                         lineStyle: {
                             type: 'dashed',
-                            color: 'rgba(255,255,255,.3)'
+                            color: 'rgba(102,102,102,.6)'
                         },
                         data: [
                             {

+ 1 - 4
src/hooks/echarts/timeline/dataset.ts

@@ -1,7 +1,6 @@
 import { reactive } from 'vue'
 import { getRangeTime } from '@/utils/time'
 import { EchartsDataset } from './interface'
-import moment from 'moment'
 
 export function useDataset() {
     const dataset = reactive<EchartsDataset>({
@@ -55,11 +54,9 @@ export function useDataset() {
 
         for (let i = 0; i < historyDatas.length; i++) {
             const { ts, c, f } = historyDatas[i];
-            const d = moment(ts).format('YYYY-MM-DD HH:mm:ss');
-
             if (f) dataset.invalid.push(i); // 添加补充数据的索引位置
 
-            dataset.rawDate.push(d);
+            dataset.rawDate.push(ts);
             close.push(c);
             ma5.push('-');
         }

+ 34 - 20
src/hooks/echarts/timeline/options.ts

@@ -10,26 +10,26 @@ const theme = localCache.getRef('appTheme');
 function getColors() {
     // 默认主题色配置
     const defaultColors: Colors = {
-        upColor: '#FF2B2B',
-        downColor: '#1FF195',
-        xAxisLineColor: '#171B1D',
-        yAxisLineColor: '#171B1D',
-        seriesLineColor: '#39afe6',
-        seriesMarkLabelColor: '#3C454B',
-        seriesMarkLineColor: '#666',
+        upColor: '#ff3333',
+        downColor: '#0aab62',
+        xAxisLineColor: 'rgba(128,128,128,.1)',
+        yAxisLineColor: 'rgba(128,128,128,.1)',
+        seriesLineColor: '#50b4eb',
         seriesAreaGradients: new echarts.graphic.LinearGradient(0, 0, 0, 1,
             [
                 {
                     offset: 0,
-                    color: 'rgba(0, 136, 212, 0.3)',
+                    color: 'rgba(80, 180, 235, .2)',
                 },
                 {
                     offset: 1,
-                    color: 'rgba(0, 136, 212, 0.3)',
+                    color: 'rgba(80, 180, 235, .15)',
                 },
             ],
             false
         ),
+        seriesMarkLabelColor: '#fff',
+        seriesMarkLineColor: 'rgba(102,102,102,.6)'
     }
 
     const colors = {
@@ -77,10 +77,17 @@ export function useOptions(dataset: EchartsDataset) {
 
         options.timeline = {
             dataset: timeline,
+            grid: {
+                left: '10px',
+                right: '10px',
+                top: '15px',
+                bottom: '10px',
+                containLabel: true,
+            },
             axisPointer: {
                 label: {
-                    // 小数点精度
-                    precision: decimal,
+                    precision: decimal, // 小数点精度
+                    backgroundColor: 'rgba(128,128,128,.75)',
                 }
             },
             xAxis: {
@@ -90,6 +97,9 @@ export function useOptions(dataset: EchartsDataset) {
                     showMaxLabel: true,
                     margin: 12,
                 },
+                axisTick: {
+                    show: false,
+                }
             },
             yAxis: [
                 {
@@ -154,30 +164,33 @@ export function useOptions(dataset: EchartsDataset) {
                     },
                     areaStyle: {
                         color: colors.seriesAreaGradients,
-                        shadowColor: 'rgba(0, 0, 0, 0.1)',
-                        shadowBlur: 10,
+                        opacity: 1,
                     },
                     // 标线
                     markLine: {
-                        // 标线两端图标
-                        symbol: 'none',
+                        symbolSize: 6,
                         // 标线标签样式
                         label: {
-                            color: colors.seriesMarkLabelColor,
-                            fontWeight: 'bold',
-                            backgroundColor: 'rgba(255,255,255,.75)',
+                            show: false,
+                            backgroundColor: 'rgba(128,128,128,.75)',
                             padding: 5,
-                            borderRadius: 3
+                            borderRadius: 3,
+                            position: 'insideStartTop',
                         },
                         // 标线样式
                         lineStyle: {
                             type: 'dashed',
+                            color: 'rgba(128,128,128,.3)'
                         },
                         data: [
                             {
                                 yAxis: timeline.source.close[timeline.source.close.length - 1] ?? '--', // 最新价
+                                label: {
+                                    show: true,
+                                    color: colors.seriesMarkLabelColor,
+                                },
                                 lineStyle: {
-                                    color: colors.seriesMarkLineColor
+                                    color: colors.seriesMarkLineColor,
                                 },
                             },
                             {
@@ -195,6 +208,7 @@ export function useOptions(dataset: EchartsDataset) {
                     lineStyle: {
                         width: 1,
                         opacity: 0.8,
+                        color: '#ffcc00',
                     },
                 },
             ],

+ 0 - 79
src/hooks/menu/index.ts

@@ -1,79 +0,0 @@
-import { useRoute } from 'vue-router'
-import { sessionCache } from '@/store'
-import { AuthMenu } from './interface'
-
-export function useMenu() {
-    const route = useRoute();
-    const auth = route.meta.auth as Ermcp.AccountMenu.Auth[];
-    const menus = sessionCache.getValue('menus');
-
-    /**
-     * 通过code获取对应的子菜单
-     * @param menucode 
-     * @returns 
-     */
-    const getChildrenMenu = (menucode?: string) => {
-        const filter = (items: Ermcp.AccountMenu[], name?: string): Ermcp.AccountMenu | undefined => {
-            if (name) {
-                for (let i = 0; i < items.length; i++) {
-                    const { code, children } = items[i];
-                    if (code === name) return items[i];
-                    if (children) {
-                        const res = filter(children, name);
-                        if (res) return res;
-                    }
-                }
-            }
-            return undefined;
-        }
-        return filter(menus, menucode ?? route.name?.toString());
-    }
-
-    /**
-     * 获取权限菜单
-     * @returns 
-     */
-    const getAuthMenu = () => {
-        const filter = (menu: Ermcp.AccountMenu) => ({
-            path: menu.path,
-            name: menu.code,
-            label: menu.title,
-            icon: menu.icon,
-        })
-
-        return menus.map((menu) => {
-            const result: AuthMenu = filter(menu);
-            if (menu.children) {
-                result.children = menu.children.map((child) => filter(child));
-            }
-            return result;
-        })
-    }
-
-    /**
-     * 过滤操作权限
-     * @param filtered 过滤的数据项
-     * @param reverse 是否反向过滤
-     * @returns 
-     */
-    const authFilter = (filtered: string[] = [], reverse = false) => {
-        if (filtered.length) {
-            if (reverse) {
-                // 返回除指定的权限代码
-                return auth.filter((e) => !filtered.includes(e.code));
-            } else {
-                // 返回指定的权限代码
-                return auth.filter((e) => filtered.includes(e.code));
-            }
-        }
-        return auth;
-    }
-
-    return {
-        menus,
-        auth,
-        getChildrenMenu,
-        authFilter,
-        getAuthMenu,
-    }
-}

+ 0 - 10
src/hooks/menu/interface.ts

@@ -1,10 +0,0 @@
-/** 
- * 权限菜单
- */
-export interface AuthMenu {
-    path: string;
-    name: string;
-    label: string;
-    icon: string;
-    children?: AuthMenu[];
-}

+ 19 - 12
src/hooks/theme/index.ts

@@ -10,30 +10,37 @@ export default new (class {
         document.addEventListener('DOMContentLoaded', this.loadTheme, false);
     }
 
+    private setStatusBarTheme = (theme: AppTheme) => {
+        switch (theme) {
+            case AppTheme.Default:
+            case AppTheme.Dark: {
+                plus.setStatusBarStyle('light');
+                break
+            }
+            default: {
+                plus.setStatusBarStyle('dark');
+            }
+        }
+    }
+
     /**
      * 加载主题
      */
-    private loadTheme() {
+    private loadTheme = () => {
         const theme = localCache.getValue('appTheme');
-        const statusBarStyle = AppTheme[theme];
-
+        this.setStatusBarTheme(theme);
         document.documentElement.setAttribute('theme', theme);
-        plus.setStatusBarStyle(statusBarStyle);
         document.removeEventListener('DOMContentLoaded', this.loadTheme);
     }
 
     /**
      * 设置主题
-     * @param theme 
+     * @param themeKey 
      */
-    setTheme(theme: keyof typeof AppTheme) {
-        const statusBarStyle = AppTheme[theme];
-
+    setTheme = (themeKey: keyof typeof AppTheme) => {
+        const theme = AppTheme[themeKey];
+        this.setStatusBarTheme(theme);
         document.documentElement.setAttribute('theme', theme);
         localCache.setValue('appTheme', theme);
-
-        if (statusBarStyle) {
-            plus.setStatusBarStyle(statusBarStyle);
-        }
     }
 })

+ 38 - 13
src/mock/account.ts

@@ -1,21 +1,10 @@
-const getLoginId = {
-    url: '/User/GetLoginID',
-    type: 'get',
-    response: {
-        code: 200,
-        msg: 'success',
-        total: 0,
-        data: '133900000005'
-    }
-}
-
 const login = {
     url: '/account/login',
     type: 'post',
     response: {
         code: 200,
         msg: 'success',
-        total: 0,
+        total: 1,
         data: {
             id: 1000,
             userName: 'teamwei',
@@ -26,7 +15,43 @@ const login = {
     }
 }
 
+const getLoginId = {
+    url: '/User/GetLoginID',
+    type: 'get',
+    response: {
+        code: 200,
+        msg: 'success',
+        total: 0,
+        data: '133900000005'
+    }
+}
+
+const getAccountRole = {
+    url: '/account/role',
+    type: 'get',
+    response: {
+        code: 200,
+        message: 'success',
+        total: 2,
+        data: [
+            {
+                id: 1,
+                roleName: '管理员',
+                createdAt: '@datetime()',
+                updatedAt: '@datetime()'
+            },
+            {
+                id: 2,
+                roleName: '审核员',
+                createdAt: '@datetime()',
+                updatedAt: '@datetime()'
+            }
+        ]
+    }
+}
+
 export default [
-    getLoginId,
     login,
+    getLoginId,
+    getAccountRole,
 ]

Some files were not shown because too many files changed in this diff