Yan 4 年之前
父节点
当前提交
6852363f2a
共有 100 个文件被更改,包括 4873 次插入0 次删除
  1. 23 0
      .gitignore
  2. 21 0
      LICENSE
  3. 22 0
      index.html
  4. 700 0
      package-lock.json
  5. 31 0
      package.json
  6. 12 0
      public/detailConfig.json
  7. 16 0
      public/simpleConfig.json
  8. 41 0
      public/table.json
  9. 二进制
      screenshots/wms1.png
  10. 二进制
      screenshots/wms3.png
  11. 12 0
      src/App.vue
  12. 2 0
      src/api/_prefix.js
  13. 18 0
      src/api/index.js
  14. 114 0
      src/api/model.js
  15. 28 0
      src/assets/css/color-dark.css
  16. 4 0
      src/assets/css/icon.css
  17. 177 0
      src/assets/css/main.css
  18. 二进制
      src/assets/img/img.jpg
  19. 二进制
      src/assets/img/login-bg.jpg
  20. 162 0
      src/components/Header.vue
  21. 159 0
      src/components/Sidebar.vue
  22. 183 0
      src/components/Tags.vue
  23. 12 0
      src/main.js
  24. 17 0
      src/plugins/element.js
  25. 167 0
      src/router/index.js
  26. 56 0
      src/store/index.js
  27. 24 0
      src/utils/i18n.js
  28. 34 0
      src/utils/request.js
  29. 62 0
      src/views/403.vue
  30. 62 0
      src/views/404.vue
  31. 174 0
      src/views/BaseCharts.vue
  32. 174 0
      src/views/BaseForm.vue
  33. 279 0
      src/views/Config.vue
  34. 170 0
      src/views/ConfigForm.vue
  35. 198 0
      src/views/Dashboard.vue
  36. 139 0
      src/views/Dllearning.vue
  37. 26 0
      src/views/Donate.vue
  38. 58 0
      src/views/Editor.vue
  39. 44 0
      src/views/Home.vue
  40. 40 0
      src/views/I18n.vue
  41. 229 0
      src/views/Icon.vue
  42. 125 0
      src/views/Login.vue
  43. 40 0
      src/views/Permission.vue
  44. 137 0
      src/views/Tabs.vue
  45. 133 0
      src/views/Upload.vue
  46. 192 0
      src/views/User.vue
  47. 196 0
      src/views/dlform.vue
  48. 9 0
      vite.config.js
  49. 二进制
      参考/web前端结构.docx
  50. 二进制
      参考/~$eb前端结构.docx
  51. 49 0
      参考/会议记录/1月28日-2月4日.md
  52. 二进制
      参考/接口.xlsx
  53. 二进制
      参考/接口测试.pdf
  54. 二进制
      参考/接口测试md/接口测试.assets/image-20220207152620531.png
  55. 二进制
      参考/接口测试md/接口测试.assets/image-20220207152908085.png
  56. 二进制
      参考/接口测试md/接口测试.assets/image-20220207153409659.png
  57. 二进制
      参考/接口测试md/接口测试.assets/image-20220207162707754.png
  58. 二进制
      参考/接口测试md/接口测试.assets/image-20220207163557482.png
  59. 二进制
      参考/接口测试md/接口测试.assets/image-20220207163711420.png
  60. 二进制
      参考/接口测试md/接口测试.assets/image-20220207163917993.png
  61. 二进制
      参考/接口测试md/接口测试.assets/image-20220207163943482.png
  62. 二进制
      参考/接口测试md/接口测试.assets/image-20220207164150453.png
  63. 二进制
      参考/接口测试md/接口测试.assets/image-20220207164158117.png
  64. 二进制
      参考/接口测试md/接口测试.assets/image-20220207164445827.png
  65. 二进制
      参考/接口测试md/接口测试.assets/image-20220207164636503.png
  66. 二进制
      参考/接口测试md/接口测试.assets/image-20220207164651547.png
  67. 二进制
      参考/接口测试md/接口测试.assets/image-20220207165209667.png
  68. 二进制
      参考/接口测试md/接口测试.assets/image-20220207165314803.png
  69. 二进制
      参考/接口测试md/接口测试.assets/image-20220207165510867.png
  70. 二进制
      参考/接口测试md/接口测试.assets/image-20220207165530711.png
  71. 二进制
      参考/接口测试md/接口测试.assets/image-20220207165753287.png
  72. 二进制
      参考/接口测试md/接口测试.assets/image-20220207165837625.png
  73. 二进制
      参考/接口测试md/接口测试.assets/image-20220207165913815.png
  74. 二进制
      参考/接口测试md/接口测试.assets/image-20220207170139844.png
  75. 二进制
      参考/接口测试md/接口测试.assets/image-20220207170203829.png
  76. 二进制
      参考/接口测试md/接口测试.assets/image-20220207170315922.png
  77. 二进制
      参考/接口测试md/接口测试.assets/image-20220207170318027.png
  78. 二进制
      参考/接口测试md/接口测试.assets/image-20220207170415247.png
  79. 二进制
      参考/接口测试md/接口测试.assets/image-20220207170606466.png
  80. 二进制
      参考/接口测试md/接口测试.assets/image-20220207170756540.png
  81. 二进制
      参考/接口测试md/接口测试.assets/image-20220207170907495.png
  82. 二进制
      参考/接口测试md/接口测试.assets/image-20220207170922376.png
  83. 二进制
      参考/接口测试md/接口测试.assets/image-20220207171144766.png
  84. 二进制
      参考/接口测试md/接口测试.assets/image-20220207171204233.png
  85. 二进制
      参考/接口测试md/接口测试.assets/image-20220207171358274.png
  86. 二进制
      参考/接口测试md/接口测试.assets/image-20220207171409716.png
  87. 二进制
      参考/接口测试md/接口测试.assets/image-20220207171530951.png
  88. 二进制
      参考/接口测试md/接口测试.assets/image-20220207171615446.png
  89. 二进制
      参考/接口测试md/接口测试.assets/modelAdd.jpg
  90. 二进制
      参考/接口测试md/接口测试.assets/modelAddResult.jpg
  91. 二进制
      参考/接口测试md/接口测试.assets/modelDelResult.jpg
  92. 二进制
      参考/接口测试md/接口测试.assets/upload结果.jpg
  93. 二进制
      参考/接口测试md/接口测试.assets/文件上传.jpg
  94. 二进制
      参考/接口测试md/接口测试.assets/注册测试成功.jpg
  95. 302 0
      参考/接口测试md/接口测试.md
  96. 二进制
      参考/服务器后端启动办法.pdf
  97. 二进制
      参考/服务器后端启动办法md/服务器后端启动办法.assets/image-20220207151426948.png
  98. 二进制
      参考/服务器后端启动办法md/服务器后端启动办法.assets/image-20220207151443142.png
  99. 二进制
      参考/服务器后端启动办法md/服务器后端启动办法.assets/image-20220207151613175.png
  100. 二进制
      参考/服务器后端启动办法md/服务器后端启动办法.assets/image-20220207151710148.png

+ 23 - 0
.gitignore

@@ -0,0 +1,23 @@
+.DS_Store
+node_modules
+/dist
+
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016-2021 vue-manage-system
+
+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.

+ 22 - 0
index.html

@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html lang="">
+
+<head>
+  <meta charset="utf-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="viewport" content="width=device-width,initial-scale=1.0">
+  <title>vue-manage-system</title>
+  <link rel="stylesheet" href="https://at.alicdn.com/t/font_830376_qzecyukz0s.css">
+</head>
+
+<body>
+  <noscript>
+    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
+      Please enable it to continue.</strong>
+  </noscript>
+  <div id="app"></div>
+  <script type="module" src="/src/main.js"></script>
+  <!-- built files will be auto injected -->
+</body>
+
+</html>

+ 700 - 0
package-lock.json

@@ -0,0 +1,700 @@
+{
+  "name": "vue-manage-system",
+  "version": "5.1.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "@babel/helper-validator-identifier": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz",
+      "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg=="
+    },
+    "@babel/parser": {
+      "version": "7.14.7",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.7.tgz",
+      "integrity": "sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA=="
+    },
+    "@babel/runtime": {
+      "version": "7.14.6",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.6.tgz",
+      "integrity": "sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==",
+      "requires": {
+        "regenerator-runtime": "^0.13.4"
+      }
+    },
+    "@babel/runtime-corejs3": {
+      "version": "7.14.7",
+      "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.7.tgz",
+      "integrity": "sha512-Wvzcw4mBYbTagyBVZpAJWI06auSIj033T/yNE0Zn1xcup83MieCddZA7ls3kme17L4NOGBrQ09Q+nKB41RLWBA==",
+      "requires": {
+        "core-js-pure": "^3.15.0",
+        "regenerator-runtime": "^0.13.4"
+      }
+    },
+    "@babel/types": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz",
+      "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==",
+      "requires": {
+        "@babel/helper-validator-identifier": "^7.14.5",
+        "to-fast-properties": "^2.0.0"
+      }
+    },
+    "@intlify/core-base": {
+      "version": "9.1.6",
+      "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.6.tgz",
+      "integrity": "sha512-d5GDPpsQbqPkisSJA5b6nJFEkalY/IHAd7vOLNd/Sj4YaNRzXtInu2FoqKiOv8e/lQnXGTpurdCZg5Jxq1Gsxw==",
+      "requires": {
+        "@intlify/devtools-if": "9.1.6",
+        "@intlify/message-compiler": "9.1.6",
+        "@intlify/message-resolver": "9.1.6",
+        "@intlify/runtime": "9.1.6",
+        "@intlify/shared": "9.1.6",
+        "@intlify/vue-devtools": "9.1.6"
+      }
+    },
+    "@intlify/devtools-if": {
+      "version": "9.1.6",
+      "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.1.6.tgz",
+      "integrity": "sha512-m8Api+kh+BtFa2FZ/JjIdr1ibsGGqBjdKCzWo5BZecEUxBquIeOQZwpokPh/0K5j+/PZleFXkVAMC5mNt+9WdA==",
+      "requires": {
+        "@intlify/shared": "9.1.6"
+      }
+    },
+    "@intlify/message-compiler": {
+      "version": "9.1.6",
+      "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.1.6.tgz",
+      "integrity": "sha512-DR8645VOrVK6x/8tkaCpHnckMAIcoOgeNS5j0wB12RfZoXYQp7vAXMaOP511KMll2mXCREgIB0ojpajiof7yzQ==",
+      "requires": {
+        "@intlify/message-resolver": "9.1.6",
+        "@intlify/shared": "9.1.6",
+        "source-map": "0.6.1"
+      }
+    },
+    "@intlify/message-resolver": {
+      "version": "9.1.6",
+      "resolved": "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.6.tgz",
+      "integrity": "sha512-UUnbawQa5U9sffd5wRIscqtyY1xWlwJbyfwCLPEWLvBhyAnCwPYlvaHGnnO0CSi0fzJTVwlV9DYzobh3agDeMA=="
+    },
+    "@intlify/runtime": {
+      "version": "9.1.6",
+      "resolved": "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.1.6.tgz",
+      "integrity": "sha512-U1QZ+TPf3kQQvWo4BA2mj3cHAxMRHXNTBhu2u+deh6ubTqXdZ19XGBTMSasrXG6RE+zSio9oM+ndoLja7JGtPg==",
+      "requires": {
+        "@intlify/message-compiler": "9.1.6",
+        "@intlify/message-resolver": "9.1.6",
+        "@intlify/shared": "9.1.6"
+      }
+    },
+    "@intlify/shared": {
+      "version": "9.1.6",
+      "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.6.tgz",
+      "integrity": "sha512-6MtsKulyfZxdD7OuxjaODjj8QWoHCnLFAk4wkWiHqBCa6UCTC0qXjtEeZ1MxpQihvFmmJZauBUu25EvtngW5qQ=="
+    },
+    "@intlify/vue-devtools": {
+      "version": "9.1.6",
+      "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.1.6.tgz",
+      "integrity": "sha512-UdNovg4OML9rIr1sOGZzTfNr1nUy4UQpDf5ni4dNC93T6FIkVJz0n1Np7Vp7e6gDjcmufRYcV99tEwjQSN9+5A==",
+      "requires": {
+        "@intlify/message-resolver": "9.1.6",
+        "@intlify/runtime": "9.1.6",
+        "@intlify/shared": "9.1.6"
+      }
+    },
+    "@popperjs/core": {
+      "version": "2.9.2",
+      "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.2.tgz",
+      "integrity": "sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q=="
+    },
+    "@types/estree": {
+      "version": "0.0.48",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz",
+      "integrity": "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew==",
+      "dev": true
+    },
+    "@types/lodash": {
+      "version": "4.14.170",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.170.tgz",
+      "integrity": "sha512-bpcvu/MKHHeYX+qeEN8GE7DIravODWdACVA1ctevD8CN24RhPZIKMn9ntfAsrvLfSX3cR5RrBKAbYm9bGs0A+Q=="
+    },
+    "@vitejs/plugin-vue": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-1.2.3.tgz",
+      "integrity": "sha512-LlnLpObkGKZ+b7dcpL4T24l13nPSHLjo+6Oc7MbZiKz5PMAUzADfNJ3EKfYIQ0l0969nxf2jp/9vsfnuJ7h6fw==",
+      "dev": true
+    },
+    "@vue/compiler-core": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.1.2.tgz",
+      "integrity": "sha512-nHmq7vLjq/XM2IMbZUcKWoH5sPXa2uR/nIKZtjbK5F3TcbnYE/zKsrSUR9WZJ03unlwotNBX1OyxVt9HbWD7/Q==",
+      "requires": {
+        "@babel/parser": "^7.12.0",
+        "@babel/types": "^7.12.0",
+        "@vue/shared": "3.1.2",
+        "estree-walker": "^2.0.1",
+        "source-map": "^0.6.1"
+      }
+    },
+    "@vue/compiler-dom": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.1.2.tgz",
+      "integrity": "sha512-k2+SWcWH0jL6WQAX7Or2ONqu5MbtTgTO0dJrvebQYzgqaKMXNI90RNeWeCxS4BnNFMDONpHBeFgbwbnDWIkmRg==",
+      "requires": {
+        "@vue/compiler-core": "3.1.2",
+        "@vue/shared": "3.1.2"
+      }
+    },
+    "@vue/compiler-sfc": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.1.2.tgz",
+      "integrity": "sha512-SeG/2+DvwejQ7oAiSx8BrDh5qOdqCYHGClPiTvVIHTfSIHiS2JjMbCANdDCjHkTOh/O7WZzo2JhdKm98bRBxTw==",
+      "dev": true,
+      "requires": {
+        "@babel/parser": "^7.13.9",
+        "@babel/types": "^7.13.0",
+        "@types/estree": "^0.0.48",
+        "@vue/compiler-core": "3.1.2",
+        "@vue/compiler-dom": "3.1.2",
+        "@vue/compiler-ssr": "3.1.2",
+        "@vue/shared": "3.1.2",
+        "consolidate": "^0.16.0",
+        "estree-walker": "^2.0.1",
+        "hash-sum": "^2.0.0",
+        "lru-cache": "^5.1.1",
+        "magic-string": "^0.25.7",
+        "merge-source-map": "^1.1.0",
+        "postcss": "^8.1.10",
+        "postcss-modules": "^4.0.0",
+        "postcss-selector-parser": "^6.0.4",
+        "source-map": "^0.6.1"
+      }
+    },
+    "@vue/compiler-ssr": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.1.2.tgz",
+      "integrity": "sha512-BwXo9LFk5OSWdMyZQ4bX1ELHX0Z/9F+ld/OaVnpUPzAZCHslBYLvyKUVDwv2C/lpLjRffpC2DOUEdl1+RP1aGg==",
+      "dev": true,
+      "requires": {
+        "@vue/compiler-dom": "3.1.2",
+        "@vue/shared": "3.1.2"
+      }
+    },
+    "@vue/devtools-api": {
+      "version": "6.0.0-beta.14",
+      "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.0.0-beta.14.tgz",
+      "integrity": "sha512-44fPrrN1cqcs6bFkT0C+yxTM6PZXLbR+ESh1U1j8UD22yO04gXvxH62HApMjLbS3WqJO/iCNC+CYT+evPQh2EQ=="
+    },
+    "@vue/reactivity": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.2.tgz",
+      "integrity": "sha512-glJzJoN2xE7I2lRvwKM5u1BHRPTd1yc8iaf//Lai/78/uYAvE5DXp5HzWRFOwMlbRvMGJHIQjOqoxj87cDAaag==",
+      "requires": {
+        "@vue/shared": "3.1.2"
+      }
+    },
+    "@vue/runtime-core": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.1.2.tgz",
+      "integrity": "sha512-gsPZG4dRIkixuuKmoj4P9IHgfT0yaFLcqWOM5F/bCk0nxQn1XtxH8oUehWuET726KhbukvDoJfe9G2CKviy80w==",
+      "requires": {
+        "@vue/reactivity": "3.1.2",
+        "@vue/shared": "3.1.2"
+      }
+    },
+    "@vue/runtime-dom": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.1.2.tgz",
+      "integrity": "sha512-QvINxjLucEZFzp5f0NVu7JqWYCv5TKQfkH2FDs/N6QNE4iKcYtKrWdT0HKfABnVXG28Znqv6rIH0dH4ZAOwxpA==",
+      "requires": {
+        "@vue/runtime-core": "3.1.2",
+        "@vue/shared": "3.1.2",
+        "csstype": "^2.6.8"
+      }
+    },
+    "@vue/shared": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.2.tgz",
+      "integrity": "sha512-EmH/poaDWBPJaPILXNI/1fvUbArJQmmTyVCwvvyDYDFnkPoTclAbHRAtyIvqfez7jybTDn077HTNILpxlsoWhg=="
+    },
+    "async-validator": {
+      "version": "3.5.2",
+      "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-3.5.2.tgz",
+      "integrity": "sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ=="
+    },
+    "axios": {
+      "version": "0.21.1",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
+      "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
+      "requires": {
+        "follow-redirects": "^1.10.0"
+      }
+    },
+    "big.js": {
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
+      "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
+      "dev": true
+    },
+    "bluebird": {
+      "version": "3.7.2",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+      "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+      "dev": true
+    },
+    "colorette": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz",
+      "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==",
+      "dev": true
+    },
+    "consolidate": {
+      "version": "0.16.0",
+      "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.16.0.tgz",
+      "integrity": "sha512-Nhl1wzCslqXYTJVDyJCu3ODohy9OfBMB5uD2BiBTzd7w+QY0lBzafkR8y8755yMYHAaMD4NuzbAw03/xzfw+eQ==",
+      "dev": true,
+      "requires": {
+        "bluebird": "^3.7.2"
+      }
+    },
+    "core-js-pure": {
+      "version": "3.15.1",
+      "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.15.1.tgz",
+      "integrity": "sha512-OZuWHDlYcIda8sJLY4Ec6nWq2hRjlyCqCZ+jCflyleMkVt3tPedDVErvHslyS2nbO+SlBFMSBJYvtLMwxnrzjA=="
+    },
+    "cropperjs": {
+      "version": "1.5.12",
+      "resolved": "https://registry.npmjs.org/cropperjs/-/cropperjs-1.5.12.tgz",
+      "integrity": "sha512-re7UdjE5UnwdrovyhNzZ6gathI4Rs3KGCBSc8HCIjUo5hO42CtzyblmWLj6QWVw7huHyDMfpKxhiO2II77nhDw=="
+    },
+    "cssesc": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+      "dev": true
+    },
+    "csstype": {
+      "version": "2.6.17",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.17.tgz",
+      "integrity": "sha512-u1wmTI1jJGzCJzWndZo8mk4wnPTZd1eOIYTYvuEyOQGfmDl3TrabCCfKnOC86FZwW/9djqTl933UF/cS425i9A=="
+    },
+    "dayjs": {
+      "version": "1.10.5",
+      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.5.tgz",
+      "integrity": "sha512-BUFis41ikLz+65iH6LHQCDm4YPMj5r1YFLdupPIyM4SGcXMmtiLQ7U37i+hGS8urIuqe7I/ou3IS1jVc4nbN4g=="
+    },
+    "element-plus": {
+      "version": "1.0.2-beta.52",
+      "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-1.0.2-beta.52.tgz",
+      "integrity": "sha512-oAuJHwXyvM4dsuOz7HSDPIBVPqRJ1KEzFzGqYdqbBjQ/aw79uCJxvS9Q4q9/XrPMfPire09+bPTypiIaHkNBhA==",
+      "requires": {
+        "@popperjs/core": "^2.4.4",
+        "@types/lodash": "^4.14.161",
+        "async-validator": "^3.4.0",
+        "dayjs": "1.x",
+        "lodash": "^4.17.20",
+        "mitt": "^2.1.0",
+        "normalize-wheel": "^1.0.1",
+        "resize-observer-polyfill": "^1.5.1"
+      }
+    },
+    "emojis-list": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
+      "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
+      "dev": true
+    },
+    "esbuild": {
+      "version": "0.12.9",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.9.tgz",
+      "integrity": "sha512-MWRhAbMOJ9RJygCrt778rz/qNYgA4ZVj6aXnNPxFjs7PmIpb0fuB9Gmg5uWrr6n++XKwwm/RmSz6RR5JL2Ocsw==",
+      "dev": true
+    },
+    "estree-walker": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
+    },
+    "follow-redirects": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz",
+      "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg=="
+    },
+    "fsevents": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+      "dev": true,
+      "optional": true
+    },
+    "function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+      "dev": true
+    },
+    "generic-names": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-2.0.1.tgz",
+      "integrity": "sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ==",
+      "dev": true,
+      "requires": {
+        "loader-utils": "^1.1.0"
+      }
+    },
+    "has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "dev": true,
+      "requires": {
+        "function-bind": "^1.1.1"
+      }
+    },
+    "hash-sum": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz",
+      "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==",
+      "dev": true
+    },
+    "icss-replace-symbols": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz",
+      "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=",
+      "dev": true
+    },
+    "icss-utils": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
+      "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
+      "dev": true
+    },
+    "is-core-module": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz",
+      "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==",
+      "dev": true,
+      "requires": {
+        "has": "^1.0.3"
+      }
+    },
+    "json5": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+      "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+      "dev": true,
+      "requires": {
+        "minimist": "^1.2.0"
+      }
+    },
+    "loader-utils": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
+      "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
+      "dev": true,
+      "requires": {
+        "big.js": "^5.2.2",
+        "emojis-list": "^3.0.0",
+        "json5": "^1.0.1"
+      }
+    },
+    "lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+    },
+    "lodash.camelcase": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+      "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=",
+      "dev": true
+    },
+    "lru-cache": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+      "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+      "dev": true,
+      "requires": {
+        "yallist": "^3.0.2"
+      }
+    },
+    "magic-string": {
+      "version": "0.25.7",
+      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
+      "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
+      "dev": true,
+      "requires": {
+        "sourcemap-codec": "^1.4.4"
+      }
+    },
+    "merge-source-map": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz",
+      "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==",
+      "dev": true,
+      "requires": {
+        "source-map": "^0.6.1"
+      }
+    },
+    "minimist": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+      "dev": true
+    },
+    "mitt": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/mitt/-/mitt-2.1.0.tgz",
+      "integrity": "sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg=="
+    },
+    "nanoid": {
+      "version": "3.1.23",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
+      "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==",
+      "dev": true
+    },
+    "normalize-wheel": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz",
+      "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU="
+    },
+    "path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+      "dev": true
+    },
+    "postcss": {
+      "version": "8.3.5",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.5.tgz",
+      "integrity": "sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA==",
+      "dev": true,
+      "requires": {
+        "colorette": "^1.2.2",
+        "nanoid": "^3.1.23",
+        "source-map-js": "^0.6.2"
+      }
+    },
+    "postcss-modules": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.1.3.tgz",
+      "integrity": "sha512-dBT39hrXe4OAVYJe/2ZuIZ9BzYhOe7t+IhedYeQ2OxKwDpAGlkEN/fR0fGnrbx4BvgbMReRX4hCubYK9cE/pJQ==",
+      "dev": true,
+      "requires": {
+        "generic-names": "^2.0.1",
+        "icss-replace-symbols": "^1.1.0",
+        "lodash.camelcase": "^4.3.0",
+        "postcss-modules-extract-imports": "^3.0.0",
+        "postcss-modules-local-by-default": "^4.0.0",
+        "postcss-modules-scope": "^3.0.0",
+        "postcss-modules-values": "^4.0.0",
+        "string-hash": "^1.1.1"
+      }
+    },
+    "postcss-modules-extract-imports": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
+      "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
+      "dev": true
+    },
+    "postcss-modules-local-by-default": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz",
+      "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==",
+      "dev": true,
+      "requires": {
+        "icss-utils": "^5.0.0",
+        "postcss-selector-parser": "^6.0.2",
+        "postcss-value-parser": "^4.1.0"
+      }
+    },
+    "postcss-modules-scope": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz",
+      "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==",
+      "dev": true,
+      "requires": {
+        "postcss-selector-parser": "^6.0.4"
+      }
+    },
+    "postcss-modules-values": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz",
+      "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==",
+      "dev": true,
+      "requires": {
+        "icss-utils": "^5.0.0"
+      }
+    },
+    "postcss-selector-parser": {
+      "version": "6.0.6",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz",
+      "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==",
+      "dev": true,
+      "requires": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      }
+    },
+    "postcss-value-parser": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
+      "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
+      "dev": true
+    },
+    "regenerator-runtime": {
+      "version": "0.13.7",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
+      "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew=="
+    },
+    "resize-observer-polyfill": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
+      "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
+    },
+    "resolve": {
+      "version": "1.20.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
+      "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
+      "dev": true,
+      "requires": {
+        "is-core-module": "^2.2.0",
+        "path-parse": "^1.0.6"
+      }
+    },
+    "rollup": {
+      "version": "2.52.3",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.52.3.tgz",
+      "integrity": "sha512-QF3Sju8Kl2z0osI4unyOLyUudyhOMK6G0AeqJWgfiyigqLAlnNrfBcDWDx+f1cqn+JU2iIYVkDrgQ6/KtwEfrg==",
+      "dev": true,
+      "requires": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "schart.js": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/schart.js/-/schart.js-3.0.4.tgz",
+      "integrity": "sha512-uylb2u9rrHX1jyAuSAJUQON8XTfyDKI9kWj1J3fUlCQCkLVZ4HG4+IiV8qm//Z71dqvLI78QZ/fCBw0reB22Zw=="
+    },
+    "source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+    },
+    "source-map-js": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz",
+      "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==",
+      "dev": true
+    },
+    "sourcemap-codec": {
+      "version": "1.4.8",
+      "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
+      "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
+      "dev": true
+    },
+    "string-hash": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz",
+      "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=",
+      "dev": true
+    },
+    "to-fast-properties": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+      "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
+    },
+    "tslib": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
+      "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+      "dev": true
+    },
+    "vite": {
+      "version": "2.3.7",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-2.3.7.tgz",
+      "integrity": "sha512-Y0xRz11MPYu/EAvzN94+FsOZHbSvO6FUvHv127CyG7mV6oDoay2bw+g5y9wW3Blf8OY3chaz3nc/DcRe1IQ3Nw==",
+      "dev": true,
+      "requires": {
+        "esbuild": "^0.12.5",
+        "fsevents": "~2.3.1",
+        "postcss": "^8.3.0",
+        "resolve": "^1.19.0",
+        "rollup": "^2.38.5"
+      }
+    },
+    "vue": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/vue/-/vue-3.1.2.tgz",
+      "integrity": "sha512-q/rbKpb7aofax4ugqu2k/uj7BYuNPcd6Z5/qJtfkJQsE0NkwVoCyeSh7IZGH61hChwYn3CEkh4bHolvUPxlQ+w==",
+      "requires": {
+        "@vue/compiler-dom": "3.1.2",
+        "@vue/runtime-dom": "3.1.2",
+        "@vue/shared": "3.1.2"
+      }
+    },
+    "vue-cropperjs": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/vue-cropperjs/-/vue-cropperjs-5.0.0.tgz",
+      "integrity": "sha512-RhnC8O33uRZNkn74aiHZwNHnBJOXWlS4P6gsRI0lw4cZlWjKSCywZI9oSI9POlIPI6OYv30jvnHMXGch85tw7w==",
+      "requires": {
+        "cropperjs": "^1.5.6"
+      }
+    },
+    "vue-i18n": {
+      "version": "9.1.6",
+      "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.1.6.tgz",
+      "integrity": "sha512-FEC4HZkTH6QRIu/A0wlo0VS/GH3w/fuCC6xfvoC8IyhhtbG9A+go9NfW+HZ1ZXdAcO4EWcVQi04M+iSwuxgixw==",
+      "requires": {
+        "@intlify/core-base": "9.1.6",
+        "@intlify/shared": "9.1.6",
+        "@intlify/vue-devtools": "9.1.6",
+        "@vue/devtools-api": "^6.0.0-beta.7"
+      }
+    },
+    "vue-router": {
+      "version": "4.0.10",
+      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.10.tgz",
+      "integrity": "sha512-YbPf6QnZpyyWfnk7CUt2Bme+vo7TLfg1nGZNkvYqKYh4vLaFw6Gn8bPGdmt5m4qrGnKoXLqc4htAsd3dIukICA==",
+      "requires": {
+        "@vue/devtools-api": "^6.0.0-beta.14"
+      }
+    },
+    "vue-schart": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/vue-schart/-/vue-schart-2.0.0.tgz",
+      "integrity": "sha512-qAu3e5wfMcq26wK1xeHExEWfGpnjfoN1R/9QXblNi+AsU/p52X7tTwhi+Fw7H/otfEufhEY2X7z7emaoF4QO+g==",
+      "requires": {
+        "schart.js": "^3.0.0"
+      }
+    },
+    "vuex": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz",
+      "integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==",
+      "requires": {
+        "@vue/devtools-api": "^6.0.0-beta.11"
+      }
+    },
+    "wangeditor": {
+      "version": "4.7.4",
+      "resolved": "https://registry.npmjs.org/wangeditor/-/wangeditor-4.7.4.tgz",
+      "integrity": "sha512-MVWJyFZm3SOhIGFsxDwD6Q0ahIWQTYU0/otHxq85EnfdxtJBJ8c55iKDp3zIvBZaiBawBiYCpRmbn8HOedNj5w==",
+      "requires": {
+        "@babel/runtime": "^7.11.2",
+        "@babel/runtime-corejs3": "^7.11.2",
+        "tslib": "^2.1.0"
+      }
+    },
+    "yallist": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+      "dev": true
+    }
+  }
+}

+ 31 - 0
package.json

@@ -0,0 +1,31 @@
+{
+  "name": "vue-manage-system",
+  "version": "5.1.0",
+  "private": true,
+  "scripts": {
+    "dev": "vite",
+    "build": "vite build",
+    "serve": "vite preview"
+  },
+  "dependencies": {
+    "axios": "^0.21.1",
+    "element-plus": "1.0.2-beta.52",
+    "vue": "^3.1.2",
+    "vue-cropperjs": "^5.0.0",
+    "vue-i18n": "^9.0.0",
+    "vue-router": "^4.0.10",
+    "vue-schart": "^2.0.0",
+    "vuex": "^4.0.2",
+    "wangeditor": "^4.7.4"
+  },
+  "devDependencies": {
+    "vite": "2.3.7",
+    "@vitejs/plugin-vue": "^1.2.3",
+    "@vue/compiler-sfc": "^3.1.2"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not dead"
+  ]
+}

+ 12 - 0
public/detailConfig.json

@@ -0,0 +1,12 @@
+{
+    "list":[
+        {
+         "configId":1,
+         "modelTypeId":1,
+         "modelTypeName":2,
+         "modelDes":"experiment" ,  
+         "modelDetileDes": "",
+         "featureList":""
+     }],
+    "pageTotal":5
+ }

+ 16 - 0
public/simpleConfig.json

@@ -0,0 +1,16 @@
+{
+    "list":[
+        {
+         "fileId":0,
+         "fileName":1,
+         "configId":2,
+         "confName":"experiment"    
+     },
+     {
+         "fileId":111,
+         "fileName":222,
+         "configId":1111,
+         "confName":"experiment2"   
+    }],
+    "pageTotal":5
+ }

+ 41 - 0
public/table.json

@@ -0,0 +1,41 @@
+{
+    "list": [{
+            "id": 1,
+            "name": "张三",
+            "money": 123,
+            "address": "广东省东莞市长安镇",
+            "state": "成功",
+            "date": "2019-11-1",
+            "thumb": "https://lin-xin.gitee.io/images/post/wms.png"
+        },
+        {
+            "id": 2,
+            "name": "李四",
+            "money": 456,
+            "address": "广东省广州市白云区",
+            "state": "成功",
+            "date": "2019-10-11",
+            "thumb": "https://lin-xin.gitee.io/images/post/node3.png"
+        },
+        {
+            "id": 3,
+            "name": "王五",
+            "money": 789,
+            "address": "湖南省长沙市",
+            "state": "失败",
+            "date": "2019-11-11",
+            "thumb": "https://lin-xin.gitee.io/images/post/parcel.png"
+        },
+        {
+            "id": 4,
+            "name": "赵六",
+            "money": 1011,
+            "address": "福建省厦门市鼓浪屿",
+            "state": "成功",
+            "date": "2019-10-20",
+            "thumb": "https://lin-xin.gitee.io/images/post/notice.png"
+        }
+    ],
+    "pageTotal": 4
+    
+}

二进制
screenshots/wms1.png


二进制
screenshots/wms3.png


+ 12 - 0
src/App.vue

@@ -0,0 +1,12 @@
+<template>
+    <router-view />
+</template>
+
+<script>
+export default {};
+</script>
+
+<style>
+@import "./assets/css/main.css";
+@import "./assets/css/color-dark.css";
+</style>

+ 2 - 0
src/api/_prefix.js

@@ -0,0 +1,2 @@
+export const API_MODULE = '/api'
+export const MODEL_MODULE=`${API_MODULE}/model`

+ 18 - 0
src/api/index.js

@@ -0,0 +1,18 @@
+import request from '../utils/request';
+import axios from 'axios';
+// BaseCharts页面用于根据userId获取模型简要信息
+export const fetchData = query => {
+    return request({
+        url: './simpleConfig.json',
+        method: 'get',
+        params: query
+    });
+};
+
+// BaseCharts页面用于根据configId获取模型详细信息
+export const  fetchModuleDetail=(configId)=>{
+    return axios.get('./detailConfig.json',{
+        params:configId
+    })
+    
+}

+ 114 - 0
src/api/model.js

@@ -0,0 +1,114 @@
+import axios from "axios"
+import {MODEL_MODULE} from "./_prefix";
+
+/**
+ * 新建模型 POST /model/add
+ * @param {*} payload
+ * @returns
+ */
+export const addModel = async payload => {
+    const {fileInfoId, configId, modelName, modelTypeId, argument} = payload;
+    const res = await axios.post(`${MODEL_MODULE}/add`, {
+        fileInfoId,
+        configId,
+        modelName,
+        modelTypeId,
+        arguments:argument
+    })
+    return res//response
+}
+/**
+ * 新建DL模型 POST /model/add/dl
+ * @param {*} payload
+ * @returns
+ */
+export const addDLModel = async payload => {
+    const {fileInfoId, configId, modelName, modelTypeId, argument} = payload;
+    const res = await axios.post(`${MODEL_MODULE}/add/dl`, {
+        fileInfoId,
+        configId,
+        modelName,
+        modelTypeId,
+        arguments: argument
+    })
+    return res//response
+}
+/**
+ * 删除模型 GET /model/delete
+ * @param modelId
+ * @returns
+ */
+export const deleteModel=async modelId=>{
+    const res=await axios.get(`${MODEL_MODULE}/delete`,{params:{modelId:modelId}})
+    return res;
+}
+    /**
+     * 获取全部模型 GET /model/get/all
+     * @param userId
+     * @returns
+     */
+    export const getAllModel = async userId => {
+        const res = await axios.get(`${MODEL_MODULE}/get/all`, {params: {userId: userId}})
+        return res//response
+    }
+    /**
+     * 获取深度学习模型 GET /model/get/all/dl
+     * @param userId
+     * @returns
+     */
+    export const getAllDLModel = async userId => {
+        const res = await axios.get(`${MODEL_MODULE}/get/all/dl`, {params: {userId: userId}})
+        return res//response
+    }
+    /**
+     * 获取dl模型详情 GET /model/get/detail/dl
+     * @param modelId
+     * @returns
+     */
+    export const getDLDetail = async modelId => {
+        const res = await axios.get(`${MODEL_MODULE}/get/all/dl`, {params: {modelId: modelId}})
+        return res//response
+    }
+    /**
+     * change GET /model/change
+     * @param modelId
+     * @param modelName
+     * @param modelTypeId
+     * @returns
+     */
+    export const change=async data =>{
+        const res=await axios.get(`${MODEL_MODULE}/change`,{params:data})
+        return res;
+    }
+    /**
+     * 获取某一类模型 GET /model/get/models
+     * @param modelTypeId
+     * @returns
+     */
+    export const getModels=async modelTypeId=>{
+        const res=await axios.get(`${MODEL_MODULE}/get/models`,{params:{modelTypeId:modelTypeId}});
+        return res;
+    }
+    /**
+     * 训练 GET /model/train
+     * @param modelId
+     * @returns
+     */
+    export const train = async modelId=>{
+        const res=await axios.get(`${MODEL_MODULE}/train`,{params:{modelId:modelId}});
+        return res;
+    }
+    /**
+     * 使用模型预测 GET /model/use
+     * @param modelId
+     * @param fileId
+     * @returns
+     */
+    export const use = async data=>{
+        const res=await axios.get(`${MODEL_MODULE}/use`,{params:data});
+        return res;
+    }
+
+
+
+

+ 28 - 0
src/assets/css/color-dark.css

@@ -0,0 +1,28 @@
+.header{
+    background-color: #242f42;
+}
+.login-wrap{
+    background: #324157;
+}
+.plugins-tips{
+    background: #eef1f6;
+}
+.plugins-tips a{
+    color: #20a0ff;
+}
+.el-upload--text em {
+    color: #20a0ff;
+}
+.pure-button{
+    background: #20a0ff;
+}
+.tags-li.active {
+    border: 1px solid #409EFF;
+    background-color: #409EFF;
+}
+.message-title{
+    color: #20a0ff;
+}
+.collapse-btn:hover{
+    background: rgb(40,52,70);
+}

+ 4 - 0
src/assets/css/icon.css

@@ -0,0 +1,4 @@
+[class*=" el-icon-lx"],
+[class^=el-icon-lx] {
+    font-family: lx-iconfont !important;
+}

+ 177 - 0
src/assets/css/main.css

@@ -0,0 +1,177 @@
+* {
+    margin: 0;
+    padding: 0;
+}
+
+html,
+body,
+#app,
+.wrapper {
+    width: 100%;
+    height: 100%;
+    overflow: hidden;
+}
+
+body {
+    font-family: 'PingFang SC', "Helvetica Neue", Helvetica, "microsoft yahei", arial, STHeiTi, sans-serif;
+}
+
+a {
+    text-decoration: none
+}
+
+
+.content-box {
+    position: absolute;
+    left: 250px;
+    right: 0;
+    top: 70px;
+    bottom: 0;
+    padding-bottom: 30px;
+    -webkit-transition: left .3s ease-in-out;
+    transition: left .3s ease-in-out;
+    background: #f0f0f0;
+}
+
+.content {
+    width: auto;
+    height: 100%;
+    padding: 10px;
+    overflow-y: scroll;
+    box-sizing: border-box;
+}
+
+.content-collapse {
+    left: 65px;
+}
+
+.container {
+    padding: 30px;
+    background: #fff;
+    border: 1px solid #ddd;
+    border-radius: 5px;
+}
+
+.crumbs {
+    margin: 10px 0;
+}
+
+.el-table th {
+    background-color: #f5f7fa !important;
+}
+
+.pagination {
+    margin: 20px 0;
+    text-align: right;
+}
+
+.plugins-tips {
+    padding: 20px 10px;
+    margin-bottom: 20px;
+}
+
+.el-button+.el-tooltip {
+    margin-left: 10px;
+}
+
+.el-table tr:hover {
+    background: #f6faff;
+}
+
+.mgb20 {
+    margin-bottom: 20px;
+}
+
+.move-enter-active,
+.move-leave-active {
+    transition: opacity .1s ease;
+}
+
+.move-enter-from,
+.move-leave-to {
+    opacity: 0;
+}
+
+/*BaseForm*/
+
+.form-box {
+    width: 600px;
+}
+
+.form-box .line {
+    text-align: center;
+}
+
+.el-time-panel__content::after,
+.el-time-panel__content::before {
+    margin-top: -7px;
+}
+
+.el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default) {
+    padding-bottom: 0;
+}
+
+/*Upload*/
+
+.pure-button {
+    width: 150px;
+    height: 40px;
+    line-height: 40px;
+    text-align: center;
+    color: #fff;
+    border-radius: 3px;
+}
+
+.g-core-image-corp-container .info-aside {
+    height: 45px;
+}
+
+.el-upload--text {
+    background-color: #fff;
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    box-sizing: border-box;
+    width: 360px;
+    height: 180px;
+    text-align: center;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+}
+
+.el-upload--text .el-icon-upload {
+    font-size: 67px;
+    color: #97a8be;
+    margin: 40px 0 16px;
+    line-height: 50px;
+}
+
+.el-upload--text {
+    color: #97a8be;
+    font-size: 14px;
+    text-align: center;
+}
+
+.el-upload--text em {
+    font-style: normal;
+}
+
+/*VueEditor*/
+
+.ql-container {
+    min-height: 400px;
+}
+
+.ql-snow .ql-tooltip {
+    transform: translateX(117.5px) translateY(10px) !important;
+}
+
+.editor-btn {
+    margin-top: 20px;
+}
+
+/*markdown*/
+
+.v-note-wrapper .v-note-panel {
+    min-height: 500px;
+}

二进制
src/assets/img/img.jpg


二进制
src/assets/img/login-bg.jpg


+ 162 - 0
src/components/Header.vue

@@ -0,0 +1,162 @@
+<template>
+    <div class="header">
+        <!-- 折叠按钮 -->
+        <div class="collapse-btn" @click="collapseChage">
+            <i v-if="!collapse" class="el-icon-s-fold"></i>
+            <i v-else class="el-icon-s-unfold"></i>
+        </div>
+        <div class="logo">后台管理系统</div>
+        <div class="header-right">
+            <div class="header-user-con">
+                <!-- 消息中心 -->
+                <div class="btn-bell">
+                    <el-tooltip effect="dark" :content="message?`有${message}条未读消息`:`消息中心`" placement="bottom">
+                        <router-link to="/tabs">
+                            <i class="el-icon-bell"></i>
+                        </router-link>
+                    </el-tooltip>
+                    <span class="btn-bell-badge" v-if="message"></span>
+                </div>
+                <!-- 用户头像 -->
+                <div class="user-avator">
+                    <img src="../assets/img/img.jpg" />
+                </div>
+                <!-- 用户名下拉菜单 -->
+                <el-dropdown class="user-name" trigger="click" @command="handleCommand">
+                    <span class="el-dropdown-link">
+                        {{username}}
+                        <i class="el-icon-caret-bottom"></i>
+                    </span>
+                    <template #dropdown>
+                        <el-dropdown-menu>
+                            <a href="https://github.com/lin-xin/vue-manage-system" target="_blank">
+                                <el-dropdown-item>项目仓库</el-dropdown-item>
+                            </a>
+                            <el-dropdown-item command="user">个人中心</el-dropdown-item>
+                            <el-dropdown-item divided command="loginout">退出登录</el-dropdown-item>
+                        </el-dropdown-menu>
+                    </template>
+                </el-dropdown>
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+import { computed, onMounted } from "vue";
+import { useStore } from "vuex";
+import { useRouter } from "vue-router";
+export default {
+    setup() {
+        const username = localStorage.getItem("ms_username");
+        const message = 2;
+
+        const store = useStore();
+        const collapse = computed(() => store.state.collapse);
+        // 侧边栏折叠
+        const collapseChage = () => {
+            store.commit("handleCollapse", !collapse.value);
+        };
+
+        onMounted(() => {
+            if (document.body.clientWidth < 1500) {
+                collapseChage();
+            }
+        });
+
+        // 用户名下拉菜单选择事件
+        const router = useRouter();
+        const handleCommand = (command) => {
+            if (command == "loginout") {
+                localStorage.removeItem("ms_username");
+                router.push("/login");
+            } else if (command == "user") {
+                router.push("/user");
+            }
+        };
+
+        return {
+            username,
+            message,
+            collapse,
+            collapseChage,
+            handleCommand,
+        };
+    },
+};
+</script>
+<style scoped>
+.header {
+    position: relative;
+    box-sizing: border-box;
+    width: 100%;
+    height: 70px;
+    font-size: 22px;
+    color: #fff;
+}
+.collapse-btn {
+    float: left;
+    padding: 0 21px;
+    cursor: pointer;
+    line-height: 70px;
+}
+.header .logo {
+    float: left;
+    width: 250px;
+    line-height: 70px;
+}
+.header-right {
+    float: right;
+    padding-right: 50px;
+}
+.header-user-con {
+    display: flex;
+    height: 70px;
+    align-items: center;
+}
+.btn-fullscreen {
+    transform: rotate(45deg);
+    margin-right: 5px;
+    font-size: 24px;
+}
+.btn-bell,
+.btn-fullscreen {
+    position: relative;
+    width: 30px;
+    height: 30px;
+    text-align: center;
+    border-radius: 15px;
+    cursor: pointer;
+}
+.btn-bell-badge {
+    position: absolute;
+    right: 0;
+    top: -2px;
+    width: 8px;
+    height: 8px;
+    border-radius: 4px;
+    background: #f56c6c;
+    color: #fff;
+}
+.btn-bell .el-icon-bell {
+    color: #fff;
+}
+.user-name {
+    margin-left: 10px;
+}
+.user-avator {
+    margin-left: 20px;
+}
+.user-avator img {
+    display: block;
+    width: 40px;
+    height: 40px;
+    border-radius: 50%;
+}
+.el-dropdown-link {
+    color: #fff;
+    cursor: pointer;
+}
+.el-dropdown-menu__item {
+    text-align: center;
+}
+</style>

+ 159 - 0
src/components/Sidebar.vue

@@ -0,0 +1,159 @@
+<template>
+    <div class="sidebar">
+        <el-menu class="sidebar-el-menu" :default-active="onRoutes" :collapse="collapse" background-color="#324157"
+            text-color="#bfcbd9" active-text-color="#20a0ff" unique-opened router>
+            <template v-for="item in items">
+                <template v-if="item.subs">
+                    <el-submenu :index="item.index" :key="item.index">
+                        <template #title>
+                            <i :class="item.icon"></i>
+                            <span>{{ item.title }}</span>
+                        </template>
+                        <template v-for="subItem in item.subs">
+                            <el-submenu v-if="subItem.subs" :index="subItem.index" :key="subItem.index">
+                                <template #title>{{ subItem.title }}</template>
+                                <el-menu-item v-for="(threeItem, i) in subItem.subs" :key="i" :index="threeItem.index">
+                                    {{ threeItem.title }}</el-menu-item>
+                            </el-submenu>
+                            <el-menu-item v-else :index="subItem.index" :key="subItem.index">{{ subItem.title }}
+                            </el-menu-item>
+                        </template>
+                    </el-submenu>
+                </template>
+                <template v-else>
+                    <el-menu-item :index="item.index" :key="item.index">
+                        <i :class="item.icon"></i>
+                        <template #title>{{ item.title }}</template>
+                    </el-menu-item>
+                </template>
+            </template>
+        </el-menu>
+    </div>
+</template>
+
+<script>
+import { computed, watch } from "vue";
+import { useStore } from "vuex";
+import { useRoute } from "vue-router";
+export default {
+    setup() {
+        const items = [
+            {
+                icon: "el-icon-lx-home",
+                index: "/dashboard",
+                title: "首页",
+            },
+            {
+                icon: "el-icon-lx-cascades",
+                index: "/config",
+                title: "模型配置",
+            },
+            {
+              icon: "el-icon-lx-redpacket_fill",
+              index: "/Dllearning",
+              title:"深度学习",
+            },
+            {
+                icon: "el-icon-lx-copy",
+                index: "/tabs",
+                title: "我的消息",
+            },
+            {
+                icon: "el-icon-lx-calendar",
+                index: "3",
+                title: "表单相关",
+                subs: [
+                    {
+                        index: "/form",
+                        title: "基本表单",
+                    },
+                    {
+                        index: "/upload",
+                        title: "文件上传",
+                    },
+                    {
+                        index: "4",
+                        title: "三级菜单",
+                        subs: [
+                            {
+                                index: "/editor",
+                                title: "富文本编辑器",
+                            },
+                        ],
+                    },
+                ],
+            },
+            {
+                icon: "el-icon-lx-emoji",
+                index: "/icon",
+                title: "自定义图标",
+            },
+            {
+                icon: "el-icon-pie-chart",
+                index: "/charts",
+                title: "训练结果",
+            },
+            {
+                icon: "el-icon-lx-global",
+                index: "/i18n",
+                title: "国际化功能",
+            },
+            {
+                icon: "el-icon-lx-warn",
+                index: "7",
+                title: "错误处理",
+                subs: [
+                    {
+                        index: "/permission",
+                        title: "权限测试",
+                    },
+                    {
+                        index: "/404",
+                        title: "404页面",
+                    },
+                ],
+            },
+            {
+                icon: "el-icon-lx-redpacket_fill",
+                index: "/donate",
+                title: "支持作者",
+            }
+        ];
+
+        const route = useRoute();
+
+        const onRoutes = computed(() => {
+            return route.path;
+        });
+
+        const store = useStore();
+        const collapse = computed(() => store.state.collapse);
+
+        return {
+            items,
+            onRoutes,
+            collapse,
+        };
+    },
+};
+</script>
+
+<style scoped>
+.sidebar {
+    display: block;
+    position: absolute;
+    left: 0;
+    top: 70px;
+    bottom: 0;
+    overflow-y: scroll;
+}
+.sidebar::-webkit-scrollbar {
+    width: 0;
+}
+.sidebar-el-menu:not(.el-menu--collapse) {
+    width: 250px;
+}
+.sidebar > ul {
+    height: 100%;
+}
+</style>

+ 183 - 0
src/components/Tags.vue

@@ -0,0 +1,183 @@
+<template>
+    <div class="tags" v-if="showTags">
+        <ul>
+            <li class="tags-li" v-for="(item,index) in tagsList" :class="{'active': isActive(item.path)}" :key="index">
+                <router-link :to="item.path" class="tags-li-title">{{item.title}}</router-link>
+                <span class="tags-li-icon" @click="closeTags(index)">
+                    <i class="el-icon-close"></i>
+                </span>
+            </li>
+        </ul>
+        <div class="tags-close-box">
+            <el-dropdown @command="handleTags">
+                <el-button size="mini" type="primary">
+                    标签选项
+                    <i class="el-icon-arrow-down el-icon--right"></i>
+                </el-button>
+                <template #dropdown>
+                    <el-dropdown-menu size="small">
+                        <el-dropdown-item command="other">关闭其他</el-dropdown-item>
+                        <el-dropdown-item command="all">关闭所有</el-dropdown-item>
+                    </el-dropdown-menu>
+                </template>
+            </el-dropdown>
+        </div>
+    </div>
+</template>
+
+<script>
+import { computed } from "vue";
+import { useStore } from "vuex";
+import { onBeforeRouteUpdate, useRoute, useRouter } from "vue-router";
+export default {
+    setup() {
+        const route = useRoute();
+        const router = useRouter();
+        const isActive = (path) => {
+            return path === route.fullPath;
+        };
+
+        const store = useStore();
+        const tagsList = computed(() => store.state.tagsList);
+        const showTags = computed(() => tagsList.value.length > 0);
+
+        // 关闭单个标签
+        const closeTags = (index) => {
+            const delItem = tagsList.value[index];
+            store.commit("delTagsItem", { index });
+            const item = tagsList.value[index]
+                ? tagsList.value[index]
+                : tagsList.value[index - 1];
+            if (item) {
+                delItem.path === route.fullPath && router.push(item.path);
+            } else {
+                router.push("/");
+            }
+        };
+
+        // 设置标签
+        const setTags = (route) => {
+            const isExist = tagsList.value.some((item) => {
+                return item.path === route.fullPath;
+            });
+            if (!isExist) {
+                if (tagsList.value.length >= 8) {
+                    store.commit("delTagsItem", { index: 0 });
+                }
+                store.commit("setTagsItem", {
+                    name: route.name,
+                    title: route.meta.title,
+                    path: route.fullPath,
+                });
+            }
+        };
+        setTags(route);
+        onBeforeRouteUpdate((to) => {
+            setTags(to);
+        });
+
+        // 关闭全部标签
+        const closeAll = () => {
+            store.commit("clearTags");
+            router.push("/");
+        };
+        // 关闭其他标签
+        const closeOther = () => {
+            const curItem = tagsList.value.filter((item) => {
+                return item.path === route.fullPath;
+            });
+            store.commit("closeTagsOther", curItem);
+        };
+        const handleTags = (command) => {
+            command === "other" ? closeOther() : closeAll();
+        };
+
+        // 关闭当前页面的标签页
+        // store.commit("closeCurrentTag", {
+        //     $router: router,
+        //     $route: route
+        // });
+
+        return {
+            isActive,
+            tagsList,
+            showTags,
+            closeTags,
+            handleTags,
+        };
+    },
+};
+</script>
+
+
+<style>
+.tags {
+    position: relative;
+    height: 30px;
+    overflow: hidden;
+    background: #fff;
+    padding-right: 120px;
+    box-shadow: 0 5px 10px #ddd;
+}
+
+.tags ul {
+    box-sizing: border-box;
+    width: 100%;
+    height: 100%;
+}
+
+.tags-li {
+    float: left;
+    margin: 3px 5px 2px 3px;
+    border-radius: 3px;
+    font-size: 12px;
+    overflow: hidden;
+    cursor: pointer;
+    height: 23px;
+    line-height: 23px;
+    border: 1px solid #e9eaec;
+    background: #fff;
+    padding: 0 5px 0 12px;
+    vertical-align: middle;
+    color: #666;
+    -webkit-transition: all 0.3s ease-in;
+    -moz-transition: all 0.3s ease-in;
+    transition: all 0.3s ease-in;
+}
+
+.tags-li:not(.active):hover {
+    background: #f8f8f8;
+}
+
+.tags-li.active {
+    color: #fff;
+}
+
+.tags-li-title {
+    float: left;
+    max-width: 80px;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    margin-right: 5px;
+    color: #666;
+}
+
+.tags-li.active .tags-li-title {
+    color: #fff;
+}
+
+.tags-close-box {
+    position: absolute;
+    right: 0;
+    top: 0;
+    box-sizing: border-box;
+    padding-top: 1px;
+    text-align: center;
+    width: 110px;
+    height: 30px;
+    background: #fff;
+    box-shadow: -3px 0 15px 3px rgba(0, 0, 0, 0.1);
+    z-index: 10;
+}
+</style>

+ 12 - 0
src/main.js

@@ -0,0 +1,12 @@
+import {createApp} from 'vue'
+import App from './App.vue'
+import router from './router'
+import store from './store'
+import installElementPlus from './plugins/element'
+import './assets/css/icon.css'
+const app = createApp(App)
+installElementPlus(app)
+app
+    .use(store)
+    .use(router)
+    .mount('#app')

+ 17 - 0
src/plugins/element.js

@@ -0,0 +1,17 @@
+import ElementPlus from 'element-plus'
+import { createI18n } from 'vue-i18n'
+import 'element-plus/lib/theme-chalk/index.css'
+import localeZH from 'element-plus/lib/locale/lang/zh-cn'
+import localeEN from 'element-plus/lib/locale/lang/en'
+import messages from '../utils/i18n'
+
+const i18n = createI18n({
+  locale: localeZH.name,
+  fallbackLocale: localeEN.name,
+  messages,
+})
+
+export default (app) => {
+  app.use(ElementPlus, { locale:localeZH })
+  app.use(i18n)
+}

+ 167 - 0
src/router/index.js

@@ -0,0 +1,167 @@
+import {createRouter, createWebHashHistory} from "vue-router";
+import Home from "../views/Home.vue";
+
+const routes = [
+    {
+        path: '/',
+        redirect: '/dashboard'
+    }, {
+        path: "/",
+        name: "Home",
+        component: Home,
+        children: [
+            {
+                path: "/dashboard",
+                name: "dashboard",
+                meta: {
+                    title: '首页'
+                },
+                component: () => import ( /* webpackChunkName: "dashboard" */ "../views/Dashboard.vue")
+            }, {
+                path: "/config",
+                name: "config",
+                meta: {
+                    title: '模型配置'
+                },
+                component: () => import ( /* webpackChunkName: "table" */ "../views/Config.vue")
+            }, {
+                path: "/charts",
+                name: "basecharts",
+                meta: {
+                    title: '训练结果'
+                },
+                component: () => import ( /* webpackChunkName: "charts" */ "../views/BaseCharts.vue")
+            }, {
+                path: "/form",
+                name: "baseform",
+                meta: {
+                    title: '表单'
+                },
+                component: () => import ( /* webpackChunkName: "form" */ "../views/BaseForm.vue")
+            }, {
+                path: "/tabs",
+                name: "tabs",
+                meta: {
+                    title: 'tab标签'
+                },
+                component: () => import ( /* webpackChunkName: "tabs" */ "../views/Tabs.vue")
+            }, {
+                path: "/donate",
+                name: "donate",
+                meta: {
+                    title: '鼓励作者'
+                },
+                component: () => import ( /* webpackChunkName: "donate" */ "../views/Donate.vue")
+            }, {
+                path: "/permission",
+                name: "permission",
+                meta: {
+                    title: '权限管理',
+                    permission: true
+                },
+                component: () => import ( /* webpackChunkName: "permission" */ "../views/Permission.vue")
+            }, {
+                path: "/i18n",
+                name: "i18n",
+                meta: {
+                    title: '国际化语言'
+                },
+                component: () => import ( /* webpackChunkName: "i18n" */ "../views/I18n.vue")
+            }, {
+                path: "/upload",
+                name: "upload",
+                meta: {
+                    title: '上传插件'
+                },
+                component: () => import ( /* webpackChunkName: "upload" */ "../views/Upload.vue")
+            }, {
+                path: "/icon",
+                name: "icon",
+                meta: {
+                    title: '自定义图标'
+                },
+                component: () => import ( /* webpackChunkName: "icon" */ "../views/Icon.vue")
+            }, {
+                path: '/404',
+                name: '404',
+                meta: {
+                    title: '找不到页面'
+                },
+                component: () => import (/* webpackChunkName: "404" */ '../views/404.vue')
+            }, {
+                path: '/403',
+                name: '403',
+                meta: {
+                    title: '没有权限'
+                },
+                component: () => import (/* webpackChunkName: "403" */ '../views/403.vue')
+            }, {
+                path: '/user',
+                name: 'user',
+                meta: {
+                    title: '个人中心'
+                },
+                component: () => import (/* webpackChunkName: "user" */ '../views/User.vue')
+            }, {
+                path: '/editor',
+                name: 'editor',
+                meta: {
+                    title: '富文本编辑器'
+                },
+                component: () => import (/* webpackChunkName: "editor" */ '../views/Editor.vue')
+            },{
+                path:'/dllearning',
+                name:'dllearning',
+                meta:{
+                    title:'深度学习页面'
+                },
+                component:()=>import(/*webpackChunkName:"dllearning" */ '../views/Dllearning.vue')
+            },{
+                path:'/dlform',
+                name:'dlform',
+                meta:{
+                    title:'配置模型'
+                },
+                component:()=>import(/*webpackChunkName:"dllearning" */ '../views/dlform.vue')
+            },
+            {
+                path:'/configform',
+                name:'configform',
+                meta:{
+                    title:'编辑配置'
+                },
+                component:()=>import(/*webpackChunkName:"configform" */ '../views/ConfigForm.vue')
+            }
+
+        ]
+    }, {
+        path: "/login",
+        name: "Login",
+        meta: {
+            title: '登录'
+        },
+        component: () => import ( /* webpackChunkName: "login" */ "../views/Login.vue")
+    }
+];
+
+const router = createRouter({
+    history: createWebHashHistory(),
+    routes
+});
+
+router.beforeEach((to, from, next) => {
+    document.title = `${to.meta.title} | vue-manage-system`;
+    const role = localStorage.getItem('ms_username');
+    if (!role && to.path !== '/login') {
+        next('/login');
+    } else if (to.meta.permission) {
+        // 如果是管理员权限则可进入,这里只是简单的模拟管理员权限而已
+        role === 'admin'
+            ? next()
+            : next('/403');
+    } else {
+        next();
+    }
+});
+
+export default router;

+ 56 - 0
src/store/index.js

@@ -0,0 +1,56 @@
+import {createStore} from 'vuex'
+
+export default createStore({
+    state: {
+        tagsList: [],
+        collapse: false
+    },
+    mutations: {
+        delTagsItem(state, data) {
+            state
+                .tagsList
+                .splice(data.index, 1);
+        },
+        setTagsItem(state, data) {
+            state
+                .tagsList
+                .push(data)
+        },
+        clearTags(state) {
+            state.tagsList = []
+        },
+        closeTagsOther(state, data) {
+            state.tagsList = data;
+        },
+        closeCurrentTag(state, data) {
+            for (let i = 0, len = state.tagsList.length; i < len; i++) {
+                const item = state.tagsList[i];
+                if (item.path === data.$route.fullPath) {
+                    if (i < len - 1) {
+                        data
+                            .$router
+                            .push(state.tagsList[i + 1].path);
+                    } else if (i > 0) {
+                        data
+                            .$router
+                            .push(state.tagsList[i - 1].path);
+                    } else {
+                        data
+                            .$router
+                            .push("/");
+                    }
+                    state
+                        .tagsList
+                        .splice(i, 1);
+                    break;
+                }
+            }
+        },
+        // 侧边栏折叠
+        handleCollapse(state, data) {
+            state.collapse = data;
+        }
+    },
+    actions: {},
+    modules: {}
+})

+ 24 - 0
src/utils/i18n.js

@@ -0,0 +1,24 @@
+export default {
+    'zh-cn': {
+        i18n: {
+            breadcrumb: '国际化产品',
+            tips: '通过切换语言按钮,来改变当前内容的语言。',
+            btn: '切换英文',
+            title1: '常用用法',
+            p1: '要是你把你的秘密告诉了风,那就别怪风把它带给树。',
+            p2: '没有什么比信念更能支撑我们度过艰难的时光了。',
+            p3: '只要能把自己的事做好,并让自己快乐,你就领先于大多数人了。'
+        }
+    },
+    'en': {
+        i18n: {
+            breadcrumb: 'International Products',
+            tips: 'Click on the button to change the current language. ',
+            btn: 'Switch Chinese',
+            title1: 'Common usage',
+            p1: "If you reveal your secrets to the wind you should not blame the wind for  revealing them to the trees.",
+            p2: "Nothing can help us endure dark times better than our faith. ",
+            p3: "If you can do what you do best and be happy, you're further along in life  than most people."
+        }
+    }
+}

+ 34 - 0
src/utils/request.js

@@ -0,0 +1,34 @@
+import axios from 'axios';
+
+const service = axios.create({
+    // process.env.NODE_ENV === 'development' 来判断是否开发环境
+    // easy-mock服务挂了,暂时不使用了
+    // baseURL: 'https://www.easy-mock.com/mock/592501a391470c0ac1fab128',
+    timeout: 5000
+});
+
+service.interceptors.request.use(
+    config => {
+        return config;
+    },
+    error => {
+        console.log(error);
+        return Promise.reject();
+    }
+);
+
+service.interceptors.response.use(
+    response => {
+        if (response.status === 200) {
+            return response.data;
+        } else {
+            Promise.reject();
+        }
+    },
+    error => {
+        console.log(error);
+        return Promise.reject();
+    }
+);
+
+export default service;

+ 62 - 0
src/views/403.vue

@@ -0,0 +1,62 @@
+<template>
+    <div class="error-page">
+        <div class="error-code">4<span>0</span>3</div>
+        <div class="error-desc">啊哦~ 你没有权限访问该页面哦</div>
+        <div class="error-handle">
+            <router-link to="/">
+                <el-button type="primary" size="large">返回首页</el-button>
+            </router-link>
+            <el-button class="error-btn" type="primary" size="large" @click="goBack">返回上一页</el-button>
+        </div>
+    </div>
+</template>
+
+<script>
+import { useRouter } from "vue-router";
+export default {
+    name: "403",
+    setup() {
+        const router = useRouter();
+        const goBack = () => {
+            router.go(-1);
+        };
+        return {
+            goBack,
+        };
+    },
+};
+</script>
+
+
+<style scoped>
+.error-page {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    flex-direction: column;
+    width: 100%;
+    height: 100%;
+    background: #f3f3f3;
+    box-sizing: border-box;
+}
+.error-code {
+    line-height: 1;
+    font-size: 250px;
+    font-weight: bolder;
+    color: #f02d2d;
+}
+.error-code span {
+    color: #00a854;
+}
+.error-desc {
+    font-size: 30px;
+    color: #777;
+}
+.error-handle {
+    margin-top: 30px;
+    padding-bottom: 200px;
+}
+.error-btn {
+    margin-left: 100px;
+}
+</style>

+ 62 - 0
src/views/404.vue

@@ -0,0 +1,62 @@
+<template>
+    <div class="error-page">
+        <div class="error-code">4<span>0</span>4</div>
+        <div class="error-desc">啊哦~ 你所访问的页面不存在</div>
+        <div class="error-handle">
+            <router-link to="/config">
+                <el-button type="primary" size="large">返回首页</el-button>
+            </router-link>
+            <el-button class="error-btn" type="primary" size="large" @click="goBack">返回上一页</el-button>
+        </div>
+    </div>
+</template>
+
+<script>
+import { useRouter } from "vue-router";
+export default {
+    name: "404",
+    setup() {
+        const router = useRouter();
+        const goBack = () => {
+            router.go(-1);
+        };
+        return {
+            goBack,
+        };
+    },
+};
+</script>
+
+
+<style scoped>
+.error-page {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    flex-direction: column;
+    width: 100%;
+    height: 100%;
+    background: #f3f3f3;
+    box-sizing: border-box;
+}
+.error-code {
+    line-height: 1;
+    font-size: 250px;
+    font-weight: bolder;
+    color: #2d8cf0;
+}
+.error-code span {
+    color: #00a854;
+}
+.error-desc {
+    font-size: 30px;
+    color: #777;
+}
+.error-handle {
+    margin-top: 30px;
+    padding-bottom: 200px;
+}
+.error-btn {
+    margin-left: 100px;
+}
+</style>

+ 174 - 0
src/views/BaseCharts.vue

@@ -0,0 +1,174 @@
+<template>
+    <div>
+        <!-- 历史记录,面包屑 -->
+        <div class="crumbs">
+            <el-breadcrumb separator="/">
+                <el-breadcrumb-item>
+                    <i class="el-icon-lx-cascades"></i> 基础表格
+                </el-breadcrumb-item>
+            </el-breadcrumb>
+        </div>
+
+    <div class="container">
+    
+    <!-- 详情页 -->
+    <div>
+    <el-dialog fullscreen=true v-model="dialogTableVisible" title="模型详情">
+    <el-table :data="moduleData">
+      <el-table-column
+        prop="configId"
+        label="配置id"
+        width="150"
+      ></el-table-column>
+      <el-table-column
+        prop="modelTypeId"
+        label="模型类型Id"
+        width="200"
+      ></el-table-column>
+      <el-table-column
+        label="模型名称"
+        prop="modelTypeName"
+        width="200"
+      ></el-table-column>
+      <el-table-column
+        prop="模型描述"
+        label="modelDes"
+        width="200"
+      ></el-table-column>
+       <el-table-column
+        prop="模型详情描述"
+        label="modelDetileDes"
+        width="200"
+      ></el-table-column>
+       <el-table-column
+        prop="模型特征信息"
+        label="featureList"
+        width="200"
+      ></el-table-column>
+      <el-table-column prop="modelInfos" label="modelInfos" width="200"></el-table-column>
+     </el-table>
+   </el-dialog>
+   </div>
+
+    <div class="mytTable">
+         <el-table :data="tableData" border style="width: 100%">
+         <el-table-column prop="fileId" label="文件ID" width="180" />
+         <el-table-column prop="fileName" label="文件名" width="180" />
+         <el-table-column prop="configId" label="配置ID" width="180" />
+         <el-table-column prop="confName" label="配置名" />
+         
+         <el-table-column  label="Operations">
+             <template #default="scope" >
+                 <el-button type="text" size="small" @click="handleDetail(scope.row)">详情</el-button>
+             </template>
+        </el-table-column>
+        
+        </el-table>
+    </div>
+            <div class="pagination">
+                <el-pagination background layout="total, prev, pager, next" :current-page="query.pageIndex"
+                    :page-size="query.pageSize" :total="pageTotal" @current-change="handlePageChange"></el-pagination>
+            </div>
+    </div>
+
+    </div>
+</template>
+
+<script>
+import { ref, reactive } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { fetchData,fetchModuleDetail } from "../api/index";
+
+export default {
+    
+    name:"basecharts",
+    setup() {
+        const query = reactive({
+            address: "",
+            name: "",
+            pageIndex: 1,
+            pageSize: 10,
+        });
+        const tableData = ref([]);
+        const moduleData = ref([]);
+        const pageTotal = ref(0);
+        let userId=ref(1);
+        const  dialogTableVisible = ref(false)
+        // 获取表格数据
+        //  插入获取数据的api,可以引入第三方文件
+        const getData = () => {
+            console.log("getData被调用了")
+            fetchData(userId)
+            .then((res) => {
+                tableData.value = res.list;
+                pageTotal.value = res.pageTotal || 50;
+            });
+        };
+
+        // 相当于beforeCreated生命周期中调用了getData()函数
+        getData();
+
+       
+        // 分页导航
+        const handlePageChange = (val) => {
+            query.pageIndex = val;
+            getData();
+        };
+
+        const  handleDetail=({configId})=>{
+            
+            fetchModuleDetail(configId).
+            then((res)=>{
+                moduleData.value=res.data.list
+                dialogTableVisible.value=true
+                
+            })
+            // console.log(configId)
+        }
+
+        
+
+        return {
+            query,
+            tableData,
+            pageTotal,
+            userId,
+            handlePageChange,
+            handleDetail,
+            dialogTableVisible,
+            moduleData,
+        };
+    },
+};
+</script>
+
+<style scoped>
+.handle-box {
+    margin-bottom: 20px;
+}
+
+.handle-select {
+    width: 120px;
+}
+
+.handle-input {
+    width: 300px;
+    display: inline-block;
+}
+.table {
+    width: 100%;
+    font-size: 14px;
+}
+.red {
+    color: #ff0000;
+}
+.mr10 {
+    margin-right: 10px;
+}
+.table-td-thumb {
+    display: block;
+    margin: auto;
+    width: 40px;
+    height: 40px;
+}
+</style>

+ 174 - 0
src/views/BaseForm.vue

@@ -0,0 +1,174 @@
+<template>
+    <div>
+        <div class="crumbs">
+            <el-breadcrumb separator="/">
+                <el-breadcrumb-item>
+                    <i class="el-icon-lx-calendar"></i> 表单
+                </el-breadcrumb-item>
+                <el-breadcrumb-item>基本表单</el-breadcrumb-item>
+            </el-breadcrumb>
+        </div>
+        <div class="container">
+            <div class="form-box">
+                <el-form ref="formRef" :rules="rules" :model="form" label-width="80px">
+                    <el-form-item label="表单名称" prop="name">
+                        <el-input v-model="form.name"></el-input>
+                    </el-form-item>
+                    <el-form-item label="选择器" prop="region">
+                        <el-select v-model="form.region" placeholder="请选择">
+                            <el-option key="bbk" label="步步高" value="bbk"></el-option>
+                            <el-option key="xtc" label="小天才" value="xtc"></el-option>
+                            <el-option key="imoo" label="imoo" value="imoo"></el-option>
+                        </el-select>
+                    </el-form-item>
+                    <el-form-item label="日期时间">
+                        <el-col :span="11">
+                            <el-form-item prop="date1">
+                                <el-date-picker type="date" placeholder="选择日期" v-model="form.date1"
+                                    style="width: 100%;"></el-date-picker>
+                            </el-form-item>
+                        </el-col>
+                        <el-col class="line" :span="2">-</el-col>
+                        <el-col :span="11">
+                            <el-form-item prop="date2">
+                                <el-time-picker placeholder="选择时间" v-model="form.date2" style="width: 100%;">
+                                </el-time-picker>
+                            </el-form-item>
+                        </el-col>
+                    </el-form-item>
+                    <el-form-item label="城市级联" prop="options">
+                        <el-cascader :options="options" v-model="form.options"></el-cascader>
+                    </el-form-item>
+                    <el-form-item label="选择开关" prop="delivery">
+                        <el-switch v-model="form.delivery"></el-switch>
+                    </el-form-item>
+                    <el-form-item label="多选框" prop="type">
+                        <el-checkbox-group v-model="form.type">
+                            <el-checkbox label="步步高" name="type"></el-checkbox>
+                            <el-checkbox label="小天才" name="type"></el-checkbox>
+                            <el-checkbox label="imoo" name="type"></el-checkbox>
+                        </el-checkbox-group>
+                    </el-form-item>
+                    <el-form-item label="单选框" prop="resource">
+                        <el-radio-group v-model="form.resource">
+                            <el-radio label="步步高"></el-radio>
+                            <el-radio label="小天才"></el-radio>
+                            <el-radio label="imoo"></el-radio>
+                        </el-radio-group>
+                    </el-form-item>
+                    <el-form-item label="文本框" prop="desc">
+                        <el-input type="textarea" rows="5" v-model="form.desc"></el-input>
+                    </el-form-item>
+                    <el-form-item>
+                        <el-button type="primary" @click="onSubmit">表单提交</el-button>
+                        <el-button @click="onReset">重置表单</el-button>
+                    </el-form-item>
+                </el-form>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import { reactive, ref } from "vue";
+import { ElMessage } from "element-plus";
+export default {
+    name: "baseform",
+    setup() {
+        const options = [
+            {
+                value: "guangdong",
+                label: "广东省",
+                children: [
+                    {
+                        value: "guangzhou",
+                        label: "广州市",
+                        children: [
+                            {
+                                value: "tianhe",
+                                label: "天河区",
+                            },
+                            {
+                                value: "haizhu",
+                                label: "海珠区",
+                            },
+                        ],
+                    },
+                    {
+                        value: "dongguan",
+                        label: "东莞市",
+                        children: [
+                            {
+                                value: "changan",
+                                label: "长安镇",
+                            },
+                            {
+                                value: "humen",
+                                label: "虎门镇",
+                            },
+                        ],
+                    },
+                ],
+            },
+            {
+                value: "hunan",
+                label: "湖南省",
+                children: [
+                    {
+                        value: "changsha",
+                        label: "长沙市",
+                        children: [
+                            {
+                                value: "yuelu",
+                                label: "岳麓区",
+                            },
+                        ],
+                    },
+                ],
+            },
+        ];
+        const rules = {
+            name: [
+                { required: true, message: "请输入表单名称", trigger: "blur" },
+            ],
+        };
+        const formRef = ref(null);
+        const form = reactive({
+            name: "",
+            region: "",
+            date1: "",
+            date2: "",
+            delivery: true,
+            type: ["步步高"],
+            resource: "小天才",
+            desc: "",
+            options: [],
+        });
+        // 提交
+        const onSubmit = () => {
+            // 表单校验
+            formRef.value.validate((valid) => {
+                if (valid) {
+                    console.log(form);
+                    ElMessage.success("提交成功!");
+                } else {
+                    return false;
+                }
+            });
+        };
+        // 重置
+        const onReset = () => {
+            formRef.value.resetFields();
+        };
+
+        return {
+            options,
+            rules,
+            formRef,
+            form,
+            onSubmit,
+            onReset,
+        };
+    },
+};
+</script>

+ 279 - 0
src/views/Config.vue

@@ -0,0 +1,279 @@
+<template>
+    <div>
+        <div class="crumbs">
+            <el-breadcrumb separator="/">
+                <el-breadcrumb-item>
+                    <i class="el-icon-lx-cascades"></i> 配置列表
+                </el-breadcrumb-item>
+            </el-breadcrumb>
+        </div>
+
+        <div class="container">
+            <div class="handle-box">
+                <el-select v-model="query.file" placeholder="模型类别" class="handle-select mr10">
+                    <el-option key="0" label="所有" value="0"></el-option>
+                    <el-option key="1" label="分类" value="1"></el-option>
+                    <el-option key="2" label="聚类" value="2"></el-option>
+                    <el-option key="3" label="回归" value="3"></el-option>
+                    <el-option key="4" label="自动化" value="4"></el-option>
+                </el-select>
+                <el-input v-model="query.name" placeholder="模型名" class="handle-input mr10"></el-input>
+                <el-button type="primary" icon="el-icon-search" @click="handleSearch">搜索</el-button>
+                <el-button type="success" icon="el-icon-plus" @click="handleEdit(tableData.length,0)" style="position: absolute;right: 15em">添加模型</el-button>
+                <el-button type="danger" icon="el-icon-minus" @click="handleBatchDelete" style="position: absolute;right: 5em">批量删除</el-button>
+            </div>
+
+            <el-table
+                :data="tableData" border class="table" ref="multipleTable"
+                header-cell-class-name="table-header"
+                @selection-change="handleSelectionChange"
+            >
+                <el-table-column width="50" type="selection"></el-table-column>
+                <el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>
+                <el-table-column prop="name" label="模型名"></el-table-column>
+                <el-table-column label="类别">
+                    <template #default="scope">{{ scope.row.type }}</template>
+                </el-table-column>
+                <el-table-column label="特征">
+                    <template #default="scope">{{ scope.row.feature }}</template>
+                </el-table-column>
+<!--                <el-table-column label="头像(查看大图)" align="center">-->
+<!--                    <template #default="scope">-->
+<!--                        <el-image class="table-td-thumb" :src="scope.row.thumb" :preview-src-list="[scope.row.thumb]">-->
+<!--                        </el-image>-->
+<!--                    </template>-->
+<!--                </el-table-column>-->
+<!--                <el-table-column prop="file" label="地址"></el-table-column>-->
+<!--                <el-table-column label="状态" align="center">-->
+<!--                    <template #default="scope">-->
+<!--                        <el-tag :type="-->
+<!--                                scope.row.state === '成功'-->
+<!--                                    ? 'success'-->
+<!--                                    : scope.row.state === '失败'-->
+<!--                                    ? 'danger'-->
+<!--                                    : ''-->
+<!--                            ">{{ scope.row.state }}</el-tag>-->
+<!--                    </template>-->
+<!--                </el-table-column>-->
+
+                <el-table-column prop="date" label="创建时间"></el-table-column>
+                <el-table-column label="操作" width="180" align="center">
+                    <template #default="scope">
+<!--                        <el-button type="text" icon="el-icon-edit" @click="handleEdit(scope.$index, scope.row)">编辑-->
+<!--                        </el-button>-->
+                      <router-link to="/configform">
+                        <el-button type="text" icon="el-icon-edit">编辑
+                        </el-button>
+                      </router-link>
+                        <el-button type="text" icon="el-icon-delete" class="red"
+                            @click="handleDelete(scope.$index, scope.row)">删除</el-button>
+                    </template>
+                </el-table-column>
+            </el-table>
+            <div class="pagination">
+                <el-pagination background layout="total, prev, pager, next" :current-page="query.pageIndex"
+                    :page-size="query.pageSize" :total="pageTotal" @current-change="handlePageChange"></el-pagination>
+            </div>
+        </div>
+
+        <!-- 编辑弹出框 -->
+        <el-dialog title="编辑" v-model="editVisible" min-width="30%">
+            <el-form label-width="150px">
+                <el-form-item label="配置名称" required>
+                    <el-input v-model="form.name"></el-input>
+                </el-form-item>
+                <el-form-item label="训练文件" required>
+                    <el-input v-model="form.file"></el-input>
+                </el-form-item>
+                <el-form-item label="选择模型类别" required>
+                  <el-checkbox label="分类"></el-checkbox>
+                  <el-checkbox label="聚类"></el-checkbox>
+                  <el-checkbox label="回归"></el-checkbox>
+                  <el-checkbox label="自动化分类器"></el-checkbox>
+                </el-form-item>
+
+                <el-form-item label="特征选择方式" required>
+<!--                    <el-checkbox v-for="f in featureList" :key="f" :label="f"></el-checkbox>-->
+                    <el-checkbox label="手动选择"></el-checkbox>
+                    <el-checkbox label="自动选择"></el-checkbox>
+                </el-form-item>
+
+                <el-form-item label="选择特征字段" required>
+                  <el-alert type="info" description="您下列选择的第一个字段为分类模型的目标字段"
+                            show-icon style="height: 40px;"></el-alert>
+                </el-form-item>
+            </el-form>
+            <template #footer>
+                <span class="dialog-footer">
+                    <el-button @click="editVisible = false">取 消</el-button>
+                    <el-button type="primary" @click="saveEdit">确 定</el-button>
+                </span>
+            </template>
+        </el-dialog>
+    </div>
+</template>
+
+<script>
+import { ref, reactive } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { fetchData } from "../api/index";
+
+export default {
+    name: "config",
+    //训练特征
+  setup() {
+        const query = reactive({
+            file: "",
+            name: "",
+            pageIndex: 1,
+            pageSize: 10,
+        });
+
+        //new TODO
+        const typeList=["所有","分类","聚类","回归","自动分类器"];
+        const featureList=["所有","手动选择","自动选择"];
+        const multipleSelection =ref([]);
+
+        const tableData = ref([]);
+        const pageTotal = ref(0);
+        // 获取表格数据
+        const getData = () => {
+            fetchData(query).then((res) => {
+                tableData.value = res.list;
+                pageTotal.value = res.pageTotal || 50;
+            });
+        };
+        getData();
+
+        // 查询操作
+        const handleSearch = () => {
+            query.pageIndex = 1;
+            getData();
+        };
+        // 分页导航
+        const handlePageChange = (val) => {
+            query.pageIndex = val;
+            getData();
+        };
+
+        // 删除操作(单个)
+        const handleDelete = (index) => {
+            // 二次确认删除
+            ElMessageBox.confirm("确定要删除吗?", "提示", {
+                type: "warning",
+            })
+                .then(() => {
+                    ElMessage.success("删除成功");
+                    tableData.value.splice(index, 1);
+                })
+                .catch(() => {});
+        };
+
+        //TODO
+        const handleSelectionChange = (val) => {
+          multipleSelection.value = val
+        };
+
+        //TODO 批量删除
+        const handleBatchDelete =()=>{
+          // 二次确认
+          if(multipleSelection.value.length<=0){
+            ElMessageBox.alert("请先勾选要删除的模型", '提示', {
+              confirmButtonText: '好的'
+            })
+          }
+          else{
+            ElMessageBox.confirm("确定要删除这些模型吗?", "提示", {
+              type: "warning",
+            })
+                .then(() => {
+                  let idList=[];
+                  for(let i=0;i<multipleSelection.value.length;i++){
+                    let id=multipleSelection.value[i]['id'];
+                    idList.push(id);
+                  }
+                  idList.sort();
+                  console.log(idList);
+                  for (let i = idList[idList.length-1]; i >=0 ; i--) {
+                    tableData.value.splice(i,1);
+                  }
+                  ElMessage.success("删除成功");
+                })
+                .catch(() => {});
+          }
+        };
+
+
+        // 表格编辑时弹窗和保存
+        const editVisible = ref(false);
+        let form = reactive({
+            name: "",
+            file: "",
+          // classification:"",
+          // feature:"",
+        });
+        let idx = -1;
+        const handleEdit = (index, row) => {
+            idx = index;
+            Object.keys(form).forEach((item) => {
+                form[item] = row[item];
+            });
+            editVisible.value = true;
+        };
+
+        const saveEdit = () => {
+            editVisible.value = false;
+            ElMessage.success(`修改第 ${idx + 1} 行成功`);
+            Object.keys(form).forEach((item) => {
+                tableData.value[idx][item] = form[item];
+            });
+        };
+
+        return {
+            query,
+            tableData,
+            pageTotal,
+            editVisible,
+            form,
+            handleSearch,
+            handlePageChange,
+            handleDelete,
+          handleSelectionChange,
+            handleBatchDelete,
+            handleEdit,
+            saveEdit,
+        };
+    },
+};
+</script>
+
+<style scoped>
+.handle-box {
+    margin-bottom: 20px;
+}
+
+.handle-select {
+    width: 120px;
+}
+
+.handle-input {
+    width: 300px;
+    display: inline-block;
+}
+.table {
+    width: 100%;
+    font-size: 14px;
+}
+.red {
+    color: #ff0000;
+}
+.mr10 {
+    margin-right: 10px;
+}
+.table-td-thumb {
+    display: block;
+    margin: auto;
+    width: 40px;
+    height: 40px;
+}
+</style>

+ 170 - 0
src/views/ConfigForm.vue

@@ -0,0 +1,170 @@
+<template>
+  <div>
+    <div class="crumbs">
+      <el-breadcrumb separator="/">
+        <el-breadcrumb-item>
+          <i class="el-icon-lx-calendar"></i> 模型配置
+        </el-breadcrumb-item>
+
+      </el-breadcrumb>
+    </div>
+    <div class="container">
+      <div class="form-box" >
+        <el-form ref="formRef" :rules="rules" :model="form" label-width="120px">
+          <el-form-item label="模型名称" prop="name">
+            <el-input v-model="form.name"></el-input>
+          </el-form-item>
+<!--          <el-form-item label="选择文件" prop="region">-->
+<!--            <el-select v-model="form.region" placeholder="请选择">-->
+<!--              <el-option key="bbk" label="无" value="bbk"></el-option>-->
+<!--            </el-select>-->
+<!--          </el-form-item>-->
+          <el-form-item label="配置类型" prop="region">
+            <el-select v-model="form.region" placeholder="请选择配置类型">
+              <el-option key="0" label="所有" value="0"></el-option>
+              <el-option key="1" label="分类" value="1"></el-option>
+              <el-option key="2" label="聚类" value="2"></el-option>
+              <el-option key="3" label="回归" value="3"></el-option>
+              <el-option key="4" label="自动化" value="4"></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="特征设置方式" prop="region">
+            <el-select v-model="form.region" placeholder="请选择配置类型">
+              <el-option key="0" label="手动" value="0"></el-option>
+              <el-option key="1" label="自动" value="1"></el-option>
+            </el-select>
+          </el-form-item>
+            <el-form-item label="模型参数" prop="region">
+            <el-table :data="tableData" border class="table" ref="multipleTable" header-cell-class-name="table-header">
+<!--              <el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>-->
+              <el-table-column label="参数名">
+                <template #default="scope">{{ scope.row.fieldname }}</template>
+              </el-table-column>
+              <el-table-column label="参数值">
+                <template #default="scope">{{ scope.row.alias }}</template>
+              </el-table-column>
+              <el-table-column label="参数范围">
+                <template #default="scope">{{ scope.row.desc }}</template>
+              </el-table-column>
+              <el-table-column label="参数说明">
+                <template #default="scope">{{ scope.row.num }}</template>
+              </el-table-column>
+            </el-table>
+          </el-form-item>
+          <el-form-item label="选择特征字段" required>
+            <el-alert type="info" description="您下列选择的第一个字段为分类模型的目标字段"
+                      show-icon style="height: 40px;"></el-alert>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="onSubmit">表单提交</el-button>
+            <el-button @click="onReset">重置表单</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { reactive, ref } from "vue";
+import { ElMessage } from "element-plus";
+export default {
+  name: "configform",
+  setup() {
+    const options = [
+      {
+        value: "guangdong",
+        label: "广东省",
+        children: [
+          {
+            value: "guangzhou",
+            label: "广州市",
+            children: [
+              {
+                value: "tianhe",
+                label: "天河区",
+              },
+              {
+                value: "haizhu",
+                label: "海珠区",
+              },
+            ],
+          },
+          {
+            value: "dongguan",
+            label: "东莞市",
+            children: [
+              {
+                value: "changan",
+                label: "长安镇",
+              },
+              {
+                value: "humen",
+                label: "虎门镇",
+              },
+            ],
+          },
+        ],
+      },
+      {
+        value: "hunan",
+        label: "湖南省",
+        children: [
+          {
+            value: "changsha",
+            label: "长沙市",
+            children: [
+              {
+                value: "yuelu",
+                label: "岳麓区",
+              },
+            ],
+          },
+        ],
+      },
+    ];
+    const rules = {
+      name: [
+        { required: true, message: "请输入表单名称", trigger: "blur" },
+      ],
+    };
+    const formRef = ref(null);
+    const form = reactive({
+      name: "",
+      region: "",
+      date1: "",
+      date2: "",
+      delivery: true,
+      type: ["步步高"],
+      resource: "小天才",
+      desc: "",
+      options: [],
+    });
+    // 提交
+    const onSubmit = () => {
+      // 表单校验
+      formRef.value.validate((valid) => {
+        if (valid) {
+          console.log(form);
+          ElMessage.success("提交成功!");
+        } else {
+          return false;
+        }
+      });
+    };
+    // 重置
+    const onReset = () => {
+      formRef.value.resetFields();
+    };
+
+    return {
+      options,
+      rules,
+      formRef,
+      form,
+      onSubmit,
+      onReset,
+    };
+  },
+};
+</script>

+ 198 - 0
src/views/Dashboard.vue

@@ -0,0 +1,198 @@
+<template>
+  <div>
+    <div class="crumbs">
+      <el-breadcrumb separator="/">
+        <el-breadcrumb-item>
+          <i class="el-icon-lx-cascades"></i> 首页
+        </el-breadcrumb-item>
+      </el-breadcrumb>
+    </div>
+    <div class="container">
+      <div class="handle-box">
+        <el-button type="primary" icon="el-icon-thumb" @click="handleEdit">选择字段</el-button>
+        <el-button type="primary" plain icon="el-icon-s-order" @click="handleSave">保存</el-button>
+      </div>
+
+      <el-table :data="tableData" border class="table" ref="multipleTable" header-cell-class-name="table-header">
+        <el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>
+        <el-table-column label="字段名">
+          <template #default="scope">{{ scope.row.fieldname }}</template>
+        </el-table-column>
+        <el-table-column label="别名">
+          <template #default="scope">{{ scope.row.alias }}</template>
+        </el-table-column>
+        <el-table-column label="描述">
+          <template #default="scope">{{ scope.row.desc }}</template>
+        </el-table-column>
+        <el-table-column label="取值类型">
+          <template #default="scope">{{ scope.row.num }}</template>
+        </el-table-column>
+        <el-table-column label="分布类型">
+          <template #default="scope">{{ scope.row.distribution }}</template>
+        </el-table-column>
+        <el-table-column label="空值率">
+          <template #default="scope">{{ scope.row.null }}</template>
+        </el-table-column>
+
+        <el-table-column label="值域" >
+          <template #default="scope">{{ scope.row.num }}</template>
+        </el-table-column>
+        <el-table-column  label="创建时间"></el-table-column>
+      </el-table>
+      <div class="pagination">
+        <el-pagination background layout="total, prev, pager, next" :current-page="query.pageIndex"
+                       :page-size="query.pageSize" :total="pageTotal" @current-change="handlePageChange"></el-pagination>
+      </div>
+    </div>
+
+    <!-- 编辑弹出框 -->
+    <el-dialog title="选择字段" v-model="editVisible" width="30%">
+      <el-form label-width="120px">
+        <el-form-item label="统计分析" required>
+          <el-input v-model="form.name"></el-input>
+        </el-form-item>
+        <el-form-item label="所选方法简介" required>
+          <el-input v-model="form.address"></el-input>
+        </el-form-item>
+        <el-form-item label="可选择字段" required>
+
+        </el-form-item>
+
+      </el-form>
+      <template #footer>
+                <span class="dialog-footer">
+                    <el-button @click="editVisible = false">取 消</el-button>
+                    <el-button type="primary" @click="saveEdit">确 定</el-button>
+                </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { ref, reactive } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { fetchData } from "../api/index";
+export default {
+  name: "config",
+  //训练特征
+  setup() {
+    const query = reactive({
+      address: "",
+      name: "",
+      pageIndex: 1,
+      pageSize: 10,
+    });
+
+    //new TODO
+    //TODO
+    const fieldNameList=[]; //字段名
+    const aliasList=[];   //别名
+    const descList=[];      //描述
+    const aList=[];   //取值类型
+    const bList=[];   //分布类型
+    const cList=[];   //空值率
+    const dList=[];
+
+
+    const tableData = ref([]);
+    const pageTotal = ref(0);
+    // 获取表格数据
+    const getData = () => {
+      fetchData(query).then((res) => {
+        tableData.value = res.list;
+        pageTotal.value = res.pageTotal || 50;
+      });
+    };
+    getData();
+
+    // 查询操作
+    const handleSearch = () => {
+      query.pageIndex = 1;
+      getData();
+    };
+    // 分页导航
+    const handlePageChange = (val) => {
+      query.pageIndex = val;
+      getData();
+    };
+
+    // 删除操作
+    const handleDelete = (index) => {
+      // 二次确认删除
+      ElMessageBox.confirm("确定要删除吗?", "提示", {
+        type: "warning",
+      })
+          .then(() => {
+            ElMessage.success("删除成功");
+            tableData.value.splice(index, 1);
+          })
+          .catch(() => {});
+    };
+
+    // 表格编辑时弹窗和保存
+    const editVisible = ref(false);
+    let form = reactive({
+      name: "",
+      address: "",
+      // classification:"",
+      // feature:"",
+    });
+    let idx = -1;
+    const handleEdit = () => {
+      editVisible.value = true;
+    };
+    const saveEdit = () => {
+      editVisible.value = false;
+      ElMessage.success(`修改第 ${idx + 1} 行成功`);
+      Object.keys(form).forEach((item) => {
+        tableData.value[idx][item] = form[item];
+      });
+    };
+
+    return {
+      query,
+      tableData,
+      pageTotal,
+      editVisible,
+      form,
+      handleSearch,
+      handlePageChange,
+      handleDelete,
+      handleEdit,
+      saveEdit,
+    };
+  },
+};
+</script>
+
+<style scoped>
+.handle-box {
+  margin-bottom: 20px;
+}
+
+.handle-select {
+  width: 120px;
+}
+
+.handle-input {
+  width: 300px;
+  display: inline-block;
+}
+.table {
+  width: 100%;
+  font-size: 14px;
+}
+.red {
+  color: #ff0000;
+}
+.mr10 {
+  margin-right: 10px;
+}
+.table-td-thumb {
+  display: block;
+  margin: auto;
+  width: 40px;
+  height: 40px;
+}
+</style>

+ 139 - 0
src/views/Dllearning.vue

@@ -0,0 +1,139 @@
+<!--<template>-->
+<!--<div className="home-page">-->
+<!--<div className="sub-menu">-->
+<!--  <button class="el-button el-button&#45;&#45;primary" type="button" data-v-4eda24fc="">&lt;!&ndash;v-if&ndash;&gt;<i class="el-icon-upload"></i><span>上传</span></button>-->
+
+
+<!--  <button class="el-button el-button&#45;&#45;primary" type="button" data-v-4eda24fc="">&lt;!&ndash;v-if&ndash;&gt;<i class="el-icon-s-home"></i><span>模型</span></button>-->
+<!--</div>-->
+<!--<div className="carousel-page">-->
+<!--  <h3 className="img-list-title">图片文件列表</h3>-->
+
+
+
+
+<!--    <el-table  :show-header="false" style="width: 100%">-->
+<!--      <div>1</div>>-->
+<!--    </el-table>-->
+
+
+
+
+
+
+<!--</div>-->
+<!--</div>-->
+<!--</template>-->
+
+
+<template>
+  <div class="">
+    <div class="crumbs">
+      <el-breadcrumb separator="/">
+        <el-breadcrumb-item><i class="el-icon-lx-copy"></i> 深度学习</el-breadcrumb-item>
+      </el-breadcrumb>
+    </div>
+    <div class="container">
+      <el-tabs v-model="message">
+        <el-tab-pane :label="`图片文件列表`" name="first">
+          <el-table :data="state.unread" :show-header="false" style="width: 100%">
+            <el-table-column>
+              <template #default="scope">
+                <span class="message-title">{{scope.row.title}}</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="date" width="180"></el-table-column>
+            <el-table-column width="120">
+              <template #default="scope">
+                <el-button size="small" @click="handleRead(scope.$index)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+<!--          <div class="handle-row">-->
+<!--            <el-button type="primary">全部标为已读</el-button>-->
+<!--          </div>-->
+
+<!--            <button class="el-button el-button&#45;&#45;primary" type="button" data-v-4eda24fc="">&lt;!&ndash;v-if&ndash;&gt;<i class="el-icon-upload"></i><span>上传</span></button>-->
+
+<!--            <router-link to="/config">-->
+<!--&lt;!&ndash;            <button class="el-button el-button&#45;&#45;primary" type="button" data-v-4eda24fc="">&lt;!&ndash;v-if&ndash;&gt;<i class="el-icon-s-home"></i><span>添加模型</span></button>&ndash;&gt;-->
+<!--              <el-button type="primary" size="large">配置模型</el-button>-->
+<!--            </router-link>-->
+
+
+        </el-tab-pane>
+        <router-link to="/dlform">
+          <el-button type="primary" size="large"><i class="el-icon-s-home"></i>配置模型</el-button>
+        </router-link>
+
+
+      </el-tabs>
+    </div>
+  </div>
+</template>
+
+<script>
+import { ref, reactive } from "vue";
+export default {
+  name: "tabs",
+  setup() {
+    const message = ref("first");
+    const state = reactive({
+      unread: [
+        {
+          date: "2018-04-19 20:00:00",
+          title: "文件1",
+        },
+        {
+          date: "2018-04-19 21:00:00",
+          title: "文件2",
+        },
+      ],
+      read: [
+        {
+          date: "2018-04-19 20:00:00",
+          title: "【系统通知】该系统将于今晚凌晨2点到5点进行升级维护",
+        },
+      ],
+      recycle: [
+        {
+          date: "2018-04-19 20:00:00",
+          title: "【系统通知】该系统将于今晚凌晨2点到5点进行升级维护",
+        },
+      ],
+    });
+
+    const handleRead = (index) => {
+      const item = state.unread.splice(index, 1);
+      console.log(item);
+      state.read = item.concat(state.read);
+    };
+    const handleDel = (index) => {
+      const item = state.read.splice(index, 1);
+      state.recycle = item.concat(state.recycle);
+    };
+    const handleRestore = (index) => {
+      const item = state.recycle.splice(index, 1);
+      state.read = item.concat(state.read);
+    };
+
+    return {
+      message,
+      state,
+      handleRead,
+      handleDel,
+      handleRestore,
+    };
+  },
+};
+</script>
+
+<style>
+.message-title {
+  cursor: pointer;
+}
+.handle-row {
+  margin-top: 30px;
+}
+</style>
+

+ 26 - 0
src/views/Donate.vue

@@ -0,0 +1,26 @@
+<template>
+    <div>
+        <div class="crumbs">
+            <el-breadcrumb separator="/">
+                <el-breadcrumb-item>
+                    <i class="el-icon-lx-redpacket_fill"></i> 支持作者
+                </el-breadcrumb-item>
+            </el-breadcrumb>
+        </div>
+        <div class="container">
+            <div class="plugins-tips">如果该框架对你有帮助,那就请作者喝杯饮料吧!加微信号linxin_20探讨问题。</div>
+            <div>
+                <img src="https://lin-xin.gitee.io/images/weixin.jpg" />
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    name: "donate"
+};
+</script>
+
+<style>
+</style>

+ 58 - 0
src/views/Editor.vue

@@ -0,0 +1,58 @@
+<template>
+    <div>
+        <div class="crumbs">
+            <el-breadcrumb separator="/">
+                <el-breadcrumb-item>
+                    <i class="el-icon-lx-calendar"></i> 表单
+                </el-breadcrumb-item>
+                <el-breadcrumb-item>富文本编辑器</el-breadcrumb-item>
+            </el-breadcrumb>
+        </div>
+        <div class="container">
+            <div class="plugins-tips">
+                wangEditor:轻量级 web 富文本编辑器,配置方便,使用简单。
+                访问地址:
+                <a href="https://www.wangeditor.com/doc/" target="_blank">wangEditor</a>
+            </div>
+            <div class="mgb20" ref='editor'></div>
+            <el-button type="primary" @click="syncHTML">提交</el-button>
+        </div>
+    </div>
+</template>
+
+<script>
+import WangEditor from "wangEditor";
+import { ref, reactive, onMounted, onBeforeUnmount } from "vue";
+export default {
+    name: "editor",
+    setup() {
+        const editor = ref(null);
+        const content = reactive({
+            html: "",
+            text: "",
+        });
+        let instance;
+        onMounted(() => {
+            instance = new WangEditor(editor.value);
+            instance.config.zIndex = 1;
+            instance.create();
+        });
+        onBeforeUnmount(() => {
+            instance.destroy();
+            instance = null;
+        });
+        const syncHTML = () => {
+            content.html = instance.txt.html();
+            console.log(content.html);
+        };
+        return {
+            syncHTML,
+            editor,
+            content,
+        };
+    },
+};
+</script>
+
+<style>
+</style>

+ 44 - 0
src/views/Home.vue

@@ -0,0 +1,44 @@
+<template>
+    <div class="about">
+        <v-header />
+        <v-sidebar />
+        <div class="content-box" :class="{ 'content-collapse': collapse }">
+            <v-tags></v-tags>
+            <div class="content">
+                <router-view v-slot="{ Component }">
+                    <transition name="move" mode="out-in">
+                        <keep-alive :include="tagsList">
+                            <component :is="Component" />
+                        </keep-alive>
+                    </transition>
+                </router-view>
+                <!-- <el-backtop target=".content"></el-backtop> -->
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+import { computed } from "vue";
+import { useStore } from "vuex";
+import vHeader from "../components/Header.vue";
+import vSidebar from "../components/Sidebar.vue";
+import vTags from "../components/Tags.vue";
+export default {
+    components: {
+        vHeader,
+        vSidebar,
+        vTags,
+    },
+    setup() {
+        const store = useStore();
+        const tagsList = computed(() =>
+            store.state.tagsList.map((item) => item.name)
+        );
+        const collapse = computed(() => store.state.collapse);
+        return {
+            tagsList,
+            collapse,
+        };
+    },
+};
+</script>

+ 40 - 0
src/views/I18n.vue

@@ -0,0 +1,40 @@
+<template>
+    <section class="main">
+        <div class="crumbs">
+            <el-breadcrumb separator="/">
+                <el-breadcrumb-item>
+                    <i class="el-icon-lx-global"></i>
+                    {{$t('i18n.breadcrumb')}}
+                </el-breadcrumb-item>
+            </el-breadcrumb>
+        </div>
+        <div class="container">
+            <span>{{$t('i18n.tips')}}</span>
+            <el-button
+                type="primary"
+                @click="$i18n.locale = $i18n.locale === 'zh-cn'?'en':'zh-cn';"
+            >{{$t('i18n.btn')}}</el-button>
+            <div class="list">
+                <h2>{{$t('i18n.title1')}}</h2>
+                <p>{{$t('i18n.p1')}}</p>
+                <p>{{$t('i18n.p2')}}</p>
+                <p>{{$t('i18n.p3')}}</p>
+            </div>
+        </div>
+    </section>
+</template>
+
+<script>
+export default {
+    name: "i18n"
+};
+</script>
+
+<style scoped>
+.list {
+    padding: 30px 0;
+}
+.list p {
+    margin-bottom: 20px;
+}
+</style>

+ 229 - 0
src/views/Icon.vue

@@ -0,0 +1,229 @@
+<template>
+    <div>
+        <div class="crumbs">
+            <el-breadcrumb separator="/">
+                <el-breadcrumb-item>
+                    <i class="el-icon-lx-emoji"></i> 自定义图标
+                </el-breadcrumb-item>
+            </el-breadcrumb>
+        </div>
+        <div class="container">
+            <h2>使用方法</h2>
+            <p style="line-height: 50px;">直接通过设置类名为 el-icon-lx-iconName 来使用即可。例如:(共{{iconList.length}}个图标)</p>
+            <p class="example-p">
+                <i class="el-icon-lx-redpacket_fill" style="font-size: 30px;color: #ff5900"></i>
+                <span>&lt;i class=&quot;el-icon-lx-redpacket_fill&quot;&gt;&lt;/i&gt;</span>
+            </p>
+            <p class="example-p">
+                <i class="el-icon-lx-weibo" style="font-size: 30px;color:#fd5656"></i>
+                <span>&lt;i class=&quot;el-icon-lx-weibo&quot;&gt;&lt;/i&gt;</span>
+            </p>
+            <p class="example-p">
+                <i class="el-icon-lx-emojifill" style="font-size: 30px;color: #ffc300"></i>
+                <span>&lt;i class=&quot;el-icon-lx-emojifill&quot;&gt;&lt;/i&gt;</span>
+            </p>
+            <br />
+            <h2>图标</h2>
+            <div class="search-box">
+                <el-input class="search" size="large" v-model="keyword" clearable placeholder="请输入图标名称"></el-input>
+            </div>
+            <ul>
+                <li class="icon-li" v-for="(item,index) in list" :key="index">
+                    <div class="icon-li-content">
+                        <i :class="`el-icon-lx-${item}`"></i>
+                        <span>{{item}}</span>
+                    </div>
+                </li>
+            </ul>
+        </div>
+    </div>
+</template>
+
+<script>
+import { computed, ref } from "vue";
+export default {
+    name: "icon",
+    setup() {
+        const iconList = [
+            "attentionforbid",
+            "attentionforbidfill",
+            "attention",
+            "attentionfill",
+            "tag",
+            "tagfill",
+            "people",
+            "peoplefill",
+            "notice",
+            "noticefill",
+            "mobile",
+            "mobilefill",
+            "voice",
+            "voicefill",
+            "unlock",
+            "lock",
+            "home",
+            "homefill",
+            "delete",
+            "deletefill",
+            "notification",
+            "notificationfill",
+            "notificationforbidfill",
+            "like",
+            "likefill",
+            "comment",
+            "commentfill",
+            "camera",
+            "camerafill",
+            "warn",
+            "warnfill",
+            "time",
+            "timefill",
+            "location",
+            "locationfill",
+            "favor",
+            "favorfill",
+            "skin",
+            "skinfill",
+            "news",
+            "newsfill",
+            "record",
+            "recordfill",
+            "emoji",
+            "emojifill",
+            "message",
+            "messagefill",
+            "goods",
+            "goodsfill",
+            "crown",
+            "crownfill",
+            "move",
+            "add",
+            "hot",
+            "hotfill",
+            "service",
+            "servicefill",
+            "present",
+            "presentfill",
+            "pic",
+            "picfill",
+            "rank",
+            "rankfill",
+            "male",
+            "female",
+            "down",
+            "top",
+            "recharge",
+            "rechargefill",
+            "forward",
+            "forwardfill",
+            "info",
+            "infofill",
+            "redpacket",
+            "redpacket_fill",
+            "roundadd",
+            "roundaddfill",
+            "friendadd",
+            "friendaddfill",
+            "cart",
+            "cartfill",
+            "more",
+            "moreandroid",
+            "back",
+            "right",
+            "shop",
+            "shopfill",
+            "question",
+            "questionfill",
+            "roundclose",
+            "roundclosefill",
+            "roundcheck",
+            "roundcheckfill",
+            "global",
+            "mail",
+            "punch",
+            "exit",
+            "upload",
+            "read",
+            "file",
+            "link",
+            "full",
+            "group",
+            "friend",
+            "profile",
+            "addressbook",
+            "calendar",
+            "text",
+            "copy",
+            "share",
+            "wifi",
+            "vipcard",
+            "weibo",
+            "remind",
+            "refresh",
+            "filter",
+            "settings",
+            "scan",
+            "qrcode",
+            "cascades",
+            "apps",
+            "sort",
+            "searchlist",
+            "search",
+            "edit",
+        ];
+        const keyword = ref("");
+        const list = computed(() => {
+            return iconList.filter((item) => {
+                return item.indexOf(keyword.value) !== -1;
+            });
+        });
+
+        return {
+            iconList,
+            keyword,
+            list,
+        };
+    },
+};
+</script>
+
+<style scoped>
+.example-p {
+    height: 45px;
+    display: flex;
+    align-items: center;
+}
+.search-box {
+    text-align: center;
+    margin-top: 10px;
+}
+.search {
+    width: 300px;
+}
+ul,
+li {
+    list-style: none;
+}
+.icon-li {
+    display: inline-block;
+    padding: 10px;
+    width: 120px;
+    height: 120px;
+}
+.icon-li-content {
+    display: flex;
+    height: 100%;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    cursor: pointer;
+}
+.icon-li-content i {
+    font-size: 36px;
+    color: #606266;
+}
+.icon-li-content span {
+    margin-top: 10px;
+    color: #787878;
+}
+</style>

+ 125 - 0
src/views/Login.vue

@@ -0,0 +1,125 @@
+<template>
+    <div class="login-wrap">
+        <div class="ms-login">
+            <div class="ms-title">后台管理系统</div>
+            <el-form :model="param" :rules="rules" ref="login" label-width="0px" class="ms-content">
+                <el-form-item prop="username">
+                    <el-input v-model="param.username" placeholder="username">
+                        <template #prepend>
+                            <el-button icon="el-icon-user"></el-button>
+                        </template>
+                    </el-input>
+                </el-form-item>
+                <el-form-item prop="password">
+                    <el-input type="password" placeholder="password" v-model="param.password"
+                        @keyup.enter="submitForm()">
+                        <template #prepend>
+                            <el-button icon="el-icon-lock"></el-button>
+                        </template>
+                    </el-input>
+                </el-form-item>
+                <div class="login-btn">
+                    <el-button type="primary" @click="submitForm()">登录</el-button>
+                </div>
+                <p class="login-tips">Tips : 用户名和密码随便填。</p>
+            </el-form>
+        </div>
+    </div>
+</template>
+
+<script>
+import { ref, reactive } from "vue";
+import { useStore } from "vuex";
+import { useRouter } from "vue-router";
+import { ElMessage } from "element-plus";
+
+export default {
+    setup() {
+        const router = useRouter();
+        const param = reactive({
+            username: "admin",
+            password: "123123",
+        });
+
+        const rules = {
+            username: [
+                {
+                    required: true,
+                    message: "请输入用户名",
+                    trigger: "blur",
+                },
+            ],
+            password: [
+                { required: true, message: "请输入密码", trigger: "blur" },
+            ],
+        };
+        const login = ref(null);
+        const submitForm = () => {
+            login.value.validate((valid) => {
+                if (valid) {
+                    ElMessage.success("登录成功");
+                    localStorage.setItem("ms_username", param.username);
+                    router.push("/");
+                } else {
+                    ElMessage.error("登录成功");
+                    return false;
+                }
+            });
+        };
+
+        const store = useStore();
+        store.commit("clearTags");
+
+        return {
+            param,
+            rules,
+            login,
+            submitForm,
+        };
+    },
+};
+</script>
+
+<style scoped>
+.login-wrap {
+    position: relative;
+    width: 100%;
+    height: 100%;
+    background-image: url(../assets/img/login-bg.jpg);
+    background-size: 100%;
+}
+.ms-title {
+    width: 100%;
+    line-height: 50px;
+    text-align: center;
+    font-size: 20px;
+    color: #fff;
+    border-bottom: 1px solid #ddd;
+}
+.ms-login {
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    width: 350px;
+    margin: -190px 0 0 -175px;
+    border-radius: 5px;
+    background: rgba(255, 255, 255, 0.3);
+    overflow: hidden;
+}
+.ms-content {
+    padding: 30px 30px;
+}
+.login-btn {
+    text-align: center;
+}
+.login-btn button {
+    width: 100%;
+    height: 36px;
+    margin-bottom: 10px;
+}
+.login-tips {
+    font-size: 12px;
+    line-height: 30px;
+    color: #fff;
+}
+</style>

+ 40 - 0
src/views/Permission.vue

@@ -0,0 +1,40 @@
+<template>
+    <div>
+        <div class="crumbs">
+            <el-breadcrumb separator="/">
+                <el-breadcrumb-item>
+                    <i class="el-icon-lx-warn"></i> 权限测试
+                </el-breadcrumb-item>
+            </el-breadcrumb>
+        </div>
+        <div class="container">
+            <h1>管理员权限页面</h1>
+            <p>只有用 admin 账号登录的才拥有管理员权限,才能进到这个页面,其他账号想进来都会跳到403页面,重新用管理员账号登录才有权限。</p>
+            <p>
+                想尝试一下,请
+                <router-link to="/login" class="logout">退出登录</router-link>,随便输入个账号名,再进来试试看。
+            </p>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    name: "permission"
+};
+</script>
+
+<style scoped>
+h1 {
+    text-align: center;
+    margin: 30px 0;
+}
+p {
+    line-height: 30px;
+    margin-bottom: 10px;
+    text-indent: 2em;
+}
+.logout {
+    color: #409eff;
+}
+</style>

+ 137 - 0
src/views/Tabs.vue

@@ -0,0 +1,137 @@
+<template>
+    <div class="">
+        <div class="crumbs">
+            <el-breadcrumb separator="/">
+                <el-breadcrumb-item><i class="el-icon-lx-copy"></i> tab选项卡</el-breadcrumb-item>
+            </el-breadcrumb>
+        </div>
+        <div class="container">
+            <el-tabs v-model="message">
+                <el-tab-pane :label="`未读消息(${state.unread.length})`" name="first">
+                    <el-table :data="state.unread" :show-header="false" style="width: 100%">
+                        <el-table-column>
+                            <template #default="scope">
+                                <span class="message-title">{{scope.row.title}}</span>
+                            </template>
+                        </el-table-column>
+                        <el-table-column prop="date" width="180"></el-table-column>
+                        <el-table-column width="120">
+                            <template #default="scope">
+                                <el-button size="small" @click="handleRead(scope.$index)">标为已读</el-button>
+                            </template>
+                        </el-table-column>
+                    </el-table>
+                    <div class="handle-row">
+                        <el-button type="primary">全部标为已读</el-button>
+                    </div>
+                </el-tab-pane>
+                <el-tab-pane :label="`已读消息(${state.read.length})`" name="second">
+                    <template v-if="message === 'second'">
+                        <el-table :data="state.read" :show-header="false" style="width: 100%">
+                            <el-table-column>
+                                <template #default="scope">
+                                    <span class="message-title">{{scope.row.title}}</span>
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="date" width="150"></el-table-column>
+                            <el-table-column width="120">
+                                <template #default="scope">
+                                    <el-button type="danger" @click="handleDel(scope.$index)">删除</el-button>
+                                </template>
+                            </el-table-column>
+                        </el-table>
+                        <div class="handle-row">
+                            <el-button type="danger">删除全部</el-button>
+                        </div>
+                    </template>
+                </el-tab-pane>
+                <el-tab-pane :label="`回收站(${state.recycle.length})`" name="third">
+                    <template v-if="message === 'third'">
+                        <el-table :data="state.recycle" :show-header="false" style="width: 100%">
+                            <el-table-column>
+                                <template #default="scope">
+                                    <span class="message-title">{{scope.row.title}}</span>
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="date" width="150"></el-table-column>
+                            <el-table-column width="120">
+                                <template #default="scope">
+                                    <el-button @click="handleRestore(scope.$index)">还原</el-button>
+                                </template>
+                            </el-table-column>
+                        </el-table>
+                        <div class="handle-row">
+                            <el-button type="danger">清空回收站</el-button>
+                        </div>
+                    </template>
+                </el-tab-pane>
+            </el-tabs>
+        </div>
+    </div>
+</template>
+
+<script>
+import { ref, reactive } from "vue";
+export default {
+    name: "tabs",
+    setup() {
+        const message = ref("first");
+        const state = reactive({
+            unread: [
+                {
+                    date: "2018-04-19 20:00:00",
+                    title: "【系统通知】该系统将于今晚凌晨2点到5点进行升级维护",
+                },
+                {
+                    date: "2018-04-19 21:00:00",
+                    title: "今晚12点整发大红包,先到先得",
+                },
+            ],
+            read: [
+                {
+                    date: "2018-04-19 20:00:00",
+                    title: "【系统通知】该系统将于今晚凌晨2点到5点进行升级维护",
+                },
+            ],
+            recycle: [
+                {
+                    date: "2018-04-19 20:00:00",
+                    title: "【系统通知】该系统将于今晚凌晨2点到5点进行升级维护",
+                },
+            ],
+        });
+
+        const handleRead = (index) => {
+            const item = state.unread.splice(index, 1);
+            console.log(item);
+            state.read = item.concat(state.read);
+        };
+        const handleDel = (index) => {
+            const item = state.read.splice(index, 1);
+            state.recycle = item.concat(state.recycle);
+        };
+        const handleRestore = (index) => {
+            const item = state.recycle.splice(index, 1);
+            state.read = item.concat(state.read);
+        };
+
+        return {
+            message,
+            state,
+            handleRead,
+            handleDel,
+            handleRestore,
+        };
+    },
+};
+</script>
+
+<style>
+.message-title {
+    cursor: pointer;
+}
+.handle-row {
+    margin-top: 30px;
+}
+</style>
+

+ 133 - 0
src/views/Upload.vue

@@ -0,0 +1,133 @@
+<template>
+    <div>
+        <div class="crumbs">
+            <el-breadcrumb separator="/">
+                <el-breadcrumb-item>
+                    <i class="el-icon-lx-calendar"></i> 表单
+                </el-breadcrumb-item>
+                <el-breadcrumb-item>图片上传</el-breadcrumb-item>
+            </el-breadcrumb>
+        </div>
+        <div class="container">
+            <div class="content-title">支持拖拽</div>
+            <div class="plugins-tips">
+                Element UI自带上传组件。
+                访问地址:
+                <a href="http://element.eleme.io/#/zh-CN/component/upload" target="_blank">Element UI Upload</a>
+            </div>
+            <el-upload class="upload-demo" drag action="http://jsonplaceholder.typicode.com/api/posts/" multiple>
+                <i class="el-icon-upload"></i>
+                <div class="el-upload__text">
+                    将文件拖到此处,或
+                    <em>点击上传</em>
+                </div>
+                <template #tip>
+                    <div class="el-upload__tip">只能上传 jpg/png 文件,且不超过 500kb</div>
+                </template>
+            </el-upload>
+
+            <div class="content-title">支持裁剪</div>
+            <div class="plugins-tips">
+                vue-cropperjs:一个封装了 cropperjs 的 Vue 组件。
+                访问地址:
+                <a href="https://github.com/Agontuk/vue-cropperjs" target="_blank">vue-cropperjs</a>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import { ref } from "vue";
+import VueCropper from "vue-cropperjs";
+import "cropperjs/dist/cropper.css";
+import defaultSrc from "../assets/img/img.jpg";
+export default {
+    name: "upload",
+    components: {
+        VueCropper,
+    },
+    setup() {
+        const imgSrc = ref("");
+        const cropImg = ref(defaultSrc);
+        const dialogVisible = ref(false);
+        const cropper = ref(null);
+
+        const setImage = (e) => {
+            const file = e.target.files[0];
+            if (!file.type.includes("image/")) {
+                return;
+            }
+            const reader = new FileReader();
+            reader.onload = (event) => {
+                dialogVisible.value = true;
+                imgSrc.value = event.target.result;
+                cropper.value && cropper.value.replace(event.target.result);
+            };
+            reader.readAsDataURL(file);
+        };
+
+        const cropImage = () => {
+            cropImg.value = cropper.value.getCroppedCanvas().toDataURL();
+        };
+
+        const cancelCrop = () => {
+            dialogVisible.value = false;
+            cropImg.value = defaultSrc;
+        };
+
+        return {
+            cropper,
+            imgSrc,
+            cropImg,
+            dialogVisible,
+            setImage,
+            cropImage,
+            cancelCrop,
+        };
+    },
+};
+</script>
+
+<style scoped>
+.content-title {
+    font-weight: 400;
+    line-height: 50px;
+    margin: 10px 0;
+    font-size: 22px;
+    color: #1f2f3d;
+}
+
+.pre-img {
+    width: 100px;
+    height: 100px;
+    background: #f8f8f8;
+    border: 1px solid #eee;
+    border-radius: 5px;
+}
+.crop-demo {
+    display: flex;
+    align-items: flex-end;
+}
+.crop-demo-btn {
+    position: relative;
+    width: 100px;
+    height: 40px;
+    line-height: 40px;
+    padding: 0 20px;
+    margin-left: 30px;
+    background-color: #409eff;
+    color: #fff;
+    font-size: 14px;
+    border-radius: 4px;
+    box-sizing: border-box;
+}
+.crop-input {
+    position: absolute;
+    width: 100px;
+    height: 40px;
+    left: 0;
+    top: 0;
+    opacity: 0;
+    cursor: pointer;
+}
+</style>

+ 192 - 0
src/views/User.vue

@@ -0,0 +1,192 @@
+<template>
+    <div>
+        <el-row :gutter="20">
+            <el-col :span="12">
+                <el-card shadow="hover">
+                    <template #header>
+                        <div class="clearfix">
+                            <span>基础信息</span>
+                        </div>
+                    </template>
+                    <div class="info">
+                        <div class="info-image" @click="showDialog">
+                            <img :src="avatarImg" />
+                            <span class="info-edit">
+                                <i class="el-icon-lx-camerafill"></i>
+                            </span>
+                        </div>
+                        <div class="info-name">{{ name }}</div>
+                        <div class="info-desc">不可能!我的代码怎么可能会有bug!</div>
+                    </div>
+                </el-card>
+            </el-col>
+            <el-col :span="12">
+                <el-card shadow="hover">
+                    <template #header>
+                        <div class="clearfix">
+                            <span>账户编辑</span>
+                        </div>
+                    </template>
+                    <el-form label-width="90px">
+                        <el-form-item label="用户名:"> {{ name }} </el-form-item>
+                        <el-form-item label="旧密码:">
+                            <el-input type="password" v-model="form.old"></el-input>
+                        </el-form-item>
+                        <el-form-item label="新密码:">
+                            <el-input type="password" v-model="form.new"></el-input>
+                        </el-form-item>
+                        <el-form-item label="个人简介:">
+                            <el-input v-model="form.desc"></el-input>
+                        </el-form-item>
+                        <el-form-item>
+                            <el-button type="primary" @click="onSubmit">保存</el-button>
+                        </el-form-item>
+                    </el-form>
+                </el-card>
+            </el-col>
+        </el-row>
+        <el-dialog title="裁剪图片" v-model="dialogVisible" width="600px">
+            <vue-cropper ref="cropper" :src="imgSrc" :ready="cropImage" :zoom="cropImage" :cropmove="cropImage"
+                style="width: 100%; height: 400px"></vue-cropper>
+
+            <template #footer>
+                <span class="dialog-footer">
+                    <el-button class="crop-demo-btn" type="primary">选择图片
+                        <input class="crop-input" type="file" name="image" accept="image/*" @change="setImage" />
+                    </el-button>
+                    <el-button type="primary" @click="saveAvatar">上传并保存</el-button>
+                </span>
+            </template>
+        </el-dialog>
+    </div>
+</template>
+
+<script>
+import { reactive, ref } from "vue";
+import VueCropper from "vue-cropperjs";
+import "cropperjs/dist/cropper.css";
+import avatar from "../assets/img/img.jpg";
+export default {
+    name: "user",
+    components: {
+        VueCropper,
+    },
+    setup() {
+        const name = localStorage.getItem("ms_username");
+        const form = reactive({
+            old: "",
+            new: "",
+            desc: "不可能!我的代码怎么可能会有bug!",
+        });
+        const onSubmit = () => {};
+
+        const avatarImg = ref(avatar);
+        const imgSrc = ref("");
+        const cropImg = ref("");
+        const dialogVisible = ref(false);
+        const cropper = ref(null);
+
+        const showDialog = () => {
+            dialogVisible.value = true;
+            imgSrc.value = avatarImg.value;
+        };
+
+        const setImage = (e) => {
+            const file = e.target.files[0];
+            if (!file.type.includes("image/")) {
+                return;
+            }
+            const reader = new FileReader();
+            reader.onload = (event) => {
+                dialogVisible.value = true;
+                imgSrc.value = event.target.result;
+                cropper.value && cropper.value.replace(event.target.result);
+            };
+            reader.readAsDataURL(file);
+        };
+
+        const cropImage = () => {
+            cropImg.value = cropper.value.getCroppedCanvas().toDataURL();
+        };
+
+        const saveAvatar = () => {
+            avatarImg.value = cropImg.value;
+            dialogVisible.value = false;
+        };
+
+        return {
+            name,
+            form,
+            onSubmit,
+            cropper,
+            avatarImg,
+            imgSrc,
+            cropImg,
+            showDialog,
+            dialogVisible,
+            setImage,
+            cropImage,
+            saveAvatar,
+        };
+    },
+};
+</script>
+
+<style scoped>
+.info {
+    text-align: center;
+    padding: 35px 0;
+}
+.info-image {
+    position: relative;
+    margin: auto;
+    width: 100px;
+    height: 100px;
+    background: #f8f8f8;
+    border: 1px solid #eee;
+    border-radius: 50px;
+    overflow: hidden;
+}
+.info-image img {
+    width: 100%;
+    height: 100%;
+}
+.info-edit {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: 100%;
+    background: rgba(0, 0, 0, 0.5);
+    opacity: 0;
+    transition: opacity 0.3s ease;
+}
+.info-edit i {
+    color: #eee;
+    font-size: 25px;
+}
+.info-image:hover .info-edit {
+    opacity: 1;
+}
+.info-name {
+    margin: 15px 0 10px;
+    font-size: 24px;
+    font-weight: 500;
+    color: #262626;
+}
+.crop-demo-btn {
+    position: relative;
+}
+.crop-input {
+    position: absolute;
+    width: 100px;
+    height: 40px;
+    left: 0;
+    top: 0;
+    opacity: 0;
+    cursor: pointer;
+}
+</style>

+ 196 - 0
src/views/dlform.vue

@@ -0,0 +1,196 @@
+<template>
+  <div>
+    <div class="crumbs">
+      <el-breadcrumb separator="/">
+        <el-breadcrumb-item>
+          <i class="el-icon-lx-calendar"></i> 模型配置
+        </el-breadcrumb-item>
+
+      </el-breadcrumb>
+    </div>
+    <div class="container">
+      <div class="form-box">
+        <el-form ref="formRef" :rules="rules" :model="form" label-width="80px">
+          <el-form-item label="模型名称" prop="name">
+            <el-input v-model="form.name"></el-input>
+          </el-form-item>
+          <el-form-item label="选择文件" prop="region">
+            <el-select v-model="form.region" placeholder="请选择">
+              <el-option key="bbk" label="无" value="bbk"></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="选择模型" prop="region">
+            <el-select v-model="form.region" placeholder="请选择">
+              <el-option key="bbk" label="无" value="bbk"></el-option>
+            </el-select>
+          </el-form-item>
+<!--          <el-form-item label="日期时间">-->
+<!--            <el-col :span="11">-->
+<!--              <el-form-item prop="date1">-->
+<!--                <el-date-picker type="date" placeholder="选择日期" v-model="form.date1"-->
+<!--                                style="width: 100%;"></el-date-picker>-->
+<!--              </el-form-item>-->
+<!--            </el-col>-->
+<!--            <el-col class="line" :span="2">-</el-col>-->
+<!--            <el-col :span="11">-->
+<!--              <el-form-item prop="date2">-->
+<!--                <el-time-picker placeholder="选择时间" v-model="form.date2" style="width: 100%;">-->
+<!--                </el-time-picker>-->
+<!--              </el-form-item>-->
+<!--            </el-col>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item label="城市级联" prop="options">-->
+<!--            <el-cascader :options="options" v-model="form.options"></el-cascader>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item label="选择开关" prop="delivery">-->
+<!--            <el-switch v-model="form.delivery"></el-switch>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item label="多选框" prop="type">-->
+<!--            <el-checkbox-group v-model="form.type">-->
+<!--              <el-checkbox label="步步高" name="type"></el-checkbox>-->
+<!--              <el-checkbox label="小天才" name="type"></el-checkbox>-->
+<!--              <el-checkbox label="imoo" name="type"></el-checkbox>-->
+<!--            </el-checkbox-group>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item label="单选框" prop="resource">-->
+<!--            <el-radio-group v-model="form.resource">-->
+<!--              <el-radio label="步步高"></el-radio>-->
+<!--              <el-radio label="小天才"></el-radio>-->
+<!--              <el-radio label="imoo"></el-radio>-->
+<!--            </el-radio-group>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item label="文本框" prop="desc">-->
+<!--            <el-input type="textarea" rows="5" v-model="form.desc"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item>-->
+            <el-form-item label="模型参数" prop="region">
+            <el-table :data="tableData" border class="table" ref="multipleTable" header-cell-class-name="table-header">
+<!--              <el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>-->
+              <el-table-column label="参数名">
+                <template #default="scope">{{ scope.row.fieldname }}</template>
+              </el-table-column>
+              <el-table-column label="参数值">
+                <template #default="scope">{{ scope.row.alias }}</template>
+              </el-table-column>
+              <el-table-column label="参数范围">
+                <template #default="scope">{{ scope.row.desc }}</template>
+              </el-table-column>
+              <el-table-column label="参数说明">
+                <template #default="scope">{{ scope.row.num }}</template>
+              </el-table-column>
+
+            </el-table>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="onSubmit">表单提交</el-button>
+            <el-button @click="onReset">重置表单</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { reactive, ref } from "vue";
+import { ElMessage } from "element-plus";
+export default {
+  name: "baseform",
+  setup() {
+    const options = [
+      {
+        value: "guangdong",
+        label: "广东省",
+        children: [
+          {
+            value: "guangzhou",
+            label: "广州市",
+            children: [
+              {
+                value: "tianhe",
+                label: "天河区",
+              },
+              {
+                value: "haizhu",
+                label: "海珠区",
+              },
+            ],
+          },
+          {
+            value: "dongguan",
+            label: "东莞市",
+            children: [
+              {
+                value: "changan",
+                label: "长安镇",
+              },
+              {
+                value: "humen",
+                label: "虎门镇",
+              },
+            ],
+          },
+        ],
+      },
+      {
+        value: "hunan",
+        label: "湖南省",
+        children: [
+          {
+            value: "changsha",
+            label: "长沙市",
+            children: [
+              {
+                value: "yuelu",
+                label: "岳麓区",
+              },
+            ],
+          },
+        ],
+      },
+    ];
+    const rules = {
+      name: [
+        { required: true, message: "请输入表单名称", trigger: "blur" },
+      ],
+    };
+    const formRef = ref(null);
+    const form = reactive({
+      name: "",
+      region: "",
+      date1: "",
+      date2: "",
+      delivery: true,
+      type: ["步步高"],
+      resource: "小天才",
+      desc: "",
+      options: [],
+    });
+    // 提交
+    const onSubmit = () => {
+      // 表单校验
+      formRef.value.validate((valid) => {
+        if (valid) {
+          console.log(form);
+          ElMessage.success("提交成功!");
+        } else {
+          return false;
+        }
+      });
+    };
+    // 重置
+    const onReset = () => {
+      formRef.value.resetFields();
+    };
+
+    return {
+      options,
+      rules,
+      formRef,
+      form,
+      onSubmit,
+      onReset,
+    };
+  },
+};
+</script>

+ 9 - 0
vite.config.js

@@ -0,0 +1,9 @@
+import vue from '@vitejs/plugin-vue'
+
+export default {
+    base: './',
+    plugins: [vue()],
+    optimizeDeps: {
+        include: ['schart.js']
+    }
+}

二进制
参考/web前端结构.docx


二进制
参考/~$eb前端结构.docx


+ 49 - 0
参考/会议记录/1月28日-2月4日.md

@@ -0,0 +1,49 @@
+## 1.项目说明
+
+这个仓库是我们AI大创组的前端代码仓库。
+
+该项目参考了一个github模板,启动前端之前需要在Terminal里输入:
+
+```bash
+	npm install
+
+​	npm run dev
+```
+
+
+
+## 2.本次任务
+
+| 人员   | 任务             |
+| ------ | ---------------- |
+| 陈凯文 | 修改模型页面     |
+| 冯亚林 | 修改配置页面     |
+| 郭子坤 | 修改首页         |
+| 蒋俊敏 | 修改深度学习页面 |
+
+**时间:1月28日 周五 —— 2月4日 周五**
+
+**其他任务:**
+
+1. 学习以下工具:
+   - Vue3 +  组件库Element Plus + JavaScript + 测试工具Swagger 和 jest
+2. 熟悉模板代码
+3. 学习用jest、swagger、postman等测试接口
+4. 细化各种已有文件,比如接口的excel文件
+
+
+
+## 3.项目参考
+
+学长的论文、前后端项目代码
+
+github项目 https://github.com/lin-xin/vue-manage-system
+
+https://www.jestjs.cn/  jest 中文文档
+
+[网易云课堂,为你精选好课 (163.com)](https://live.study.163.com/live/index.html?courseId=100100540&lesson=104596209&liveId=17dabaf6fb35&staffFree=true&_now=1642757470866) 第一节课中间部分有对于前端js单元测试的简介
+
+https://www.jianshu.com/p/33c28a65deb8 Swagger-强大的API文档工具
+
+https://element-plus.gitee.io/zh-CN/ Element-Plus
+

二进制
参考/接口.xlsx


二进制
参考/接口测试.pdf


二进制
参考/接口测试md/接口测试.assets/image-20220207152620531.png


二进制
参考/接口测试md/接口测试.assets/image-20220207152908085.png


二进制
参考/接口测试md/接口测试.assets/image-20220207153409659.png


二进制
参考/接口测试md/接口测试.assets/image-20220207162707754.png


二进制
参考/接口测试md/接口测试.assets/image-20220207163557482.png


二进制
参考/接口测试md/接口测试.assets/image-20220207163711420.png


二进制
参考/接口测试md/接口测试.assets/image-20220207163917993.png


二进制
参考/接口测试md/接口测试.assets/image-20220207163943482.png


二进制
参考/接口测试md/接口测试.assets/image-20220207164150453.png


二进制
参考/接口测试md/接口测试.assets/image-20220207164158117.png


二进制
参考/接口测试md/接口测试.assets/image-20220207164445827.png


二进制
参考/接口测试md/接口测试.assets/image-20220207164636503.png


二进制
参考/接口测试md/接口测试.assets/image-20220207164651547.png


二进制
参考/接口测试md/接口测试.assets/image-20220207165209667.png


二进制
参考/接口测试md/接口测试.assets/image-20220207165314803.png


二进制
参考/接口测试md/接口测试.assets/image-20220207165510867.png


二进制
参考/接口测试md/接口测试.assets/image-20220207165530711.png


二进制
参考/接口测试md/接口测试.assets/image-20220207165753287.png


二进制
参考/接口测试md/接口测试.assets/image-20220207165837625.png


二进制
参考/接口测试md/接口测试.assets/image-20220207165913815.png


二进制
参考/接口测试md/接口测试.assets/image-20220207170139844.png


二进制
参考/接口测试md/接口测试.assets/image-20220207170203829.png


二进制
参考/接口测试md/接口测试.assets/image-20220207170315922.png


二进制
参考/接口测试md/接口测试.assets/image-20220207170318027.png


二进制
参考/接口测试md/接口测试.assets/image-20220207170415247.png


二进制
参考/接口测试md/接口测试.assets/image-20220207170606466.png


二进制
参考/接口测试md/接口测试.assets/image-20220207170756540.png


二进制
参考/接口测试md/接口测试.assets/image-20220207170907495.png


二进制
参考/接口测试md/接口测试.assets/image-20220207170922376.png


二进制
参考/接口测试md/接口测试.assets/image-20220207171144766.png


二进制
参考/接口测试md/接口测试.assets/image-20220207171204233.png


二进制
参考/接口测试md/接口测试.assets/image-20220207171358274.png


二进制
参考/接口测试md/接口测试.assets/image-20220207171409716.png


二进制
参考/接口测试md/接口测试.assets/image-20220207171530951.png


二进制
参考/接口测试md/接口测试.assets/image-20220207171615446.png


二进制
参考/接口测试md/接口测试.assets/modelAdd.jpg


二进制
参考/接口测试md/接口测试.assets/modelAddResult.jpg


二进制
参考/接口测试md/接口测试.assets/modelDelResult.jpg


二进制
参考/接口测试md/接口测试.assets/upload结果.jpg


二进制
参考/接口测试md/接口测试.assets/文件上传.jpg


二进制
参考/接口测试md/接口测试.assets/注册测试成功.jpg


+ 302 - 0
参考/接口测试md/接口测试.md

@@ -0,0 +1,302 @@
+## 1.启动java后端和南大VPN
+
+启动java后端流程见该目录下的“服务器后端启动办法.md”。
+
+不启动南大VPN,无法获得网页内容。
+
+## 2.服务器地址
+
+114.212.245.120
+
+## 3.postman测试接口
+
+根据目录下的“接口.elsx"EXCEL文件,测试接口。
+
+| 编号 | 路由                                                         | 作用                               | 结果                                                |
+| ---- | ------------------------------------------------------------ | ---------------------------------- | --------------------------------------------------- |
+| 1    | http://114.212.245.120/                                      | 获得首页内容                       | 状态码200                                           |
+| 2    | http://114.212.245.120/uerManage/login                       | 用户登录                           | 404 路由错误                                        |
+| 3    | http://114.212.245.120/uerManage/login?username=1&password=1 | 登录接口,加上参数                 | 404 路由错误                                        |
+| 4    | http://114.212.245.120:7788/uerManage/login                  | 用户登录,这个路由**加上了端口号** | 200(**服务器收到了!**) + 40001(服务器返回的码) |
+| 5    | http://114.212.245.120:7788/uerManage/login?username=0&password=0 | 用户登录,加端口、加参数           | 200 + 40001                                         |
+| 6    | http://114.212.245.120:7788/uerManage/register               | 用户注册                           | 200                                                 |
+| 7    | http://114.212.245.120:7788/api/config/add                   | 模型配置模块的添加模型             | 400 + 40000                                         |
+| 8    | http://114.212.245.120:7788/api/config/get/all               | 获取现有的所有机器学习配置模型     | 400 + 40000                                         |
+| 9    | http://114.212.245.120:7788/api/config/get/one/config?configId=0 | 根据id获取某个机器学习模型         | 400 + 40000                                         |
+| 10   | http://114.212.245.120:7788/api/file/upload?userId=0&fileName=hello.csv | 上传文件                           | 400 + 服务器报了一个error,但没崩溃                 |
+| 11   | http://114.212.245.120:7788/api/file/get/all?userId=1        | 获取用户上传的文件                 | 200                                                 |
+| 12   | http://114.212.245.120:7788/api/file/analysis/fields1?filelds=hello | 进行文件数据分布分析               | 200                                                 |
+| 13   | http://114.212.245.120:7788/api/picture/get/all/proj?userId=1 | 获取该用户所有图片列表             | 200                                                 |
+| 14   | http://114.212.245.120:7788/api/picture/update/picinfo?picId=0&picCategory=0&picTag=animal | 更新图片的类别信息和标签信息       | 400                                                 |
+| 15   | http://114.212.245.120:7788/api/model/get/all?userId=1       | 获得用户所有机器学习模型           | 200                                                 |
+| 16   | http://114.212.245.120:7788/api/model/train?modelId=0        | 使用模型进行训练                   | 400                                                 |
+| 17   | http://114.212.245.120:7788/api/model/use/upload             | model测试文件上传                  | **400**+**40000**报错,疑似Spark和Hadoop的问题      |
+| 18   | http://114.212.245.120:7788/api/model/add                    | 添加模型                           | 200                                                 |
+| 19   | http://114.212.245.120:7788/api/model/delete?modelId=6       | 删除模型                           | 200                                                 |
+|      |                                                              |                                    |                                                     |
+
+
+
+### 1	首页	200
+
+![image-20220207152620531](接口测试.assets/image-20220207152620531.png)
+
+
+
+### 2、3	登录(未加端口号)	404 NOT FOUND
+
+2  http://114.212.245.120/uerManage/login:
+
+> <img src="接口测试.assets/image-20220207152908085.png" alt="image-20220207152908085" style="zoom: 50%;" />
+
+
+
+3  http://114.212.245.120/uerManage/login?username=1&password=1:
+
+> ![image-20220207153409659](接口测试.assets/image-20220207153409659.png)
+
+
+
+### 4、5	登录(有端口号) 400
+
+> 第一次尝试:
+>
+> <img src="接口测试.assets/image-20220207162707754.png" alt="image-20220207162707754" style="zoom:50%;" />
+>
+> 第二次尝试:
+>
+> <img src="接口测试.assets/image-20220207163557482.png" alt="image-20220207163557482" style="zoom:50%;" />
+>
+> 服务器运行截图:
+>
+> 因为没有参数,报了个异常。
+>
+> ![image-20220207163711420](接口测试.assets/image-20220207163711420.png)
+
+给路由里加上参数:
+
+> ![image-20220207163917993](接口测试.assets/image-20220207163917993.png)
+>
+> 服务器:异常,没有崩溃。
+>
+> ![image-20220207163943482](接口测试.assets/image-20220207163943482.png)
+>
+> 对应代码:
+>
+> <img src="接口测试.assets/image-20220207164158117.png" alt="image-20220207164158117" style="zoom:50%;" />
+
+
+
+### 6	注册	服务器异常 200
+
+
+
+> 路由:http://114.212.245.120:7788/uerManage/register
+>
+> 500:服务器异常
+>
+> ![image-20220207164445827](接口测试.assets/image-20220207164445827.png)
+>
+> 服务器:
+>
+> ![image-20220207164636503](接口测试.assets/image-20220207164636503.png)
+>
+> 对应代码:
+>
+> 很显然,缺少了try-catch捕获NullPointer等异常,所以出错了。
+>
+> ![image-20220207164651547](接口测试.assets/image-20220207164651547.png)
+
+补充:应该是测试方法问题,似乎并不会出现错误,但是没有try-catch值得注意
+
+下面补充测试结果:
+
+![注册测试成功](E:\大学学习资料\创新创业项目资料\TeamAI-FrontEnd\参考\接口测试md\接口测试.assets\注册测试成功.jpg)
+
+数据库中添加成功,但发现没有自动分配id,所以修改了数据库参数,**将id字段改为int,设置了自动递增**。
+
+但是返回数据不包括id,可以通过调用一次login获取id
+
+### 7	添加模型	Config模块 400
+
+http://114.212.245.120:7788/api/config/add
+
+> ![image-20220207165209667](接口测试.assets/image-20220207165209667.png)
+>
+> 服务器:
+>
+> ![image-20220207165314803](接口测试.assets/image-20220207165314803.png)
+
+
+
+### 8	获取所有config 400
+
+http://114.212.245.120:7788/api/config/get/all
+
+> ![image-20220207165510867](接口测试.assets/image-20220207165510867.png)服务器:
+>
+> ![image-20220207165530711](接口测试.assets/image-20220207165530711.png)
+
+
+
+### 9	获取某个config	400
+
+http://114.212.245.120:7788/api/config/get/one/config?configId=0
+
+> ![image-20220207165753287](接口测试.assets/image-20220207165753287.png)
+>
+> 服务器:
+> ![image-20220207165837625](接口测试.assets/image-20220207165837625.png)
+>
+> 对应代码:
+>
+> ![image-20220207165913815](接口测试.assets/image-20220207165913815.png)
+
+
+
+### 10	上传文件	400
+
+http://114.212.245.120:7788/api/file/upload?userId=0&fileName=hello.csv
+
+> ![image-20220207170139844](接口测试.assets/image-20220207170139844.png)
+>
+> 服务器:
+>
+> ![image-20220207170203829](接口测试.assets/image-20220207170203829.png)
+
+
+
+
+
+### 11	获取用户上传文件	200
+
+http://114.212.245.120:7788/api/file/get/all?userId=1
+
+> ![image-20220207170318027](接口测试.assets/image-20220207170318027.png)
+>
+> 服务器:
+>
+> ![image-20220207170415247](接口测试.assets/image-20220207170415247.png)
+
+
+
+### 12	文件数据分布分析	200
+
+http://114.212.245.120:7788/api/file/analysis/fields1?filelds=hello
+
+> ![image-20220207170606466](接口测试.assets/image-20220207170606466.png)
+>
+> 服务器:
+>
+> 没有反应
+>
+> ![image-20220207170756540](接口测试.assets/image-20220207170756540.png)
+
+
+
+### 13	获取用户所有图片列表	200
+
+http://114.212.245.120:7788/api/picture/get/all/proj?userId=1
+
+> ![image-20220207170907495](接口测试.assets/image-20220207170907495.png)服务器:
+>
+> ![image-20220207170922376](接口测试.assets/image-20220207170922376.png)
+
+
+
+### 14	更新图片信息	200
+
+http://114.212.245.120:7788/api/picture/update/picinfo?picId=0&picCategory=0&picTag=animal
+
+> ![image-20220207171144766](接口测试.assets/image-20220207171144766.png)
+>
+> 服务器:
+>
+> ![image-20220207171204233](接口测试.assets/image-20220207171204233.png)
+
+
+
+
+
+### 15	获得用户的所有机器学习模型	200
+
+http://114.212.245.120:7788/api/model/get/all?userId=1
+
+> ![image-20220207171358274](接口测试.assets/image-20220207171358274.png)
+>
+> 服务器:
+>
+> ![image-20220207171409716](接口测试.assets/image-20220207171409716.png)
+
+
+
+### 16	使用模型进行训练	400
+
+路由:http://114.212.245.120:7788/api/model/train?modelId=0
+
+> ![image-20220207171530951](接口测试.assets/image-20220207171530951.png)
+>
+> 服务器:
+>
+> ![image-20220207171615446](接口测试.assets/image-20220207171615446.png)
+
+### 17 测试文件上传 400
+
+http://114.212.245.120:7788/api/model/use/upload
+
+补充:按照现有的参数,上传的测试文件位于项目当前文件夹,不能重名。测试过程中可以上传到服务器,但是会报错
+
+![文件上传](E:\大学学习资料\创新创业项目资料\TeamAI-FrontEnd\参考\接口测试md\接口测试.assets\文件上传.jpg)
+
+结果:
+
+![upload结果](E:\大学学习资料\创新创业项目资料\TeamAI-FrontEnd\参考\接口测试md\接口测试.assets\upload结果.jpg)
+
+服务器:
+
+```
+22/02/08 19:51:59 INFO FileService: file uploading: filename = test, userId = 1
+22/02/08 19:51:59 INFO FileService: server file location: /home/seecoder/ai_environment_jars/test.csv
+22/02/08 19:51:59 INFO SasAdapter: /home/seecoder/ai_environment_jars/test.csv already exist.
+
+java.net.ConnectException: Call From seecoder-System-Product-Name/127.0.1.1 to 114.212.245.120:9000 failed on connection exception: java.net.ConnectException: Connection refused; For more details see:  http://wiki.apache.org/hadoop/ConnectionRefused
+
+at com.example.dao.HdfsDao.putFile(HdfsDao.java:59)
+	at com.example.data.CsvAdapter.Csv2Parquet(CsvAdapter.scala:60)
+	at com.example.data.SasAdapter.Sas2Parquet(SasAdapter.java:36)
+	at com.example.data.SasLoader.loadSas(SasLoader.java:25)
+	at com.example.services.FileService.uploadFile(FileService.java:75)
+	at com.example.services.FileService.uploadTestFile(FileService.java:88)
+	at com.example.controller.ModelController.uploadTestFile(ModelController.java:163)
+	
+22/02/08 19:51:59 INFO CsvAdapter: Initial spark config done.
+java.lang.IllegalArgumentException: Can not create a Path from a null string
+
+at com.example.data.CsvAdapter.Csv2Parquet(CsvAdapter.scala:67)
+	at com.example.data.SasAdapter.Sas2Parquet(SasAdapter.java:36)
+	at com.example.data.SasLoader.loadSas(SasLoader.java:25)
+	at com.example.services.FileService.uploadFile(FileService.java:75)
+	at com.example.services.FileService.uploadTestFile(FileService.java:88)
+	at com.example.controller.ModelController.uploadTestFile(ModelController.java:163)
+
+```
+
+### 18 模型添加 200
+
+http://114.212.245.120:7788/api/model/add
+
+补充:该接口的输入参数id不是必须参数,因为数据库中是自动递增分配id,分配id会作为结果返回
+
+**所以之前的测试不能使用id=0作参数,大概率会有nullpointer**
+
+![modelAdd](E:\大学学习资料\创新创业项目资料\TeamAI-FrontEnd\参考\接口测试md\接口测试.assets\modelAdd.jpg)
+
+结果
+
+![modelAddResult](E:\大学学习资料\创新创业项目资料\TeamAI-FrontEnd\参考\接口测试md\接口测试.assets\modelAddResult.jpg)
+
+### 19 删除模型 200
+
+http://114.212.245.120:7788/api/model/delete?modelId=6
+
+![modelDelResult](E:\大学学习资料\创新创业项目资料\TeamAI-FrontEnd\参考\接口测试md\接口测试.assets\modelDelResult.jpg)

二进制
参考/服务器后端启动办法.pdf


二进制
参考/服务器后端启动办法md/服务器后端启动办法.assets/image-20220207151426948.png


二进制
参考/服务器后端启动办法md/服务器后端启动办法.assets/image-20220207151443142.png


二进制
参考/服务器后端启动办法md/服务器后端启动办法.assets/image-20220207151613175.png


二进制
参考/服务器后端启动办法md/服务器后端启动办法.assets/image-20220207151710148.png


部分文件因为文件数量过多而无法显示