DingXiaoYu há 3 anos atrás
commit
4e93246bc1
100 ficheiros alterados com 11575 adições e 0 exclusões
  1. 23 0
      .gitignore
  2. 21 0
      LICENSE
  3. 22 0
      index.html
  4. 1657 0
      package-lock.json
  5. 33 0
      package.json
  6. 12 0
      public/detailConfig.json
  7. 16 0
      public/simpleConfig.json
  8. 41 0
      public/table.json
  9. BIN
      screenshots/wms1.png
  10. BIN
      screenshots/wms3.png
  11. 12 0
      src/App.vue
  12. 11 0
      src/api/_prefix.js
  13. 54 0
      src/api/comment.js
  14. 392 0
      src/api/config.js
  15. 305 0
      src/api/file.js
  16. 18 0
      src/api/index.js
  17. 57 0
      src/api/mail.js
  18. 115 0
      src/api/model.js
  19. 32 0
      src/api/pic.js
  20. 184 0
      src/api/posts.js
  21. 28 0
      src/assets/css/color-dark.css
  22. 4 0
      src/assets/css/icon.css
  23. 177 0
      src/assets/css/main.css
  24. BIN
      src/assets/img/earth.jpg
  25. BIN
      src/assets/img/img.jpg
  26. BIN
      src/assets/img/login-bg.jpg
  27. 73 0
      src/components/Comments.vue
  28. 171 0
      src/components/Header.vue
  29. 201 0
      src/components/Sidebar.vue
  30. 178 0
      src/components/SquareHeader.vue
  31. 183 0
      src/components/Tags.vue
  32. 49 0
      src/components/WriteComment.vue
  33. 12 0
      src/main.js
  34. 17 0
      src/plugins/element.js
  35. 56 0
      src/store/index.js
  36. 24 0
      src/utils/i18n.js
  37. 34 0
      src/utils/request.js
  38. 465 0
      src/views/ConfigDetail.vue
  39. 173 0
      src/views/ConfigForm.vue
  40. 358 0
      src/views/ConfigList.vue
  41. 390 0
      src/views/ModelList.vue
  42. 188 0
      src/views/changeConfig.vue
  43. 190 0
      src/views/file/FileAnalysis.vue
  44. 458 0
      src/views/file/FileDetail.vue
  45. 205 0
      src/views/file/FileList.vue
  46. 249 0
      src/views/file/Upload.vue
  47. 489 0
      src/views/square.vue
  48. 62 0
      src/views/unused/403.vue
  49. 62 0
      src/views/unused/404.vue
  50. 138 0
      src/views/unused/BaseCharts.vue
  51. 174 0
      src/views/unused/BaseForm.vue
  52. 196 0
      src/views/unused/DLForm.vue
  53. 139 0
      src/views/unused/Dllearning.vue
  54. 26 0
      src/views/unused/Donate.vue
  55. 58 0
      src/views/unused/Editor.vue
  56. 44 0
      src/views/unused/Home.vue
  57. 40 0
      src/views/unused/I18n.vue
  58. 229 0
      src/views/unused/Icon.vue
  59. 125 0
      src/views/unused/Login.vue
  60. 339 0
      src/views/unused/ModelDetail.vue
  61. 40 0
      src/views/unused/Permission.vue
  62. 163 0
      src/views/unused/Upload.vue
  63. 247 0
      src/views/unused/router/index.js
  64. 215 0
      src/views/user/Message.vue
  65. 192 0
      src/views/user/User.vue
  66. 26 0
      vite.config.js
  67. 50 0
      前端页面说明.md
  68. 1101 0
      参考/Java接口文档.md
  69. 246 0
      参考/Python接口文档.md
  70. BIN
      参考/web前端结构.docx
  71. 49 0
      参考/会议记录/1月28日-2月4日.md
  72. 237 0
      参考/前后端逻辑整理.md
  73. BIN
      参考/接口.xlsx
  74. BIN
      参考/接口测试.pdf
  75. BIN
      参考/接口测试md/接口测试.assets/image-20220207152620531.png
  76. BIN
      参考/接口测试md/接口测试.assets/image-20220207152908085.png
  77. BIN
      参考/接口测试md/接口测试.assets/image-20220207153409659.png
  78. BIN
      参考/接口测试md/接口测试.assets/image-20220207162707754.png
  79. BIN
      参考/接口测试md/接口测试.assets/image-20220207163557482.png
  80. BIN
      参考/接口测试md/接口测试.assets/image-20220207163711420.png
  81. BIN
      参考/接口测试md/接口测试.assets/image-20220207163917993.png
  82. BIN
      参考/接口测试md/接口测试.assets/image-20220207163943482.png
  83. BIN
      参考/接口测试md/接口测试.assets/image-20220207164150453.png
  84. BIN
      参考/接口测试md/接口测试.assets/image-20220207164158117.png
  85. BIN
      参考/接口测试md/接口测试.assets/image-20220207164445827.png
  86. BIN
      参考/接口测试md/接口测试.assets/image-20220207164636503.png
  87. BIN
      参考/接口测试md/接口测试.assets/image-20220207164651547.png
  88. BIN
      参考/接口测试md/接口测试.assets/image-20220207165209667.png
  89. BIN
      参考/接口测试md/接口测试.assets/image-20220207165314803.png
  90. BIN
      参考/接口测试md/接口测试.assets/image-20220207165510867.png
  91. BIN
      参考/接口测试md/接口测试.assets/image-20220207165530711.png
  92. BIN
      参考/接口测试md/接口测试.assets/image-20220207165753287.png
  93. BIN
      参考/接口测试md/接口测试.assets/image-20220207165837625.png
  94. BIN
      参考/接口测试md/接口测试.assets/image-20220207165913815.png
  95. BIN
      参考/接口测试md/接口测试.assets/image-20220207170139844.png
  96. BIN
      参考/接口测试md/接口测试.assets/image-20220207170203829.png
  97. BIN
      参考/接口测试md/接口测试.assets/image-20220207170315922.png
  98. BIN
      参考/接口测试md/接口测试.assets/image-20220207170318027.png
  99. BIN
      参考/接口测试md/接口测试.assets/image-20220207170415247.png
  100. BIN
      参考/接口测试md/接口测试.assets/image-20220207170606466.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>

+ 1657 - 0
package-lock.json

@@ -0,0 +1,1657 @@
+{
+  "name": "vue-manage-system",
+  "version": "5.1.0",
+  "lockfileVersion": 2,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "vue-manage-system",
+      "version": "5.1.0",
+      "dependencies": {
+        "@vitejs/plugin-vue": "^1.10.2",
+        "axios": "^0.21.1",
+        "echarts": "^5.3.2",
+        "echarts-gl": "^2.0.9",
+        "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": {
+        "@vue/compiler-sfc": "^3.1.2",
+        "vite": "2.3.7"
+      }
+    },
+    "node_modules/@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==",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.14.7",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.7.tgz",
+      "integrity": "sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==",
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/runtime": {
+      "version": "7.14.6",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.6.tgz",
+      "integrity": "sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==",
+      "dependencies": {
+        "regenerator-runtime": "^0.13.4"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@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==",
+      "dependencies": {
+        "core-js-pure": "^3.15.0",
+        "regenerator-runtime": "^0.13.4"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/types": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz",
+      "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==",
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.14.5",
+        "to-fast-properties": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@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==",
+      "dependencies": {
+        "@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"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@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==",
+      "dependencies": {
+        "@intlify/shared": "9.1.6"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@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==",
+      "dependencies": {
+        "@intlify/message-resolver": "9.1.6",
+        "@intlify/shared": "9.1.6",
+        "source-map": "0.6.1"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@intlify/message-resolver": {
+      "version": "9.1.6",
+      "resolved": "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.6.tgz",
+      "integrity": "sha512-UUnbawQa5U9sffd5wRIscqtyY1xWlwJbyfwCLPEWLvBhyAnCwPYlvaHGnnO0CSi0fzJTVwlV9DYzobh3agDeMA==",
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@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==",
+      "dependencies": {
+        "@intlify/message-compiler": "9.1.6",
+        "@intlify/message-resolver": "9.1.6",
+        "@intlify/shared": "9.1.6"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@intlify/shared": {
+      "version": "9.1.6",
+      "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.6.tgz",
+      "integrity": "sha512-6MtsKulyfZxdD7OuxjaODjj8QWoHCnLFAk4wkWiHqBCa6UCTC0qXjtEeZ1MxpQihvFmmJZauBUu25EvtngW5qQ==",
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@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==",
+      "dependencies": {
+        "@intlify/message-resolver": "9.1.6",
+        "@intlify/runtime": "9.1.6",
+        "@intlify/shared": "9.1.6"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@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=="
+    },
+    "node_modules/@types/estree": {
+      "version": "0.0.48",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz",
+      "integrity": "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew==",
+      "dev": true
+    },
+    "node_modules/@types/lodash": {
+      "version": "4.14.170",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.170.tgz",
+      "integrity": "sha512-bpcvu/MKHHeYX+qeEN8GE7DIravODWdACVA1ctevD8CN24RhPZIKMn9ntfAsrvLfSX3cR5RrBKAbYm9bGs0A+Q=="
+    },
+    "node_modules/@vitejs/plugin-vue": {
+      "version": "1.10.2",
+      "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-1.10.2.tgz",
+      "integrity": "sha512-/QJ0Z9qfhAFtKRY+r57ziY4BSbGUTGsPRMpB/Ron3QPwBZM4OZAZHdTa4a8PafCwU5DTatXG8TMDoP8z+oDqJw==",
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "peerDependencies": {
+        "vite": "^2.5.10"
+      }
+    },
+    "node_modules/@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==",
+      "dependencies": {
+        "@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"
+      }
+    },
+    "node_modules/@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==",
+      "dependencies": {
+        "@vue/compiler-core": "3.1.2",
+        "@vue/shared": "3.1.2"
+      }
+    },
+    "node_modules/@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,
+      "dependencies": {
+        "@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"
+      },
+      "peerDependencies": {
+        "vue": "3.1.2"
+      }
+    },
+    "node_modules/@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,
+      "dependencies": {
+        "@vue/compiler-dom": "3.1.2",
+        "@vue/shared": "3.1.2"
+      }
+    },
+    "node_modules/@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=="
+    },
+    "node_modules/@vue/reactivity": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.2.tgz",
+      "integrity": "sha512-glJzJoN2xE7I2lRvwKM5u1BHRPTd1yc8iaf//Lai/78/uYAvE5DXp5HzWRFOwMlbRvMGJHIQjOqoxj87cDAaag==",
+      "dependencies": {
+        "@vue/shared": "3.1.2"
+      }
+    },
+    "node_modules/@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==",
+      "dependencies": {
+        "@vue/reactivity": "3.1.2",
+        "@vue/shared": "3.1.2"
+      }
+    },
+    "node_modules/@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==",
+      "dependencies": {
+        "@vue/runtime-core": "3.1.2",
+        "@vue/shared": "3.1.2",
+        "csstype": "^2.6.8"
+      }
+    },
+    "node_modules/@vue/shared": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.2.tgz",
+      "integrity": "sha512-EmH/poaDWBPJaPILXNI/1fvUbArJQmmTyVCwvvyDYDFnkPoTclAbHRAtyIvqfez7jybTDn077HTNILpxlsoWhg=="
+    },
+    "node_modules/async-validator": {
+      "version": "3.5.2",
+      "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-3.5.2.tgz",
+      "integrity": "sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ=="
+    },
+    "node_modules/axios": {
+      "version": "0.21.1",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
+      "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
+      "dependencies": {
+        "follow-redirects": "^1.10.0"
+      }
+    },
+    "node_modules/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,
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/bluebird": {
+      "version": "3.7.2",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+      "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+      "dev": true
+    },
+    "node_modules/claygl": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmmirror.com/claygl/-/claygl-1.3.0.tgz",
+      "integrity": "sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ=="
+    },
+    "node_modules/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
+    },
+    "node_modules/consolidate": {
+      "version": "0.16.0",
+      "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.16.0.tgz",
+      "integrity": "sha512-Nhl1wzCslqXYTJVDyJCu3ODohy9OfBMB5uD2BiBTzd7w+QY0lBzafkR8y8755yMYHAaMD4NuzbAw03/xzfw+eQ==",
+      "dev": true,
+      "dependencies": {
+        "bluebird": "^3.7.2"
+      },
+      "engines": {
+        "node": ">= 0.10.0"
+      }
+    },
+    "node_modules/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=="
+    },
+    "node_modules/cropperjs": {
+      "version": "1.5.12",
+      "resolved": "https://registry.npmjs.org/cropperjs/-/cropperjs-1.5.12.tgz",
+      "integrity": "sha512-re7UdjE5UnwdrovyhNzZ6gathI4Rs3KGCBSc8HCIjUo5hO42CtzyblmWLj6QWVw7huHyDMfpKxhiO2II77nhDw=="
+    },
+    "node_modules/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,
+      "bin": {
+        "cssesc": "bin/cssesc"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/csstype": {
+      "version": "2.6.17",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.17.tgz",
+      "integrity": "sha512-u1wmTI1jJGzCJzWndZo8mk4wnPTZd1eOIYTYvuEyOQGfmDl3TrabCCfKnOC86FZwW/9djqTl933UF/cS425i9A=="
+    },
+    "node_modules/dayjs": {
+      "version": "1.10.5",
+      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.5.tgz",
+      "integrity": "sha512-BUFis41ikLz+65iH6LHQCDm4YPMj5r1YFLdupPIyM4SGcXMmtiLQ7U37i+hGS8urIuqe7I/ou3IS1jVc4nbN4g=="
+    },
+    "node_modules/echarts": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.3.2.tgz",
+      "integrity": "sha512-LWCt7ohOKdJqyiBJ0OGBmE9szLdfA9sGcsMEi+GGoc6+Xo75C+BkcT/6NNGRHAWtnQl2fNow05AQjznpap28TQ==",
+      "dependencies": {
+        "tslib": "2.3.0",
+        "zrender": "5.3.1"
+      }
+    },
+    "node_modules/echarts-gl": {
+      "version": "2.0.9",
+      "resolved": "https://registry.npmmirror.com/echarts-gl/-/echarts-gl-2.0.9.tgz",
+      "integrity": "sha512-oKeMdkkkpJGWOzjgZUsF41DOh6cMsyrGGXimbjK2l6Xeq/dBQu4ShG2w2Dzrs/1bD27b2pLTGSaUzouY191gzA==",
+      "dependencies": {
+        "claygl": "^1.2.1",
+        "zrender": "^5.1.1"
+      },
+      "peerDependencies": {
+        "echarts": "^5.1.2"
+      }
+    },
+    "node_modules/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==",
+      "workspaces": [
+        "packages/*"
+      ],
+      "dependencies": {
+        "@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"
+      },
+      "peerDependencies": {
+        "vue": "3.1.1"
+      }
+    },
+    "node_modules/emojis-list": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
+      "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/esbuild": {
+      "version": "0.12.9",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.9.tgz",
+      "integrity": "sha512-MWRhAbMOJ9RJygCrt778rz/qNYgA4ZVj6aXnNPxFjs7PmIpb0fuB9Gmg5uWrr6n++XKwwm/RmSz6RR5JL2Ocsw==",
+      "dev": true,
+      "bin": {
+        "esbuild": "bin/esbuild"
+      }
+    },
+    "node_modules/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=="
+    },
+    "node_modules/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==",
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/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,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+      "dev": true
+    },
+    "node_modules/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,
+      "dependencies": {
+        "loader-utils": "^1.1.0"
+      }
+    },
+    "node_modules/has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "dev": true,
+      "dependencies": {
+        "function-bind": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/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
+    },
+    "node_modules/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
+    },
+    "node_modules/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,
+      "engines": {
+        "node": "^10 || ^12 || >= 14"
+      },
+      "peerDependencies": {
+        "postcss": "^8.1.0"
+      }
+    },
+    "node_modules/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,
+      "dependencies": {
+        "has": "^1.0.3"
+      }
+    },
+    "node_modules/json5": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+      "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+      "dev": true,
+      "dependencies": {
+        "minimist": "^1.2.0"
+      },
+      "bin": {
+        "json5": "lib/cli.js"
+      }
+    },
+    "node_modules/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,
+      "dependencies": {
+        "big.js": "^5.2.2",
+        "emojis-list": "^3.0.0",
+        "json5": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=4.0.0"
+      }
+    },
+    "node_modules/lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+    },
+    "node_modules/lodash.camelcase": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+      "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=",
+      "dev": true
+    },
+    "node_modules/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,
+      "dependencies": {
+        "yallist": "^3.0.2"
+      }
+    },
+    "node_modules/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,
+      "dependencies": {
+        "sourcemap-codec": "^1.4.4"
+      }
+    },
+    "node_modules/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,
+      "dependencies": {
+        "source-map": "^0.6.1"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+      "dev": true
+    },
+    "node_modules/mitt": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/mitt/-/mitt-2.1.0.tgz",
+      "integrity": "sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg=="
+    },
+    "node_modules/nanoid": {
+      "version": "3.1.23",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
+      "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==",
+      "dev": true,
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/normalize-wheel": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz",
+      "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU="
+    },
+    "node_modules/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
+    },
+    "node_modules/postcss": {
+      "version": "8.3.5",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.5.tgz",
+      "integrity": "sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA==",
+      "dev": true,
+      "dependencies": {
+        "colorette": "^1.2.2",
+        "nanoid": "^3.1.23",
+        "source-map-js": "^0.6.2"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/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,
+      "dependencies": {
+        "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"
+      },
+      "peerDependencies": {
+        "postcss": "^8.0.0"
+      }
+    },
+    "node_modules/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,
+      "engines": {
+        "node": "^10 || ^12 || >= 14"
+      },
+      "peerDependencies": {
+        "postcss": "^8.1.0"
+      }
+    },
+    "node_modules/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,
+      "dependencies": {
+        "icss-utils": "^5.0.0",
+        "postcss-selector-parser": "^6.0.2",
+        "postcss-value-parser": "^4.1.0"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >= 14"
+      },
+      "peerDependencies": {
+        "postcss": "^8.1.0"
+      }
+    },
+    "node_modules/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,
+      "dependencies": {
+        "postcss-selector-parser": "^6.0.4"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >= 14"
+      },
+      "peerDependencies": {
+        "postcss": "^8.1.0"
+      }
+    },
+    "node_modules/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,
+      "dependencies": {
+        "icss-utils": "^5.0.0"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >= 14"
+      },
+      "peerDependencies": {
+        "postcss": "^8.1.0"
+      }
+    },
+    "node_modules/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,
+      "dependencies": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/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
+    },
+    "node_modules/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=="
+    },
+    "node_modules/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=="
+    },
+    "node_modules/resolve": {
+      "version": "1.20.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
+      "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
+      "dev": true,
+      "dependencies": {
+        "is-core-module": "^2.2.0",
+        "path-parse": "^1.0.6"
+      }
+    },
+    "node_modules/rollup": {
+      "version": "2.52.3",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.52.3.tgz",
+      "integrity": "sha512-QF3Sju8Kl2z0osI4unyOLyUudyhOMK6G0AeqJWgfiyigqLAlnNrfBcDWDx+f1cqn+JU2iIYVkDrgQ6/KtwEfrg==",
+      "dev": true,
+      "bin": {
+        "rollup": "dist/bin/rollup"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/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=="
+    },
+    "node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/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,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/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
+    },
+    "node_modules/string-hash": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz",
+      "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=",
+      "dev": true
+    },
+    "node_modules/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=",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
+      "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+      "dev": true
+    },
+    "node_modules/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,
+      "dependencies": {
+        "esbuild": "^0.12.5",
+        "postcss": "^8.3.0",
+        "resolve": "^1.19.0",
+        "rollup": "^2.38.5"
+      },
+      "bin": {
+        "vite": "bin/vite.js"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.1"
+      }
+    },
+    "node_modules/vue": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/vue/-/vue-3.1.2.tgz",
+      "integrity": "sha512-q/rbKpb7aofax4ugqu2k/uj7BYuNPcd6Z5/qJtfkJQsE0NkwVoCyeSh7IZGH61hChwYn3CEkh4bHolvUPxlQ+w==",
+      "dependencies": {
+        "@vue/compiler-dom": "3.1.2",
+        "@vue/runtime-dom": "3.1.2",
+        "@vue/shared": "3.1.2"
+      }
+    },
+    "node_modules/vue-cropperjs": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/vue-cropperjs/-/vue-cropperjs-5.0.0.tgz",
+      "integrity": "sha512-RhnC8O33uRZNkn74aiHZwNHnBJOXWlS4P6gsRI0lw4cZlWjKSCywZI9oSI9POlIPI6OYv30jvnHMXGch85tw7w==",
+      "dependencies": {
+        "cropperjs": "^1.5.6"
+      },
+      "peerDependencies": {
+        "vue": ">=3.0.0"
+      }
+    },
+    "node_modules/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==",
+      "dependencies": {
+        "@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"
+      },
+      "engines": {
+        "node": ">= 10"
+      },
+      "peerDependencies": {
+        "vue": "^3.0.0"
+      }
+    },
+    "node_modules/vue-router": {
+      "version": "4.0.10",
+      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.10.tgz",
+      "integrity": "sha512-YbPf6QnZpyyWfnk7CUt2Bme+vo7TLfg1nGZNkvYqKYh4vLaFw6Gn8bPGdmt5m4qrGnKoXLqc4htAsd3dIukICA==",
+      "dependencies": {
+        "@vue/devtools-api": "^6.0.0-beta.14"
+      },
+      "peerDependencies": {
+        "vue": "^3.0.0"
+      }
+    },
+    "node_modules/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==",
+      "dependencies": {
+        "schart.js": "^3.0.0"
+      }
+    },
+    "node_modules/vuex": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz",
+      "integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==",
+      "dependencies": {
+        "@vue/devtools-api": "^6.0.0-beta.11"
+      },
+      "peerDependencies": {
+        "vue": "^3.0.2"
+      }
+    },
+    "node_modules/wangeditor": {
+      "version": "4.7.4",
+      "resolved": "https://registry.npmjs.org/wangeditor/-/wangeditor-4.7.4.tgz",
+      "integrity": "sha512-MVWJyFZm3SOhIGFsxDwD6Q0ahIWQTYU0/otHxq85EnfdxtJBJ8c55iKDp3zIvBZaiBawBiYCpRmbn8HOedNj5w==",
+      "dependencies": {
+        "@babel/runtime": "^7.11.2",
+        "@babel/runtime-corejs3": "^7.11.2",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/yallist": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+      "dev": true
+    },
+    "node_modules/zrender": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.3.1.tgz",
+      "integrity": "sha512-7olqIjy0gWfznKr6vgfnGBk7y4UtdMvdwFmK92vVQsQeDPyzkHW1OlrLEKg6GHz1W5ePf0FeN1q2vkl/HFqhXw==",
+      "dependencies": {
+        "tslib": "2.3.0"
+      }
+    }
+  },
+  "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.10.2",
+      "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-1.10.2.tgz",
+      "integrity": "sha512-/QJ0Z9qfhAFtKRY+r57ziY4BSbGUTGsPRMpB/Ron3QPwBZM4OZAZHdTa4a8PafCwU5DTatXG8TMDoP8z+oDqJw=="
+    },
+    "@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
+    },
+    "claygl": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmmirror.com/claygl/-/claygl-1.3.0.tgz",
+      "integrity": "sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ=="
+    },
+    "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=="
+    },
+    "echarts": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.3.2.tgz",
+      "integrity": "sha512-LWCt7ohOKdJqyiBJ0OGBmE9szLdfA9sGcsMEi+GGoc6+Xo75C+BkcT/6NNGRHAWtnQl2fNow05AQjznpap28TQ==",
+      "requires": {
+        "tslib": "2.3.0",
+        "zrender": "5.3.1"
+      }
+    },
+    "echarts-gl": {
+      "version": "2.0.9",
+      "resolved": "https://registry.npmmirror.com/echarts-gl/-/echarts-gl-2.0.9.tgz",
+      "integrity": "sha512-oKeMdkkkpJGWOzjgZUsF41DOh6cMsyrGGXimbjK2l6Xeq/dBQu4ShG2w2Dzrs/1bD27b2pLTGSaUzouY191gzA==",
+      "requires": {
+        "claygl": "^1.2.1",
+        "zrender": "^5.1.1"
+      }
+    },
+    "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
+    },
+    "zrender": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.3.1.tgz",
+      "integrity": "sha512-7olqIjy0gWfznKr6vgfnGBk7y4UtdMvdwFmK92vVQsQeDPyzkHW1OlrLEKg6GHz1W5ePf0FeN1q2vkl/HFqhXw==",
+      "requires": {
+        "tslib": "2.3.0"
+      }
+    }
+  }
+}

+ 33 - 0
package.json

@@ -0,0 +1,33 @@
+{
+  "name": "vue-manage-system",
+  "version": "5.1.0",
+  "private": true,
+  "scripts": {
+    "dev": "vite",
+    "build": "vite build",
+    "serve": "vite preview"
+  },
+  "dependencies": {
+    "@vitejs/plugin-vue": "^1.10.2",
+    "axios": "^0.21.1",
+    "echarts": "^5.3.2",
+    "echarts-gl": "^2.0.9",
+    "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": {
+    "@vue/compiler-sfc": "^3.1.2",
+    "vite": "2.3.7"
+  },
+  "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
+    
+}

BIN
screenshots/wms1.png


BIN
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>

+ 11 - 0
src/api/_prefix.js

@@ -0,0 +1,11 @@
+export const API_MODULE = '/api'
+export const NEW_API_MODULE= '/newapi'
+export const MODEL_MODULE=`${API_MODULE}/model`
+export const CONFIG_MODULE = `${API_MODULE}/config`
+export const FILE_MODULE= `${API_MODULE}/file`
+export const PIC_MODULE= `${API_MODULE}/picture`
+export const POST_MODULE=`${NEW_API_MODULE}/posts`
+export const COMMENT_MODULE=`${NEW_API_MODULE}/comment`
+export const MAIL_MODULE=`${NEW_API_MODULE}/mail`
+
+

+ 54 - 0
src/api/comment.js

@@ -0,0 +1,54 @@
+import {COMMENT_MODULE} from "./_prefix";
+
+export const submitComment = payload => {
+    console.log(payload);
+    //id,
+    const {userId, postId, content} = payload;
+
+    // return axios.post(`${COMMENT_MODULE}/create`, {
+    //     userId, postId, content
+    // }).then(res => {
+    //     return res.data;
+    // });
+    return Promise.resolve({
+        "success": true,
+        "message": "success",
+        "object": {}
+    })
+}
+export const getComment = payload => {
+    // console.log("getAllConfig",payload);
+    const {userId} = payload;
+    // return axios.get(`${COMMENT_MODULE}/getComment/{userId}`).then(res => {
+    //     return res.data;
+    // });
+    return Promise.resolve({
+        "success":true,
+        "message":"success",
+        "object": [
+            {
+                "commentId":1,
+                "postId":1,
+                "userId":1,
+                "content":"决策树参数调整至0.8效果获取会更好",
+                "time":"2022.3.15"
+            },
+            {
+                "commentId":1,
+                "postId":1,
+                "userId":1,
+                "content":"试了贴主的配置效果确实不错,点赞!",
+                "time":"2022.3.15"
+            },
+            {
+                "commentId":1,
+                "postId":1,
+                "userId":1,
+                "content":"贴主可以试试把训练测试比调整至0.66",
+                "time":"2022.3.15"
+            }
+        ]
+
+
+    })
+}

+ 392 - 0
src/api/config.js

@@ -0,0 +1,392 @@
+import request from '../utils/request';
+import axios from 'axios';
+import {CONFIG_MODULE} from "./_prefix";
+
+/**
+ *  添加模型配置信息 POST /add
+ * @param {*} payload
+ * @returns
+ */
+export const addConfig = payload => {
+  console.log(payload);
+  //id,
+  const { fileInfoId,userId, modelTypeId,confName , fieldIds} = payload;
+
+  return axios.post(`${CONFIG_MODULE}/add`, {
+    fileInfoId, userId,modelTypeId,confName ,fieldIds
+  }).then(res => {
+    return res.data;
+  });
+}
+
+
+
+/**
+ * 获取所有模型配置 GET /get/all/{userId} 传入用户id
+ * @param {*} payload
+ * @returns
+ */
+export const getAllConfig = payload => {
+  // console.log("getAllConfig",payload);
+  const {uid} = payload;
+  console.log("payload",payload);
+  console.log("uid",uid);
+  // return axios.get(`${CONFIG_MODULE}/get/all?userId=${uid}`).then(res => {
+  //
+  //   return res.data;
+  // });
+  return Promise.resolve({
+    "timestamp": 1649419361037,
+    "status": 200,
+    "data": [
+      {
+        "fileId": "1",
+        "fileName": "event_data",
+        "configId": "1",
+        "modelTypeId": "2",
+        "modelTypeName": "决策树",
+        "confName": "config1",
+        "featureList": [
+          {
+            "id": 105,
+            "fileInfoId": 1,
+            "fieldName": "road",
+            "aliasName": "",
+            "fieldDes": "",
+            "nullsRatio": 0.0,
+            "conOrDis": 0,
+            "fieldType": "string",
+            "valueInfo": "[\"R\",\"L\"]"
+          },
+          {
+            "id": 106,
+            "fileInfoId": 1,
+            "fieldName": "lane",
+            "aliasName": "",
+            "fieldDes": "",
+            "nullsRatio": 0.0,
+            "conOrDis": 0,
+            "fieldType": "string",
+            "valueInfo": "[\"r\",\"m\",\"l\"]"
+          },
+          {
+            "id": 107,
+            "fileInfoId": 1,
+            "fieldName": "vehicle_class",
+            "aliasName": "",
+            "fieldDes": "",
+            "nullsRatio": 0.0,
+            "conOrDis": 0,
+            "fieldType": "string",
+            "valueInfo": "[\"car\",\"truck\",\"bus\"]"
+          },
+          {
+            "id": 110,
+            "fileInfoId": 1,
+            "fieldName": "duration",
+            "aliasName": "",
+            "fieldDes": "",
+            "nullsRatio": 0.0,
+            "conOrDis": 0,
+            "fieldType": "string",
+            "valueInfo": "[\"48,60\",\"24,36\",\"36,48\",\"12,24\",\"0,12\"]"
+          },
+          {
+            "id": 109,
+            "fileInfoId": 1,
+            "fieldName": "event_type",
+            "aliasName": "",
+            "fieldDes": "",
+            "nullsRatio": 0.0,
+            "conOrDis": 0,
+            "fieldType": "string",
+            "valueInfo": "[\"cruise\",\"overdrive\"]"
+          }
+        ]
+      },
+      {
+        "fileId": "1",
+        "fileName": "event_data",
+        "configId": "3",
+        "modelTypeId": "9",
+        "modelTypeName": "K-均值",
+        "confName": "Kmeans-Test",
+        "featureList": [
+          {
+            "id": 105,
+            "fileInfoId": 1,
+            "fieldName": "road",
+            "aliasName": "",
+            "fieldDes": "",
+            "nullsRatio": 0.0,
+            "conOrDis": 0,
+            "fieldType": "string",
+            "valueInfo": "[\"R\",\"L\"]"
+          },
+          {
+            "id": 106,
+            "fileInfoId": 1,
+            "fieldName": "lane",
+            "aliasName": "",
+            "fieldDes": "",
+            "nullsRatio": 0.0,
+            "conOrDis": 0,
+            "fieldType": "string",
+            "valueInfo": "[\"r\",\"m\",\"l\"]"
+          },
+          {
+            "id": 107,
+            "fileInfoId": 1,
+            "fieldName": "vehicle_class",
+            "aliasName": "",
+            "fieldDes": "",
+            "nullsRatio": 0.0,
+            "conOrDis": 0,
+            "fieldType": "string",
+            "valueInfo": "[\"car\",\"truck\",\"bus\"]"
+          },
+          {
+            "id": 110,
+            "fileInfoId": 1,
+            "fieldName": "duration",
+            "aliasName": "",
+            "fieldDes": "",
+            "nullsRatio": 0.0,
+            "conOrDis": 0,
+            "fieldType": "string",
+            "valueInfo": "[\"48,60\",\"24,36\",\"36,48\",\"12,24\",\"0,12\"]"
+          },
+          {
+            "id": 109,
+            "fileInfoId": 1,
+            "fieldName": "event_type",
+            "aliasName": "",
+            "fieldDes": "",
+            "nullsRatio": 0.0,
+            "conOrDis": 0,
+            "fieldType": "string",
+            "valueInfo": "[\"cruise\",\"overdrive\"]"
+          }
+        ]
+      }
+    ]
+  })
+}
+
+//   console.log("uid",uid);
+//   return[
+//     {
+//       "id": 1,
+//       "configName": "gg",
+//       "modelType": "gg",
+//       "feature": "gg",
+//       "time": 1}];
+//
+//     },{
+//       "id": 1,
+//       "configName": "gg",
+//       "modelType": "gg",
+//       "feature": "gg",
+//       "time": 1
+//
+//     },
+//     {
+//       "id": 1,
+//       "configName": "gg",
+//       "modelType": "gg",
+//       "feature": "gg",
+//       "time": 1
+//
+//     }];
+//
+//
+// }
+
+// let mock=(userId)=>{
+//   // console.log("mock");
+//   if(userId===1){
+//     return [
+//     {
+//       "id": 1,
+//         "configName": "gg",
+//         "modelType": "gg",
+//         "feature": "gg",
+//         "time": 1
+//
+//     },{
+//       "id": 1,
+//         "configName": "gg",
+//         "modelType": "gg",
+//         "feature": "gg",
+//         "time": 1
+//
+//     },
+//     {
+//       "id": 1,
+//         "configName": "gg",
+//         "modelType": "gg",
+//         "feature": "gg",
+//         "time": 1
+//
+//     }]
+//
+//   }
+// }
+
+/**
+ * 获取所有新配置 GET /get/all_new/{userId}
+ * @param {*} payload
+ * @returns
+ */
+
+export const getAllNew = payload => {
+  const { uid } = payload;
+  return axios.get(`${CONFIG_MODULE}/get/all_new/${uid}`).then(res => {
+
+    return res.data;
+  });
+}
+
+
+/**
+ * 获取单个个配置 GET  /get/one/config/{configId}
+ * @param {*} payload
+ * @returns
+ */
+export const getOneConfig = payload => {
+  const { configId } = payload;
+  console.log("configId",configId);
+  console.log("payload",payload);
+  // return axios.get(`${CONFIG_MODULE}/get/one/config?configId=${configId}`).then(res => {
+  //
+  //   return res.data;});
+    return Promise.resolve({
+      "timestamp": 1649473724362,
+      "status": 200,
+      "data": {
+        "configId": "1",
+        "modelTypeId": "6",
+        "modelTypeName": "决策树",
+        "modelDes": "决策树是一个预测模型;他代表的是对象属性与对象值之间的一种映射关系。树中每个节点表示某个对象,而每个分叉路径则代表的某个可能的属性值,而每个叶结点则对应从根节点到该叶节点所经历的路径所表示的对象的值。",
+        "modelDetileDes": "通过分析交通数据中的road、lane、vehicle_class、duration字段来预测事故类别。",
+        "featureList": [
+          {
+            "id": 105,
+            "fileInfoId": 1,
+            "fieldName": "road",
+            "aliasName": "",
+            "fieldDes": "",
+            "nullsRatio": 0.0,
+            "conOrDis": 0,
+            "fieldType": "string",
+            "valueInfo": "[\"R\",\"L\"]"
+          },
+          {
+            "id": 106,
+            "fileInfoId": 1,
+            "fieldName": "lane",
+            "aliasName": "",
+            "fieldDes": "",
+            "nullsRatio": 0.0,
+            "conOrDis": 0,
+            "fieldType": "string",
+            "valueInfo": "[\"r\",\"m\",\"l\"]"
+          },
+          {
+            "id": 107,
+            "fileInfoId": 1,
+            "fieldName": "vehicle_class",
+            "aliasName": "",
+            "fieldDes": "",
+            "nullsRatio": 0.0,
+            "conOrDis": 0,
+            "fieldType": "string",
+            "valueInfo": "[\"car\",\"truck\",\"bus\"]"
+          },
+          {
+            "id": 110,
+            "fileInfoId": 1,
+            "fieldName": "duration",
+            "aliasName": "",
+            "fieldDes": "",
+            "nullsRatio": 0.0,
+            "conOrDis": 0,
+            "fieldType": "string",
+            "valueInfo": "[\"48,60\",\"24,36\",\"36,48\",\"12,24\",\"0,12\"]"
+          },
+          {
+            "id": 109,
+            "fileInfoId": 1,
+            "fieldName": "event_type",
+            "aliasName": "",
+            "fieldDes": "",
+            "nullsRatio": 0.0,
+            "conOrDis": 0,
+            "fieldType": "string",
+            "valueInfo": "[\"cruise\",\"overdrive\"]"
+          }
+        ],
+        "modelInfos": [
+          {
+            "modelName": "event_data",
+            "modelDetailName": "DecisionTree",
+            "trainedStatus": 1
+          },
+          {
+            "modelName": "event_data2",
+            "modelDetailName": "DecisionTree",
+            "trainedStatus": -1
+          },
+          {
+            "modelName": "event_data3",
+            "modelDetailName": "DecisionTree",
+            "trainedStatus": -1
+          }
+        ]
+      }
+    });
+
+}
+
+/**
+ * 更改配置 GET /change/{configId}?confName={confName}&trainFeatureList={trainFeatureList}
+ * @param {*} payload
+ * @returns
+ */
+export const changeConfig = payload => {
+  // console.log("change");
+  console.log("changeConfig",payload);
+  const { configId,confName,tranFeatureList } = payload;
+  return axios.get(`${CONFIG_MODULE}/change/${configId}?confName=${confName}&trainFeatureList={trainFeatureList}`).then(res => {
+
+    return res.data;
+  });
+}
+
+
+/**
+ * 删除模型 GET /delete/{configId}
+ * @param {*} payload
+ * @returns
+ */
+export const deleteModelByModelId = configId => {
+  //console.log("deletepara",payload);
+  //const { configId } = payload;
+  return axios.get(`${CONFIG_MODULE}/delete?configId=${configId}`).then(res => {
+
+    return res.data;
+  });
+}
+
+/**
+ * 选择特征 GET /get/features/{fileId}?fieldName={fieldName}
+ * @param {*} payload
+ * @returns
+ */
+export const getFeatureSelection = payload => {
+  const { fileId,fieldName } = payload;
+  return axios.get(`${CONFIG_MODULE}/get/features?fileId=${fileId}&fieldName=${fieldName}`).then(res => {
+
+    return res.data;
+  });
+}

+ 305 - 0
src/api/file.js

@@ -0,0 +1,305 @@
+import axios from 'axios';
+import {FILE_MODULE} from "./_prefix";
+// import request from '../utils/request';
+
+/**
+ *  添加文件 POST /upload
+ * @param {*} payload:formData,直接放Body里
+ * @returns
+ */
+export const UploadFile = payload => {
+    return axios.post(`${FILE_MODULE}/upload`,
+        payload
+        ,{
+        headers:{
+            'Content-Type': "multipart/form-data;"
+            // 'Content-Type': "false",
+            // 'Process-Data': 'false',
+        }
+    }).then((res) => {
+        return res.data
+    })
+}
+/**
+ * ({
+        url: `${FILE_MODULE}/upload`,
+        method: 'post',
+        data: payload,
+        "Process-Data": false,// 告诉axios不要去处理发送的数据(重要参数)
+        "Content-Type": false,   // 告诉axios不要去设置Content-Type请求头
+    }).then(res => {
+        return res.data
+    });
+ */
+
+
+//    return axios.post(`${FILE_MODULE}/upload`,
+//         payload,
+//  {
+//             headers:{
+//                 'Content-Type': "multipart/form-data",
+//                 // 'Content-Type': "false",
+//                 // 'Process-Data': 'false',
+//             }
+//         }
+
+ //    ).then(res => {
+ //        return res.data;
+ //    });
+
+/**
+ *  获得文件列表 GET /get/all
+ * @param {*} userId 用户Id
+ * @returns
+ */
+export const GetAllFile = userId => {
+    return axios.get(`${FILE_MODULE}/get/all`, {
+        params:{
+            userId: userId
+        }
+    }).then( res => {
+        return res.data;
+    });
+}
+
+// 直接返回数据
+// return Promise.resolve({
+//     "timestamp": 1649397417317,
+//     "status": 200,
+//     "data": [
+//         {
+//             "fileId": "1",
+//             "fileName": "event_data"
+//         }
+//     ]
+// })
+
+/**
+ *  获得文件具体信息 GET /get/detail
+ * @param {*} fileId 文件Id
+ * @returns
+ */
+export const getFileDetail = fileId => {
+//     return axios.get(`${FILE_MODULE}/get/detail`, {
+//         params: {
+//             fileId: fileId
+//         }
+//     }).then( res => {
+//         return res.data;
+//     })
+// }
+
+//直接返回数据:
+    return Promise.resolve({
+        "timestamp": 1649398931190,
+        "status": 200,
+        "data": {
+            "fileName": "event_data",
+            "createTime": "2022-03-29T09:25:43.154+00:00",
+            "fileStrucInfo": {
+                "totalRows": "754"
+            },
+            "headerInfos": [
+                {
+                    "id": 103,
+                    "fileInfoId": 1,
+                    "fieldName": "frame_index",
+                    "aliasName": "",
+                    "fieldDes": "",
+                    "nullsRatio": 0.0,
+                    "conOrDis": 1,
+                    "fieldType": "int",
+                    "valueInfo": "[\"79\",\"89992\"]"
+                },
+                {
+                    "id": 104,
+                    "fileInfoId": 1,
+                    "fieldName": "time",
+                    "aliasName": "",
+                    "fieldDes": "",
+                    "nullsRatio": 0.0,
+                    "conOrDis": 1,
+                    "fieldType": "double",
+                    "valueInfo": "[\"3.16\",\"3599.68\"]"
+                },
+                {
+                    "id": 105,
+                    "fileInfoId": 1,
+                    "fieldName": "road",
+                    "aliasName": "",
+                    "fieldDes": "",
+                    "nullsRatio": 0.0,
+                    "conOrDis": 0,
+                    "fieldType": "string",
+                    "valueInfo": "[\"R\",\"L\"]"
+                },
+                {
+                    "id": 106,
+                    "fileInfoId": 1,
+                    "fieldName": "lane",
+                    "aliasName": "",
+                    "fieldDes": "",
+                    "nullsRatio": 0.0,
+                    "conOrDis": 0,
+                    "fieldType": "string",
+                    "valueInfo": "[\"r\",\"m\",\"l\"]"
+                },
+                {
+                    "id": 107,
+                    "fileInfoId": 1,
+                    "fieldName": "vehicle_class",
+                    "aliasName": "",
+                    "fieldDes": "",
+                    "nullsRatio": 0.0,
+                    "conOrDis": 0,
+                    "fieldType": "string",
+                    "valueInfo": "[\"car\",\"truck\",\"bus\"]"
+                },
+                {
+                    "id": 108,
+                    "fileInfoId": 1,
+                    "fieldName": "vehicle_id",
+                    "aliasName": "",
+                    "fieldDes": "",
+                    "nullsRatio": 0.0,
+                    "conOrDis": 1,
+                    "fieldType": "int",
+                    "valueInfo": "[\"20\",\"46862\"]"
+                },
+                {
+                    "id": 109,
+                    "fileInfoId": 1,
+                    "fieldName": "event_type",
+                    "aliasName": "",
+                    "fieldDes": "",
+                    "nullsRatio": 0.0,
+                    "conOrDis": 0,
+                    "fieldType": "string",
+                    "valueInfo": "[\"cruise\",\"overdrive\"]"
+                },
+                {
+                    "id": 110,
+                    "fileInfoId": 1,
+                    "fieldName": "duration",
+                    "aliasName": "",
+                    "fieldDes": "",
+                    "nullsRatio": 0.0,
+                    "conOrDis": 0,
+                    "fieldType": "string",
+                    "valueInfo": "[\"48,60\",\"24,36\",\"36,48\",\"12,24\",\"0,12\"]"
+                }
+            ]
+        }
+    })
+}
+/**
+ *  删除文件 GET /delete
+ * @param {*} fileId
+ * @returns
+ */
+export const deleteFile = fileId => {
+    return axios.get(`${FILE_MODULE}/delete`, {
+        params:{
+            fileId: fileId
+        }
+    }).then( res => {
+            return res.data;
+    });
+}
+
+/**
+ *  文件分析 GET /analysis/fields
+ * @param {*} payload
+ * @returns
+ */
+export const analysisFile = (fieldIds,funcId) => {
+    //fieldIds=JSON.stringify(fieldIds)
+    console.log(fieldIds)
+    fieldIds=JSON.parse(fieldIds)
+    console.log(fieldIds)
+    let url=`${FILE_MODULE}/analysis/fields?funcId=${funcId}`
+    for(let i=0;i<fieldIds.length;i++){
+        let fieldId=fieldIds[i]
+        url+=`&fieldIds=${fieldId}`
+    }
+    console.log(url)
+    return axios.get(url).then(res => {
+        return res.data;
+    });
+    // if (funcId==1){
+    //     return Promise.resolve({
+    //         "timestamp": 1649561125585,
+    //         "status": 200,
+    //         "data": {
+    //             "105_statistical": {
+    //                 "R": 330.0,
+    //                 "L": 424.0
+    //             },
+    //             "105_distribution": {
+    //                 "R": 0.4376657824933687,
+    //                 "L": 0.5623342175066314
+    //             }
+    //         }
+    //     });
+    // }
+    // if (funcId==2){
+    //     return Promise.resolve({
+    //         "timestamp": 1649561125585,
+    //         "status": 200,
+    //         "data":{
+    //             "103": [
+    //                 79.0,
+    //                 737.0,
+    //                 753.0],
+    //             "104": [
+    //                 3.16,
+    //                 29.48,
+    //                 30.12],
+    //             "108": [
+    //                 20.0,
+    //                 291.0,
+    //                 318.0]
+    //         }
+    //     });
+    // }
+    // if (funcId==3){
+    //     return Promise.resolve({
+    //         "timestamp": 1649561321298,
+    //         "status": 200,
+    //         "data": {
+    //             "frame_index": {
+    //                 "max": 89992.0,
+    //                 "variance": 6.474726567563616E8,
+    //                 "mean": 45439.82360742705,
+    //                 "stddev": 25445.484014975264
+    //             }
+    //         }
+    //     })
+    // }
+    // if (funcId==4){
+    //     return Promise.resolve({
+    //         "timestamp": 1649561409955,
+    //         "status": 200,
+    //         "data": {
+    //             "103": {
+    //                 "skewness": -0.010820149962232854,
+    //                 "kurtosis": -1.0998405481091291
+    //             }
+    //         }
+    //     })
+    // }
+    // if (funcId==5){
+    //     return Promise.resolve({
+    //         "timestamp": 1649561470265,
+    //         "status": 200,
+    //         "data": {
+    //             "Corr": 0.9999999999999994
+    //         }
+    //     })
+    // }
+    // return Promise.resolve({
+    //     "timestamp": 1649561470265,
+    //     "status": 400,
+    //     "data": ""
+    // })
+}

+ 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
+    })
+    
+}

+ 57 - 0
src/api/mail.js

@@ -0,0 +1,57 @@
+import {MAIL_MODULE} from "./_prefix";
+
+export const sendMail = payload => {
+    console.log(payload);
+    //id,
+    // const {fromUserId, toUserId, title,content} = payload;
+    //
+    // return axios.post(`${MAIL_MODULE}/send`, {
+    //     fromUserId, toUserId, title,content
+    // }).then(res => {
+    //     return res.data;
+    // });
+    return Promise.resolve({
+        "success": true,
+        "message": "success",
+        "object": {}
+    })
+}
+
+export const getUserMail = payload => {
+    // console.log("getAllConfig",payload);
+    // const {userId} = payload;
+    // return axios.get(`${MAIL_MODULE}/getUserMail/{userId}`).then(res => {
+    //     return res.data;
+    // });
+    return Promise.resolve({
+        "success": true,
+        "message": "success",
+        "object": [{
+            "mailId": 1,
+            "fromUserId": 1,
+            "toUserId":1,
+            "title":"title",
+            "content":" 在预实验中,我发现在保持纸牌水平飞出的前提下,不进行旋转的纸牌只能前进很短距离,而一旦使纸牌开始旋转,纸牌飞行距离明显增加且飞牌时用力越大,纸牌前进距离越长。分析现象得出猜想:在纸牌水平飞行过程中,饶自身轴旋转可以显著减小其飞行时所受到的空气阻力,从而保持稳定的飞行状态,运动更长距离。\n" +
+                "  查阅文献得到:与子弹需旋转射出的原理类似,因为空气是流体,纸牌在旋转过程中厚度切割空气,带动其薄边周围的空气旋转,使得空气与纸牌相对速度减小,由流体力学空气阻力公式(经验公式)F=C * A * V^2可知,纸牌前进所受的空气阻力减小。同时由于陀螺效应,纸牌较好地保持其旋转方向,保持其薄边迎风,减轻由于阻力干扰导致纸牌飞行晃动从而增大迎风面积,使纸牌更好保持其稳定的飞行状态。",
+            "time":"2022.3.15"
+        },
+            {
+                "mailId": 2,
+                "fromUserId": 1,
+                "toUserId":1,
+                "title":"关于您帖子“使用决策树预测交通数据帖子的询问”",
+                "content":"请问您的帖子所使用的数据是否是交通局MMM后台检测系统导出的数据?我在导出选项选择2与您导出的数据格式不同,请问您的导出参数是多少?",
+                "time":"2022.3.15"
+            },
+            {
+                "mailId": 3,
+                "fromUserId": 1,
+                "toUserId":1,
+                "title":"title",
+                "content":"这是一个内容",
+                "time":"2022.3.15"
+            }
+
+        ]
+    })
+}

+ 115 - 0
src/api/model.js

@@ -0,0 +1,115 @@
+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.data//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 {modelId,fileId}=data;
+        const res=await axios.get(`${MODEL_MODULE}/use?fileId=${fileId}&modelId=${modelId}`);
+        return res;
+    }
+
+
+
+

+ 32 - 0
src/api/pic.js

@@ -0,0 +1,32 @@
+import request from '../utils/request';
+import axios from 'axios';
+import {FILE_MODULE, PIC_MODULE} from "./_prefix";
+
+/**
+ *  添加图片 POST /upload
+ * @param {*} payload
+ * @returns
+ */
+export const UploadFile = payload => {
+    console.log(payload);
+    const {userId, file, fileName} = payload;
+    return axios.post(`${PIC_MODULE}/upload`, {
+        userId, file, fileName
+    }).then(res => {
+        return res.data;
+    });
+}
+
+/**
+ *  获得图片列表 GET /get/all/proj
+ * @param {*} payload
+ * @returns
+ */
+export const GetAllFile = payload => {
+    console.log(payload);
+    const {userId} = payload;
+    return axios.get(`${PIC_MODULE}/get/all/proj`, {params:{userId:userId}}).then(res => {
+        return res.data;
+    });
+}
+

+ 184 - 0
src/api/posts.js

@@ -0,0 +1,184 @@
+import axios from 'axios';
+import {CONFIG_MODULE, POST_MODULE} from "./_prefix";
+import {getAllModel} from "./model";
+
+
+export const getPostByPostId = payload => {
+    // console.log("getAllConfig",payload);
+    const {userId, postId} = payload;
+    //return axios.get(`${POST_MODULE}/getPost/{postId}/{userId}`).then(res => {
+    //     let modelId=res.data.object.shareModelList[0]
+    //     let postUserId=res.data.object.userId
+    //     let allModels=getAllModel(postUserId)
+    //     for(let i=0;i<allModels.length;i++){
+    //         if(modelId==allModels[i].modelId){
+    //             res.data.object["configId"]=allModels[i].configId
+    //         }
+    //     }
+    //     return res.data;
+    // });
+
+    return Promise.resolve({
+        "success":true,
+        "message":"success",
+        "object": {
+            "postId":1,
+            "userId":1,
+            "configId":1,
+            "title":"决策树分析交通数据预测事故",
+            "content":"通过a、b字段预测c字段,使用决策树模型,选了两个效果较好的模型供大家参考",
+            "updateTime":"2022.10.30",
+            "praise":15,
+            "comment_num":8,
+            "shareFileList":[1],
+            "shareModelList":["1","2"]
+        }
+    })
+}
+export const getUserCollection = payload => {
+    // console.log("getAllConfig",payload);
+    const {userId} = payload;
+    // return axios.get(`${POST_MODULE}/getUserCollection/{userId}`).then(res => {
+    //     return res.data;
+    // });
+    return Promise.resolve({
+        "success":true,
+        "message":"success",
+        "object":[{
+            "postId":1,
+            "userId":1,
+            "title":"我的收藏",
+            "content":"通过a、b字段预测c字段,使用决策树模型,选了两个效果较好的模型供大家参考",
+            "updateTime":"2022.10.30",
+            "praise":15,
+            "comment_num":8},
+            {
+                "postId":2,
+                "userId":1,
+                "title":"决策树分析交通数据预测事故",
+                "content":"通过a、b字段预测c字段,使用决策树模型,选了两个效果较好的模型供大家参考",
+                "updateTime":"2022.10.30",
+                "praise":15,
+                "comment_num":8}]
+    })
+}
+export const collection = payload => {
+    // console.log("getAllConfig",payload);
+    const {userId,postId} = payload;
+    // return axios.get(`${POST_MODULE}/collection/{userId}/{postId}`).then(res => {
+    //     return res.data;
+    // });
+    return Promise.resolve({
+        "success":true,
+        "message":"success",
+        "object":{}
+    })
+}
+export const getUserPost = payload => {
+    // console.log("getAllConfig",payload);
+    const {userId} = payload;
+    // return axios.get(`${POST_MODULE}/getUserPost/{userId}`).then(res => {
+    //     return res.data;
+    // });
+    return Promise.resolve({
+        "success":true,
+        "message":"success",
+        "object":[{
+            "postId":1,
+            "userId":1,
+            "title":"我的帖子",
+            "content":"通过a、b字段预测c字段,使用决策树模型,选了两个效果较好的模型供大家参考",
+            "updateTime":"2022.10.30",
+            "praise":15,
+            "comment_num":8},
+            {
+                "postId":2,
+                "userId":1,
+                "title":"决策树分析交通数据预测事故",
+                "content":"通过a、b字段预测c字段,使用决策树模型,选了两个效果较好的模型供大家参考",
+                "updateTime":"2022.10.30",
+                "praise":15,
+                "comment_num":8}]
+    })
+}
+
+/**
+ *  搜索帖子列表 POST /add
+ * @param {*} payload
+ * @returns
+ */
+export const searchPost = payload => {
+    console.log(payload);
+    //id,
+    const {userId, keyword, flagList} = payload;
+
+    // return axios.post(`${POST_MODULE}/searchPost`, {
+    //     userId,keyword,flagList
+    // }).then(res => {
+    //     return res.data;
+    // });
+
+
+    return Promise.resolve({
+        "success":true,
+        "message":"success",
+        "object":[{
+            "postId":1,
+            "userId":1,
+            "title":"决策树分析交通数据预测事故",
+            "content":"通过a、b字段预测c字段,使用决策树模型,选了两个效果较好的模型供大家参考",
+            "updateTime":"2022.10.30",
+            "praise":15,
+            "comment_num":8},
+            {
+                "postId":2,
+                "userId":1,
+                "title":"随即森林分析交通数据预测事故",
+                "content":"通过a、b字段预测c字段,使用决策树模型,选了两个效果较好的模型供大家参考",
+                "updateTime":"2022.10.30",
+                "praise":2,
+                "comment_num":3},
+            // {
+            //     "postId":3,
+            //     "userId":1,
+            //     "title":"决策树分析交通数据预测事故",
+            //     "content":"通过a、b字段预测c字段,使用决策树模型,选了两个效果较好的模型供大家参考",
+            //     "updateTime":"2022.10.30",
+            //     "praise":15,
+            //     "comment_num":8},
+            // {
+            //     "postId":4,
+            //     "userId":1,
+            //     "title":"决策树分析交通数据预测事故",
+            //     "content":"通过a、b字段预测c字段,使用决策树模型,选了两个效果较好的模型供大家参考",
+            //     "updateTime":"2022.10.30",
+            //     "praise":15,
+            //     "comment_num":8},
+            // {
+            //     "postId":5,
+            //     "userId":1,
+            //     "title":"决策树分析交通数据预测事故",
+            //     "content":"通过a、b字段预测c字段,使用决策树模型,选了两个效果较好的模型供大家参考",
+            //     "updateTime":"2022.10.30",
+            //     "praise":15,
+            //     "comment_num":8},
+            // {
+            //     "postId":6,
+            //     "userId":1,
+            //     "title":"决策树分析交通数据预测事故",
+            //     "content":"通过a、b字段预测c字段,使用决策树模型,选了两个效果较好的模型供大家参考",
+            //     "updateTime":"2022.10.30",
+            //     "praise":15,
+            //     "comment_num":8},
+            // {
+            //     "postId":7,
+            //     "userId":1,
+            //     "title":"决策树分析交通数据预测事故",
+            //     "content":"通过a、b字段预测c字段,使用决策树模型,选了两个效果较好的模型供大家参考",
+            //     "updateTime":"2022.10.30",
+            //     "praise":15,
+            //     "comment_num":8}
+            ]
+    })
+
+}

+ 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;
+}

BIN
src/assets/img/earth.jpg


BIN
src/assets/img/img.jpg


BIN
src/assets/img/login-bg.jpg


+ 73 - 0
src/components/Comments.vue

@@ -0,0 +1,73 @@
+<template>
+    <div :style="{'width': width + 'px'} ">
+        <h4 style="margin-bottom: 40px; padding-left: 20px; border-left: 3px solid #52A8FF;">所有评论</h4>
+        <el-empty v-show="!commentList.length" :image-size="100" description="暂无评论"></el-empty>
+        <div class="comment" v-for="comment in commentList" :key="comment.userId" >
+            <div class="header">
+                <div class="avatar">
+                    <el-avatar size="large" icon="el-icon-user" ></el-avatar>
+                </div>
+                <div class="right">
+                    <div class="time">   {{comment.time}}  </div>
+                </div>
+            </div>
+            <div class="content">
+          {{comment.content}}
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+export default {
+    name: "",
+    props: {
+        commentList: Array,
+        width: Number
+    },
+    data() {
+        return {
+        }
+    },
+    methods: {
+    }
+}
+</script>
+
+<style scoped>
+.comment {
+    
+    margin-bottom: 8px;
+}
+
+.header {
+    
+    display: flex;
+    align-items: center;
+  background-color: #eeeeee;
+
+}
+
+.avatar {
+    float: left;
+    margin-right: 10px;
+    color: red;
+}
+.right {
+    float: left;
+}
+
+.userName {
+    color: #303133;
+}
+
+.time {
+    font-size: 14px;
+    color: #606266;
+
+}
+
+.content {
+    color: #000000;
+    background-color: #ffffff;
+}
+</style>

+ 171 - 0
src/components/Header.vue

@@ -0,0 +1,171 @@
+<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">轻量级AI平台</div>
+        <div class="header-right">
+            <div class="header-user-con">
+              <div>
+                <router-link :to="{path:'/square'}">
+                  <el-button  style="float: right;margin-right: 15px;margin-top: 1px"  type="danger"   round>
+                    广场
+                  </el-button>
+                </router-link>
+              </div>
+                <!-- 消息中心 -->
+                <div class="btn-bell">
+                    <el-tooltip effect="dark" :content="message?`有${message}条未读消息`:`消息中心`" placement="bottom">
+                        <router-link to="/message">
+                          <i class="el-icon-message" style="color: #53a8ff;"></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: 30px;
+    color: #fff;
+  background-color: #000000;
+}
+.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 {
+  margin-top: 2px;
+    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>

+ 201 - 0
src/components/Sidebar.vue

@@ -0,0 +1,201 @@
+<template>
+    <div class="sidebar">
+        <el-menu class="sidebar-el-menu" :default-active="onRoutes" :collapse="collapse" background-color="#000000"
+            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 } from "vue";
+import { useStore } from "vuex";
+import { useRoute } from "vue-router";
+export default {
+    setup() {
+        const items = [
+          {
+            icon: "el-icon-lx-file",
+            title: "我的文件",
+            index:3,
+            subs: [
+              {
+                index: "/fileList",
+                title: "我的文件"
+              },
+              {
+                index: "/fileDetail",
+                title: "文件详情",
+              },
+              {
+                index: "/upload",
+                title: "文件上传",
+              },
+            ]
+          },
+          {
+              icon: "el-icon-lx-cascades",
+              index: "/config",
+              title: "模型配置",
+          },
+
+
+          {
+            icon: "el-icon-star-off",
+            index: "/modelDetail",
+            title: "模型训练",
+          },
+          {
+            icon: "el-icon-coin",
+            index: "/modelList",
+            title:"机器学习模型",
+          },
+          {
+            icon: "el-icon-coin",
+            index: "/dlModelList",
+            title:"深度学习模型",
+
+          },
+
+          {
+            icon: "el-icon-pie-chart",
+            index: "/charts",
+            title: "训练结果",
+          },
+
+          // {
+          //   icon: "el-icon-lx-redpacket_fill",
+          //   index: "/modelList",
+          //   title:"深度学习",
+          // },
+          //
+          // {
+          //     icon: "el-icon-lx-copy",
+          //     index: "/message",
+          //     title: "我的消息",
+          // },
+          {
+              icon: "el-icon-user",
+              index: "/user",
+              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-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>

+ 178 - 0
src/components/SquareHeader.vue

@@ -0,0 +1,178 @@
+<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">轻量级AI平台</div>
+    <div class="header-right">
+      <div class="header-user-con">
+        <div>
+          <router-link :to="{path:'/fileList'}">
+          <el-button  style="float: right;margin-right: 15px;margin-top: 1px"  type="danger"   round>
+            工作台
+          </el-button>
+        </router-link>
+        </div>
+        <el-button @click="handleCollect()" style="background-color: black;border: black;font-size: 30px;color: #e6a23c ">
+          <i class="el-icon-star-on" style="color: #e6a23c"></i>
+        </el-button>
+        <!-- 消息中心 -->
+        <div class="btn-bell">
+          <el-tooltip effect="dark" :content="message?`有${message}条未读消息`:`消息中心`" placement="bottom">
+            <router-link to="/message">
+              <i class="el-icon-message" style="color: #53a8ff;"></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>
+              <el-dropdown-item  divided command="collection">我的收藏</el-dropdown-item>
+              <el-dropdown-item divided command="mine">我的发布</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();
+
+
+    return {
+      username,
+      message,
+      collapse,
+      collapseChage,
+    };
+  },
+  methods:{
+    handleCollect(){
+      this.$emit('getCollection')
+    },
+     handleCommand (command){
+      if (command == "collection") {
+        this.$emit('getCollection')
+      } else if (command == "mine") {
+        this.$emit('getMine')
+      }
+    }
+  }
+};
+</script>
+<style scoped>
+.header {
+  position: relative;
+  box-sizing: border-box;
+  width: 100%;
+  height: 70px;
+  font-size: 30px;
+  color: #fff;
+  background-color: #000000;
+}
+.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 {
+  margin-top: 2px;
+  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>

+ 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>

+ 49 - 0
src/components/WriteComment.vue

@@ -0,0 +1,49 @@
+  <template>
+    <div :style="{'width': width + 'px'}" class="container" style="border-color: white">
+          <el-input v-model="describe" placeholder="输入你的评论" style="margin-top: 20px" type="textarea"></el-input>
+      <el-button type="primary"    @click="submit" style="margin-top: 20px" round>发表<i class="el-icon-upload el-icon--right"></i></el-button>
+    </div>
+</template>
+<script>
+import { submitComment } from "../api/comment.js"
+
+export default {
+    name: "",
+    data() {
+        return {
+            describe: "",
+            colors: ['#99A9BF', '#F7BA2A', '#FF9900'],
+        }
+    },
+    props: {
+        width: Number,
+        postId: Number
+    },
+    methods: {
+        submit() {
+            if (!this.describe) {
+                this.$message.warning('请填写评价')
+                return
+            }
+
+            submitComment({
+                userId: 0,
+                content: this.describe,
+                postId: this.postId
+            }).then(res => {
+                if (res.success === 0) {
+                    this.$message.success('发表成功!')
+                    
+                }
+                else {
+                    this.$message.error(res.message)
+                }
+            })
+        }
+    }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 12 - 0
src/main.js

@@ -0,0 +1,12 @@
+import {createApp} from 'vue'
+import App from './App.vue'
+import router from './views/unused/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)
+}

+ 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;

+ 465 - 0
src/views/ConfigDetail.vue

@@ -0,0 +1,465 @@
+<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="handle-box">
+
+
+
+      </div>
+
+<!--  <el-tab-pane :label="featureList"> </el-tab-pane>-->
+      <div class="container">
+        <div class="form-box" >
+          <el-form ref="formRef" label-width="120px">
+            <el-form-item label="模型类型名:" >
+              {{config.modelTypeName}}
+            </el-form-item>
+            <el-form-item label="模型描述:" >
+              {{config.modelDes}}
+            </el-form-item>
+            <el-form-item label="模型详情:" >
+              {{config.modelDetileDes}}
+            </el-form-item>
+            <el-form-item label="特征字段:" >
+              <el-table :data="tableData" border class="table"  ref="fieldTable" header-cell-class-name="table-header" @selection-change="handleSelectChange">
+                <el-table-column label="字段名" width="120%">
+                  <template #default="scope"><span>{{ scope.row.fieldName }}</span></template>
+                </el-table-column>
+                <el-table-column label="别名">
+                  <template #default="scope">{{ scope.row.aliasName }}</template>
+                </el-table-column>
+                <el-table-column label="描述">
+                  <template #default="scope">{{ scope.row.fieldDes }}</template>
+                </el-table-column>
+                <el-table-column label="取值类型">
+                  <template #default="scope">{{ scope.row.fieldType }}</template>
+                </el-table-column>
+                <el-table-column label="分布类型">
+                  <template #default="scope">{{ scope.row.conOrDis }}</template>
+                </el-table-column>
+                <el-table-column label="空值率">
+                  <template #default="scope">{{ scope.row.nullsRatio }}</template>
+                </el-table-column>
+
+                <el-table-column label="值域" width="150%">
+                  <template #default="scope">{{ scope.row.valueInfo }}</template>
+                </el-table-column>
+              </el-table>
+            </el-form-item>
+
+            <el-form-item label="模型列表:" >
+            <el-table :data="modelData" border class="table" ref="fieldTable" header-cell-class-name="table-header" @selection-change="handleSelectChange">
+              <el-table-column label="模型名" width="150%">
+                <template #default="scope"><span>{{ scope.row.modelName }}</span></template>
+              </el-table-column>
+              <el-table-column label="模型类别" width="150%">
+                <template #default="scope">{{ scope.row.modelDetailName }}</template>
+              </el-table-column>
+              <el-table-column label="训练状态">
+                <template #default="scope" >
+                  <div v-if="scope.row.trainedStatus===-1">未训练</div>
+                  <div v-else="">已训练</div></template>
+              </el-table-column>
+              <el-table-column label="操作" width="180" align="center">
+                <template #default="scope">
+
+                  <router-link :to="{path:'/modelList',query:{modelId:scope.row.id}}">
+                    <el-button type="text" icon="el-icon-view" >查看模型
+                    </el-button>
+                  </router-link>
+
+                </template>
+              </el-table-column>
+
+
+
+            </el-table>
+            </el-form-item>
+            <el-form-item>
+
+              <el-button type="primary"  @click="createModel()">生成模型</el-button>
+            </el-form-item>
+          </el-form>
+
+
+
+          <el-dialog title="新建模型" v-model="modelVisiable" width="30%">
+            <el-form label-width="120px">
+              <el-form-item label="文件Id" required>
+                <el-input v-model="form.fileInfoId" ></el-input>
+              </el-form-item>
+              <el-form-item label="模型名称" required>
+                <el-input v-model="form.modelName"></el-input>
+              </el-form-item>
+              <el-form-item label="MaxIter" v-model="showMaxIter" v-if="showMaxIter===true">
+                <el-input v-model="form.MaxIter"></el-input>
+              </el-form-item>
+              <el-form-item label="RegParam" v-model="showRegParam" v-if="showRegParam===true">
+                <el-input v-model="form.RegParam"></el-input>
+              </el-form-item>
+              <el-form-item label="ElasticNetParam" v-model="showElasticNetParam" v-if="showElasticNetParam===true">
+                <el-input v-model="form.ElasticNetParam"></el-input>
+              </el-form-item>
+              <el-form-item label="Category" v-model="showCategory" v-if="showCategory===true">
+                <el-input v-model="form.Category"></el-input>
+              </el-form-item>
+              <el-form-item label="TrainSetOccupy" v-model="showTrainingSetOccupy" v-if="showTrainingSetOccupy===true">
+                <el-input v-model="form.TrainingSetOccupy"></el-input>
+              </el-form-item>
+              <el-form-item label="DataSetOccupy" v-model="showTrainingDataSetOccupy" v-if="showTrainingDataSetOccupy===true">
+                <el-input v-model="form.TrainingDataSetOccupy"></el-input>
+              </el-form-item>
+              <el-form-item label="NumOfCluster" v-model="showNumOfCluster" v-if="showNumOfCluster===true">
+                <el-input v-model="form.NumOfCluster"></el-input>
+              </el-form-item>
+              <el-form-item label="Seed" v-model="showSeed" v-if="showSeed===true">
+                <el-input v-model="form.Seed"></el-input>
+              </el-form-item>
+
+            </el-form>
+            <template #footer>
+                <span class="dialog-footer">
+                    <el-button @click="modelVisiable = false">取 消</el-button>
+                    <el-button type="primary" @click="saveModel">确 定</el-button>
+                </span>
+            </template>
+          </el-dialog>
+          </div>
+        </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>
+
+
+
+
+
+</template>
+
+<script>
+import {ref, reactive, getCurrentInstance, onMounted} from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { fetchData } from "../api/index";
+import {getFileDetail} from "../api/file";
+import {getOneConfig} from "../api/config";
+import {useRoute}from "vue-router";
+import {addModel} from "../api/model";
+export default {
+  name: "configDetail",
+  //训练特征
+  setup() {
+    const query = reactive({
+      address: "",
+      name: "",
+      pageIndex: 1,
+      pageSize: 10,
+    });
+    const fileId=ref(1);
+    //new TODO
+    //TODO
+    const fieldNameList=[]; //字段名
+    const aliasList=[];   //别名
+    const descList=[];      //描述
+    const aList=[];   //取值类型
+    const bList=[];   //分布类型
+    const cList=[];   //空值率
+    const dList=[];
+
+
+    const tableData = ref([]);
+    const selectData = ref([]);
+    const pageTotal = ref(0);
+    const modelData=ref([]);
+    const config=ref([]);
+    const route=useRoute()
+    const showMaxIter=ref(false);
+    const showRegParam=ref(false);
+    const showElasticNetParam=ref(false);
+    const showCategory=ref(false);
+    const showTrainingSetOccupy=ref(false);
+    const showTrainingDataSetOccupy=ref(false);
+    const showNumOfCluster=ref(false);
+    const showSeed=ref(false);
+
+    let form = reactive({
+      modelTypeId:"",
+      configId:route.query.configId,
+      fileInfoId:"",
+      modelName:"",
+      MaxIter:"",
+      RegParam:"",
+      ElasticNetParam:"",
+      Category:"",
+      TrainingSetOccupy:"",
+      TrainingDataSetOccupy:"",
+      NumOfCluster:"",
+      Seed:"",
+
+
+
+
+
+    });
+    // 获取表格数据
+
+    const getData = () => {
+
+      //todo:调用获取文件具体信息获取字段列表
+      // console.log("queryId",route.query.configId);
+
+      if(route.query.configId!=null) {
+        getOneConfig({configId:route.query.configId}).then(res => {
+          // console.log("configdetail",route.query.configId);
+
+          config.value=res.data;
+          form.modelTypeId=config.value.modelTypeId;
+          console.log(config.value.modelTypeId);
+          if(config.value.modelTypeId==6){
+            console.log("this ture")
+            showCategory.value=true;
+            showTrainingDataSetOccupy.value=true;
+          }
+            switch (form.modelTypeId
+
+
+                ){
+            case '1':
+              showMaxIter.value=true;
+              showRegParam.value=true;
+              showElasticNetParam.value=true;
+              break;
+            case '2':
+              showCategory.value=true;
+              showTrainingSetOccupy.value=true;
+              break;
+            case '3'||'4':
+              showMaxIter.value=true;
+              showRegParam.value=true;
+              showElasticNetParam.value=true;
+              break;
+            case '5'||6||'7':
+              showCategory.value=true;
+              showTrainingDataSetOccupy.value=true;
+              console.log("this ture")
+              break;
+            case '8':
+              showNumOfCluster.value=true;
+              showSeed.value=true;
+
+
+          }
+          console.log("form",form);
+          //console.log("config",config.value.modelTypeId);
+          tableData.value = res.data.featureList;
+          for (var i = 0; i < tableData.value.length; i++) {
+            if (tableData.value[i].conOrDis === 1) {
+              tableData.value[i].conOrDis = "连续值"
+            } else {
+              tableData.value[i].conOrDis = "离散值"
+            }
+          }
+          //console.log(tableData)
+
+          modelData.value=res.data.modelInfos;
+          console.log("tableData",tableData);
+          fileId.value=tableData.value[0].fileInfoId;
+          form.fileInfoId=(String)(fileId.value)
+        })
+
+      }
+
+    };
+    getData();
+
+
+
+
+
+    // 查询操作
+    const handleSearch = () => {
+      query.pageIndex = 1;
+      getData();
+    };
+    // 分页导航
+    const handlePageChange = (val) => {
+      query.pageIndex = val;
+      getData();
+    };
+
+    // 删除操作
+
+
+    // 表格编辑时弹窗和保存
+    const editVisible = ref(true);
+
+
+
+    const saveModel = () => {
+      modelVisiable.value = false
+      form.fileInfoId=tableData.value[0].fileInfoId
+      console.log(form.fileInfoId)
+      //todo:   调用Model相关接口
+      console.log("savemodel",form);
+      const payload={modelTypeId:form.modelTypeId,
+                     configId:form.configId,
+                      fileInfoId:form.fileInfoId,
+                      modelName:form.modelName,
+                      argument:[]
+      }
+      const arg1={
+        MaxIter:form.MaxIter,
+        RegParam:form.RegParam,
+        ElasticNetParam:form.ElasticNetParam
+      }
+      const arg2={
+        Category:form.Category,
+        TrainingDataSetOccupy:form.TrainingDataSetOccupy
+      }
+      const arg3={
+        MaxIter:form.MaxIter,
+        RegParam:form.RegParam,
+        ElasticNetParam:form.ElasticNetParam
+      }
+      const arg4={
+        Category:form.Category,
+        TrainingDataSetOccupy:form.TrainingDataSetOccupy
+      }
+      const arg5={
+        NumOfCluster:form.NumOfCluster,
+        Seed:form.Seed
+      }
+      switch (config.value.modelTypeId){
+        case '1':
+          payload.argument=arg1;
+          break;
+        case '2':
+          payload.argument=arg2;
+          break;
+        case '3'||'4':
+          payload.argument=arg3;
+          break;
+        case '6'||'7'||'8':
+          payload.argument=arg4;
+
+          break;
+        case '9':
+          payload.argument=arg5;
+
+      }
+      ElMessage.success(`已成功生成模型`);
+      // console.log("here",payload);
+      // addModel(payload).then(res=>{
+      //
+      //   if(res.status===200) {
+      //     ElMessage.success(`已成功生成模型`);
+      //
+      //   }
+      //   else ElMessage.error(`生成模型失败`);
+      // })
+
+
+
+
+
+    };
+    let idx = -1;
+    const handleEdit = () => {
+      editVisible.value = true;
+    };
+
+
+
+    //生成模型弹窗
+    const modelVisiable=ref(false);
+    const createModel=()=>{
+
+        modelVisiable.value=true;
+      console.log("here",modelVisiable);
+    }
+    const handleSelectChange=val=>{
+      selectData.value=val;
+    }
+
+    return {
+      modelVisiable,
+      config,
+      query,
+      tableData,
+      pageTotal,
+      modelData,
+      editVisible,
+      form,
+      fileId,
+      showMaxIter,
+      saveModel,
+
+      showRegParam,
+      showElasticNetParam,
+      showCategory,
+      showTrainingSetOccupy,
+      showNumOfCluster,
+      showSeed,
+      showTrainingDataSetOccupy,
+      selectData,
+      handleSelectChange,
+      handleSearch,
+      handlePageChange,
+      createModel,
+      handleEdit,
+
+
+    };
+  },
+};
+
+
+</script>
+
+<style scoped>
+.handle-box {
+  margin-bottom: 20px;
+}
+.handle-table{
+  margin-bottem: 40px;
+}
+
+.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>

+ 173 - 0
src/views/ConfigForm.vue

@@ -0,0 +1,173 @@
+<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 = () => {
+      // 表单校验
+      // console.log("para",this.$route.query.id);
+      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>

+ 358 - 0
src/views/ConfigList.vue

@@ -0,0 +1,358 @@
+<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-option key="5" label="多层感知器分类器" value="5"></el-option>
+                  <el-option key="6" label="朴素贝叶斯" value="6"></el-option>
+                  <el-option key="7" label="随机森林回归" value="7"></el-option>
+                  <el-option key="8" label="K-均值" value="8"></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>
+<!--              <router-link to="modelList">-->
+<!--              <el-button type="success" icon="el-icon-plus"  style="position: absolute;right: 25em">所有配置</el-button>-->
+<!--              </router-link>-->
+<!--                <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>-->
+            </div>
+            <el-table
+                :data="tableData" border class="table" ref="multipleTable"
+                header-cell-class-name="table-header"
+                @selection-change="handleSelectionChange"
+                @row-dblclick="getConfigDetail"
+            >
+                <el-table-column prop="confName" label="配置名"></el-table-column>
+                <el-table-column label="模型类别">
+                    <template #default="scope">{{ scope.row.modelTypeName }}</template>
+                </el-table-column>
+              <el-table-column prop="fileName" label="文件名"></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 label="操作" width="180" align="center">
+                    <template #default="scope">
+
+                      <router-link :to="{path:'/ConfigDetail',query:{configId:scope.row.configId}}">
+                        <el-button type="text" icon="el-icon-view" >查看详情
+                        </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-radio-group v-model="modelSty.resource">
+                  <el-radio label="分类"></el-radio>
+                  <el-radio label="聚类"></el-radio>
+                  <el-radio label="回归"></el-radio>
+                  <el-radio label="自动化分类器"></el-radio>
+                  </el-radio-group>
+                </el-form-item>
+
+                <el-form-item label="特征选择方式" required>
+<!--                    <el-checkbox v-for="f in featureList" :key="f" :label="f"></el-checkbox>-->
+                  <el-radio-group v-model="featureSty.resource">
+                    <el-radio label="手动选择"></el-radio>
+                    <el-radio label="自动选择"></el-radio>
+                  </el-radio-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="选择特征字段" 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";
+import {addConfig, deleteModelByModelId, getAllConfig} from "../api/config";
+import {useRouter} from "vue-router";
+
+export default {
+    name: "config",
+    //训练特征
+  // data(){
+  //     return{
+  //       form:{
+  //         name:"",
+  //         file:"",
+  //       }
+  //     }
+  // },
+  setup() {
+    const featureSty = reactive({
+
+      resource: "小天才",
+
+    });
+    const modelSty = reactive({
+
+      resource: "小天才",
+
+    });
+        const query = reactive({
+            file: "",
+            name: "",
+            pageIndex: 1,
+            pageSize: 10,
+        });
+
+        //new TODO
+        const typeList=["所有","分类","聚类","回归","自动分类器"];
+        const featureList=["所有","手动选择","自动选择"];
+        const multipleSelection =ref([]);
+
+        // const tableData = ref([]);
+    const tableData = ref([
+      ]);
+
+        const pageTotal = ref(0);
+        // 获取表格数据
+
+    const getpage=()=> {
+      // console.log("getpage");
+      getAllConfig({
+        uid: 1
+      }).then(res => {
+        console.log("res",res);
+        tableData.value = res.data;
+
+      })
+    };
+     getpage();
+
+
+
+    // 查询操作
+        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);
+                  console.log("删除");
+                  let idx=tableData.value[index].configId;
+                  console.log(idx);
+                  deleteModelByModelId(idx
+                  ).then(res=>{
+                    //console.log("deleteres",res);
+                    if(res.status===200){
+                      location.reload();
+                    }
+                  });
+
+                })
+                .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 getConfigDetail=(row,column,event)=>{
+          var configId=row.configId;
+         let router=useRouter()
+          router.push(`/ConfigDetail?configId=${configId}`)
+        }
+        // 表格编辑时弹窗和保存
+        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];
+            // });
+          // console.log("here",featureSty.resource);
+          // const { , ,confName , fieldIds} = payload;
+
+          addConfig({
+            fileInfoId:form.file,
+            userId:0,
+            modelTypeId:modelSty.resource,
+            confName:form.name,
+            fieldIds:featureSty.resource
+            }).then(res=>{
+              console.log(res);
+            });
+        };
+
+        return {
+            query,
+            tableData,
+            pageTotal,
+            editVisible,
+            form,
+            handleSearch,
+            handlePageChange,
+            handleDelete,
+          handleSelectionChange,
+            handleBatchDelete,
+            handleEdit,
+            saveEdit,
+          getConfigDetail,
+            featureSty,
+          modelSty,
+          getpage,
+        };
+    },
+};
+</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>

+ 390 - 0
src/views/ModelList.vue

@@ -0,0 +1,390 @@
+<template>
+  <div class="">
+    <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-option key="5" label="多层感知器分类器" value="5"></el-option>
+          <el-option key="6" label="朴素贝叶斯" value="6"></el-option>
+          <el-option key="7" label="随机森林回归" value="7"></el-option>
+          <el-option key="8" label="K-均值" value="8"></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>
+      </div>
+      <el-table
+          :data="tableData" border class="table" ref="multipleTable"
+          header-cell-class-name="table-header"
+          @selection-change="handleSelectionChange"
+          @row-dblclick="getConfigDetail"
+      >
+        <el-table-column prop="modelName" label="模型名"></el-table-column>
+        <el-table-column prop="configName" label="配置名"></el-table-column>
+        <el-table-column label="模型类别">
+          <template #default="scope">{{ scope.row.modelTypeName }}</template>
+        </el-table-column>
+        <el-table-column prop="arguments" label="参数值">
+          <template #default="scope">
+            <div v-for="(item,index) in scope.row.arguments" :key="index">{{item}}</div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="trainedStatus" label="训练状态">
+          <template #default="scope">
+            <div v-if="scope.row.trainedStatus==='已训练'" >
+              <el-button type="text" icon="el-icon-video-play" class="yellow"
+                         @click="handleTrainRes(scope.$index, scope.row)">查看训练结果</el-button>
+            </div>
+            <div v-else>
+              <el-button type="text" icon="el-icon-video-play" class="green"
+                       @click="handleTrain(scope.$index, scope.row)">模型训练</el-button>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="180" align="center">
+          <template #default="scope">
+
+              <el-button type="text" icon="el-icon-mouse" 
+              @click="editUseModel(scope.$index, scope.row)">模型使用
+              </el-button>
+            <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
+        v-model="useModelVisible"
+        title="模型使用"
+        width="30%"
+        :before-close="handleClose"
+      >
+            <el-form :model="useform" width="300px">
+              <el-form-item label="选择文件" >
+                <el-select v-model="useform.file" :label-width="formLabelWidth" placeholder="请选择您要使用的文件">
+                  <el-option
+                    v-for="item in fileList.valueOf()"
+                    :key="item.fileId"
+                    :label="item.fileName"
+                    :value="item.fileId"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-form>
+        <template #footer>
+          <span class="dialog-footer">
+            <el-button @click="useModelVisible = false">取消</el-button>
+            <router-link :to="{path:'/charts',query:{fileId:useform.file,modelId:usemodelId}}">
+            <el-button type="primary" 
+            @click="useModel()"
+              >使用模型</el-button
+            >
+            </router-link>
+          </span>
+        </template>
+      </el-dialog>
+
+  </div>
+
+</template>
+
+<script>
+import { ref, reactive } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import {getAllModel,train,use} from "../api/model";
+import {GetAllFile} from "../api/file";
+import {useRoute, useRouter} from "vue-router";
+
+export default {
+  name: "model",
+  setup() {
+    const useModelVisible = ref(false)
+    const formLabelWidth='120px';
+    const featureSty = reactive({
+
+      resource: "小天才",
+
+    });
+    const modelSty = reactive({
+
+      resource: "小天才",
+
+    });
+    const query = reactive({
+      file: "",
+      name: "",
+      pageIndex: 1,
+      pageSize: 10,
+    });
+
+    const fileList=ref();
+
+    const typeList=["所有","分类","聚类","回归","自动分类器"];
+    const featureList=["所有","手动选择","自动选择"];
+    const multipleSelection =ref([]);
+
+    // const tableData = ref([]);
+    const tableData = ref();
+
+    const pageTotal = ref(0);
+    // 获取表格数据
+
+    const getpage=()=> {
+      // console.log("getpage");
+      const uid=1;
+      GetAllFile(uid).then(res=>{
+        fileList.value=res.data;
+      })
+      getAllModel(
+        uid
+      ).then(res => {
+        console.log("res",res);
+        tableData.value = res.data;
+        pageTotal.value=tableData.value.length
+        for(let i=0;i<tableData.value.length;i++) {
+          const reg=new RegExp("\"","g");
+          tableData.value[i].arguments = ((JSON.stringify(tableData.value[i].arguments))+"")
+              .replace(reg,"")
+              .replace("{","")
+              .replace("}","")
+              .split(",");
+          if(tableData.value[i].trainedStatus===1){
+            tableData.value[i].trainedStatus="已训练";
+          }else{
+            tableData.value[i].trainedStatus="未训练";
+          }
+        }
+        const route=useRoute()
+
+      })
+    };
+    getpage();
+    // 查询操作
+    const handleSearch = () => {
+      query.pageIndex = 1;
+      getData();
+    };
+    // 分页导航
+    const handlePageChange = (val) => {
+      query.pageIndex = val;
+      getData();
+    };
+    //todo模型训练
+    const handleTrain = (index) => {
+      ElMessageBox.confirm("要进行训练吗?", "提示", {
+        type: "info",
+      })
+          .then(() => {
+            console.log(tableData)
+            let modelId=tableData.value[index].modelId
+            train(modelId).then(res=>{
+              if(res.status===200)
+                ElMessage.success("模型"+modelId+"训练成功");
+              else
+                ElMessage.error("模型"+modelId+"失败");
+            })
+
+
+          })
+          .catch(() => {});
+    };
+    const modelRes=ref();
+    const resVisible = ref(false);
+    const handleTrainRes = (index) => {
+      const reg=new RegExp("\"","g");
+     modelRes.value= ((JSON.stringify(tableData.value[index].resOfModel)+"")
+            .replace(reg,"")
+            .replace("{","")
+            .replace("}","")
+            .replace("[","")
+            .split(","))
+      let str=""
+      for(let i=0;i<modelRes.value.length;i++){
+        str=str+modelRes.value[i]
+        str=str+"\n"
+      }
+       ElMessageBox.confirm(tableData.value[index].resOfModel)
+
+      }
+
+
+
+const usemodelId=ref();
+    //todo模型使用
+     const editUseModel = (index) => {
+      console.log(useModelVisible)
+      useModelVisible.value=true;
+      usemodelId.value=tableData.value[index].modelId
+    };
+
+    let useform = reactive({
+      file: "",
+    });
+        //todo模型使用
+     const useModel = (data) => {
+      console.log("模型使用")
+      useModelVisible.value=false;
+      console.log(useform.file+" "+usemodelId)
+      // use() todo
+       var data={
+        modelId:usemodelId,
+         fileId:useform.file
+       }
+       // use(data).then(res=>{
+       //   console.log(res.data);
+       // })
+       const router=useRouter()
+       const fileId=useform.file
+
+      ElMessageBox.alert("成功使用模型,快去查看结果吧",{type:"success"})
+    };
+
+    // 删除操作(单个)
+    const handleDelete = (index) => {
+      // 二次确认删除
+      ElMessageBox.confirm("确定要删除吗?", "提示", {
+        type: "warning",
+      })
+          .then(() => {
+            // ElMessage.success("删除成功");
+            // tableData.value.splice(index, 1);
+            console.log("删除");
+            let idx=tableData.value[index].id;
+            console.log(idx);
+
+          })
+          .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;
+    };
+
+    return {
+      usemodelId,
+      query,
+      tableData,
+      pageTotal,
+      fileList,
+      useModelVisible,
+      formLabelWidth,
+      editVisible,
+      form,
+      useform,
+      handleSearch,
+      handlePageChange,
+      handleTrain,
+      editUseModel,
+      useModel,
+      handleDelete,
+      handleSelectionChange,
+      handleBatchDelete,
+      handleEdit,
+      featureSty,
+      modelSty,
+      getpage,
+      handleTrainRes
+    };
+  },
+};
+</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;
+}
+.green {
+  color: rgb(32, 220, 88)
+}
+.yellow{
+  color:yellowgreen;
+}
+.mr10 {
+  margin-right: 10px;
+}
+.table-td-thumb {
+  display: block;
+  margin: auto;
+  width: 40px;
+  height: 40px;
+}
+</style>

+ 188 - 0
src/views/changeConfig.vue

@@ -0,0 +1,188 @@
+<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";
+import {changeConfig} from "../api/config";
+import router from "./unused/router";
+import {useRoute} from "vue-router";
+// import router from "../router";
+export default {
+  name: "configformp",
+
+  setup() {
+    // console.log(this.$route);
+    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: [],
+    });
+    // 提交
+    // let configid=this.$route;
+    const route=useRoute();
+    const onSubmit = () => {
+      // 表单校验
+      console.log("yes");
+      formRef.value.validate((valid) => {
+        if (valid) {
+          // console.log(form);
+          // console.log("route",router);
+          changeConfig({
+            configId:route.params.id,
+
+            confName:form.name,
+
+          })
+          ElMessage.success("提交成功!");
+        } else {
+          return false;
+        }
+      });
+    };
+    // 重置
+    const onReset = () => {
+      formRef.value.resetFields();
+    };
+
+    return {
+      options,
+      rules,
+      formRef,
+      form,
+      onSubmit,
+      onReset,
+    };
+  },
+
+};
+</script>

+ 190 - 0
src/views/file/FileAnalysis.vue

@@ -0,0 +1,190 @@
+<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" style="width: 900px;height:900px;">
+      <div class="handle-box" v-show="distributionVisible">
+        <el-table :data="distributionData" border class="table"  header-cell-class-name="table-header">
+          <el-table-column label="字段值">
+            <template #default="scope"><span>{{ scope.row.key }}</span></template>
+          </el-table-column>
+          <el-table-column label="统计值">
+            <template #default="scope"><span>{{ scope.row.statistical }}</span></template>
+          </el-table-column>
+          <el-table-column label="分布">
+            <template #default="scope"><span>{{ scope.row.distribution }}</span></template>
+          </el-table-column>
+        </el-table>
+      </div>
+      <div class="handle-box" v-show="ScatterVisible" id="echarts_box" style="width: 100%;height:100%;">
+
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import {ref} from "vue";
+import {analysisFile} from "../../api/file";
+import {ElMessageBox} from "element-plus";
+import {useRoute} from "vue-router";
+import {useRouter} from "vue-router";
+import * as echarts from 'echarts';
+import 'echarts-gl';
+
+export default {
+  name: "FileAnalysis",
+  setup(){
+    let fieldIds="";
+    let funcId="";
+    let distributionData=[];
+    let distributionVisible=false;
+    let ScatterVisible=false;
+
+    const transferData=(res,d)=>{
+      let ans=[];
+      let size=0;
+      for (var key in res){
+        size=res[key].length;
+        break;
+      }
+      for (var i=0;i<size;i++){
+        let list=[];
+        for (var key in res){
+          list.push((res[key])[i]);
+        }
+        ans.push(list);
+      }
+      return ans;
+    };
+
+    const paint_2d=(res,fields)=>{
+      var data=transferData(res,2);
+      console.log(data);
+
+      var chartDom = document.getElementById('echarts_box');
+      var myChart = echarts.init(chartDom);
+      var option = {
+        xAxis: {},
+        yAxis: {},
+        series: [
+          {
+            symbolSize: 10,
+            data: data,
+            type: 'scatter'
+          }
+        ]
+      };
+      option && myChart.setOption(option);
+    };
+
+    const paint_3d=(res,fields)=> {
+      var data=transferData(res,3);
+      console.log(data);
+      var chartDom = document.getElementById('echarts_box');
+      var myChart = echarts.init(chartDom,'light');
+      var option = {
+        grid3D: {},
+        xAxis3D: {},
+        yAxis3D: {},
+        zAxis3D: {},
+        series: [{
+          symbolSize: 10,
+          type: 'scatter3D',
+          data: data
+        }]
+      };
+      option && myChart.setOption(option);
+    };
+
+    const getAnalysisData = () =>{
+      const route=useRoute();
+      if (route.query.fieldIds!=null) fieldIds=route.query.fieldIds;
+      if (route.query.funcId!=null) funcId=route.query.funcId;
+
+      console.log(fieldIds)
+      console.log(funcId)
+      if (funcId=="1") {
+        distributionVisible=true;
+      }else {
+        ScatterVisible=true;
+      }
+
+      analysisFile(fieldIds,funcId).then(res=>{
+          console.log(res.data)
+          if (res.status!=200){
+            ElMessageBox.confirm("分析产生错误,请检查您的分析方法和字段选择是否合理", "错误", {
+              type: "error",
+            }).then(()=>{
+                //todo:回到上一界面
+              router.back();
+              })
+              .catch(() => {});
+          }else {
+            //todo:
+            var fieldArr=(JSON.parse(fieldIds));
+            switch(funcId){
+              case "1":
+                var id=fieldArr[0];
+                var str1=id+"_distribution";
+                var str2=id+"_statistical";
+                //console.log(str1);
+                //console.log(str2);
+                var distr=res.data[str1];
+                var statis=res.data[str2];
+                console.log(distr);
+                console.log(statis);
+                for (var key in statis){
+                  var value1=statis[key];
+                  var value2=distr[key];
+                  distributionData.push({key:key,statistical:value1,distribution:value2});
+                }
+                console.log(distributionData);
+                break;
+              case "2":
+                var size=fieldArr.length;
+                console.log(size);
+                switch (size){
+                  case 1:
+                    break;
+                  case 2:
+                    paint_2d(res.data,fieldArr);
+                    break;
+                  case 3:
+                    paint_3d(res.data,fieldArr);
+                    break;
+                }
+                break;
+            }
+          }
+      });
+    };
+
+    getAnalysisData();
+
+    return {
+      fieldIds,
+      funcId,
+      ScatterVisible,
+      distributionVisible,
+      distributionData,
+      getAnalysisData,
+    }
+  },
+};
+</script>
+
+<style scoped>
+.container{
+  margin-top: 10px;
+  margin: 0 auto;
+}
+.handle-box {
+  margin-bottom: 20px;
+}
+</style>

+ 458 - 0
src/views/file/FileDetail.vue

@@ -0,0 +1,458 @@
+<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" style="width:60%;">
+        <el-button plain icon="el-icon-lx-file" @click="handleFileSelect" >选择文件</el-button>
+
+        <el-button type="success" icon="el-icon-search" @click="handleAnalysis">数理分析</el-button>
+
+        <el-button type="primary" icon="el-icon-plus" @click="createConfig">生成配置文件</el-button>
+
+        <el-button type="success" icon="el-icon-thumb" @click="getFeature">自动特征选择</el-button>
+
+      </div>
+
+      <el-table :data="tableData" border class="table" ref="fieldTable" header-cell-class-name="table-header" @selection-change="handleSelectChange">
+        <el-table-column width="50" type="selection" ></el-table-column>
+        <el-table-column label="字段名">
+          <template #default="scope"><span>{{ scope.row.fieldName }}</span></template>
+        </el-table-column>
+        <el-table-column label="别名">
+          <template #default="scope">{{ scope.row.aliasName }}</template>
+        </el-table-column>
+        <el-table-column label="描述">
+          <template #default="scope">{{ scope.row.fieldDes }}</template>
+        </el-table-column>
+        <el-table-column label="取值类型">
+          <template #default="scope">{{ scope.row.fieldType }}</template>
+        </el-table-column>
+        <el-table-column label="分布类型">
+          <template #default="scope">{{ scope.row.conOrDis }}</template>
+        </el-table-column>
+        <el-table-column label="空值率">
+          <template #default="scope">{{ scope.row.nullsRatio }}</template>
+        </el-table-column>
+
+        <el-table-column label="值域" >
+          <template #default="scope">{{ scope.row.valueInfo }}</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="analysisVisible" width="50%">
+      <el-form label-width="120px">
+        <el-form-item label="分析方法" required>
+          <el-select v-model="form.type" placeholder="分析方法" class="handle-select mr10" @change="changeMethodMsg">
+            <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-option key="5" label="皮尔森相关系数" value="5"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-alert type="info"
+                  show-icon style="height: 40px;">{{methodMsg.valueOf()}}</el-alert>
+        <el-form-item label="方法和字段要求" required>
+          <text>皮尔森相关系数需要两个int/double字段,散点图可以传入2-3个字段,其他的方法只需一个字段。除了数据分布可以传入string字段,其他方法请传入int/double字段</text>
+        </el-form-item>
+        <el-form-item label="已选择字段" required>
+          <el-table :data="selectData" border class="table"  header-cell-class-name="table-header" >
+            <el-table-column label="字段名">
+              <template #default="scope"><span>{{ scope.row.fieldName }}</span></template>
+            </el-table-column>
+          </el-table>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+                <span class="dialog-footer">
+                    <el-button @click="analysisVisible = false">取 消</el-button>
+                    <el-button type="primary" @click="startAnalysis">确 定</el-button>
+                </span>
+      </template>
+    </el-dialog>
+
+    <!--数理函数分析结果-->
+    <el-dialog title="分析结果" v-model="resultVisible" width="50%">
+      <el-form label-width="120px">
+        <el-form-item label="分析方法" required>
+            {{ AnalysisMethodName[parseInt(form.type)-1] }}
+        </el-form-item>
+        <el-form-item label="已选择字段" required>
+          <el-table :data="selectData" border class="table"  header-cell-class-name="table-header" >
+            <el-table-column label="字段名">
+              <template #default="scope"><span>{{ scope.row.fieldName }}</span></template>
+            </el-table-column>
+          </el-table>
+        </el-form-item>
+        <el-form-item label="分析结果" required>
+          <el-table :data="analysisData" border class="table"  header-cell-class-name="table-header" >
+            <el-table-column label="分析指标" prop="attribute">
+              <template #default="scope"><span>{{ scope.row.attribute }}</span></template>
+            </el-table-column>
+            <el-table-column label="指标数值" prop="value">
+              <template #default="scope"><span>{{ scope.row.value }}</span></template>
+            </el-table-column>
+          </el-table>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+                <span class="dialog-footer">
+                    <el-button @click="resultVisible = false">取 消</el-button>
+                </span>
+      </template>
+    </el-dialog>
+
+    <el-dialog title="新建配置" v-model="configCreate" width="50%">
+      <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-select v-model="form.type" placeholder="模型类别" class="handle-select mr10" @change="selectModelTypeChange">
+            <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-option key="5" label="多层感知器分类器" value="5"></el-option>
+            <el-option key="6" label="朴素贝叶斯" value="6"></el-option>
+            <el-option key="7" label="随机森林回归" value="7"></el-option>
+            <el-option key="8" label="K-均值" value="8"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="已选择字段" >
+          <el-alert type="info" description="您下列选择的最后一个字段为分类模型的目标字段" v-if="featureTip===1"
+                    show-icon style="height: 40px;"></el-alert>
+          <el-alert type="info" description="k-means模型没有目标字段" v-if="featureTip===2"
+                    show-icon style="height: 40px;"></el-alert>
+          <el-table :data="selectData" border class="table"  header-cell-class-name="table-header" >
+            <el-table-column label="字段名">
+              <template #default="scope"><span>{{ scope.row.fieldName }}</span></template>
+            </el-table-column>
+          </el-table>
+        </el-form-item>
+
+      </el-form>
+      <template #footer>
+                <span class="dialog-footer">
+                    <el-button @click="configCreate = false">取 消</el-button>
+                    <el-button type="primary" @click="saveConfig">确 定</el-button>
+                </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {ref, reactive, getCurrentInstance, onMounted} from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { fetchData } from "../../api";
+import {getFileDetail,analysisFile} from "../../api/file";
+import {useRoute}from "vue-router";
+import {useRouter}from "vue-router";
+import { toRaw } from '@vue/reactivity'
+import {addConfig,getFeatureSelection} from "../../api/config";
+
+export default {
+  name: "config",
+  //训练特征
+  setup() {
+    const router=useRouter();
+    const methodMsg=ref("不同方法仅适用于特定特征字段")
+    const query = reactive({
+      address: "",
+      name: "",
+      pageIndex: 1,
+      pageSize: 10,
+    });
+    let fileId;
+    let AnalysisMethodName=["数据分布","散点图","数据统计","偏度-峰度","皮尔森相关系数"];
+
+    //TODO
+    let fieldNameList=[]; //字段名
+    let aliasList=[];   //别名
+    let descList=[];      //描述
+    let aList=[];   //取值类型
+    let bList=[];   //分布类型
+    let cList=[];   //空值率
+    let dList=[];
+
+
+    const tableData = ref([]);
+    const selectData = ref([]);
+    let analysisData=reactive([])
+    const pageTotal = ref(0);
+
+    //跳转到文件列表
+    const handleFileSelect=()=>{
+      router.push('/fileList')
+    }
+
+    // 获取表格数据
+    const getData = () => {
+      const route=useRoute()
+      //todo:调用获取文件具体信息获取字段列表
+      if(route.query.fileId!=null) {
+        getFileDetail(route.query.fileId).then(res => {
+          tableData.value = res.data.headerInfos;
+          for (var i = 0; i < tableData.value.length; i++) {
+            if (tableData.value[i].conOrDis === 1) {
+              tableData.value[i].conOrDis = "连续值"
+            } else {
+              tableData.value[i].conOrDis = "离散值"
+            }
+          }
+          //console.log(tableData)
+          console.log("fileId="+route.query.fileId)
+          fileId=route.query.fileId
+        })
+      }
+
+    };
+    getData();
+    const getFeature=()=>{
+      if(selectData.value.length===0){ElMessage.error("请先选择目标字段");return;}
+      if(selectData.value.length>1){ElMessage.error("目标字段仅可选择一个");return;}
+      getFeatureSelection({"fileId":fileId,"fieldName":selectData.value[0].fieldName}).then(
+          res=>{
+            console.log(res)
+            res=res.data
+            for(let i=0;i<res.length;i++){
+              selectData.value.unshift(res[i])
+            }
+            createConfig()
+          }
+
+      )
+    }
+    // 查询操作
+    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);
+            //todo:
+          })
+          .catch(() => {});
+    };
+
+    // 表格编辑时弹窗和保存
+    let analysisVisible = ref(false);
+    let form = reactive({
+      name: "",
+      type: "",
+      // classification:"",
+      // feature:"",
+    });
+
+    let idx = -1;
+    const handleAnalysis = () => {
+      analysisVisible.value = true;
+    };
+    const changeMethodMsg=(value)=>{
+      console.log(value)
+      if(value===1){
+        methodMsg.value="数据分布无特殊限制"
+      }else if(value===2){
+        methodMsg.value="散点图可以传入2-3个int/double字段"
+      }else if(value===3){
+        methodMsg.value="请传入1个int/double字段"
+      }else if(value===4){
+        methodMsg.value="请传入1个int/double字段"
+      }else if(value===5){
+        methodMsg.value="请传入2个int/double字段"
+      }
+    }
+    const startAnalysis = () => {
+      analysisVisible.value = false;
+      //todo: 数理分析相关
+
+      console.log(form.type);
+      console.log(toRaw(selectData.value));
+      let selectList=[];
+      let fieldIds=[];
+      for (var i=0; i<selectData.value.length;i++){
+        //selectList.push(JSON.parse(JSON.stringify(selectData.value[i])))
+        fieldIds.push(selectData.value[i].id);
+        //console.log(selectData.value[i].id)
+        //console.log(selectData.value[i])
+        //console.log(JSON.parse(JSON.stringify(selectData.value[i])))
+      }
+      //console.log(selectList)
+      console.log(fieldIds);
+      if (form.type=="1"||form.type=="2"){
+        router.push({
+          path:"/FileAnalysis",
+          query:{
+            fieldIds:JSON.stringify(fieldIds),
+            funcId:form.type
+          }
+        });
+        return ;
+      };
+      analysisFile(JSON.stringify(fieldIds),form.type).then(res=>{
+        console.log(res.data)
+        if (res.status!=200){
+          ElMessageBox.confirm("分析产生错误,请检查您的分析方法和字段选择是否合理", "错误", {
+            type: "error",
+          })
+              .then(()=>{
+
+              })
+              .catch(() => {});
+        }else{
+          analysisData.length=0
+          console.log(form.type);
+          switch (form.type){
+            case "1":
+              break;
+            case "2":
+              break;
+            case "3":
+              analysisData.push({attribute:"最大值",value:res.data.frame_index.max});
+              analysisData.push({attribute:"方差",value:res.data.frame_index.variance});
+              analysisData.push({attribute:"平均值",value:res.data.frame_index.mean});
+              analysisData.push({attribute:"标准方差",value:res.data.frame_index.stddev});
+              console.log(analysisData)
+              break;
+            case "4":
+              analysisData.push({attribute:"偏度",value:res.data[fieldIds[0]].skewness});
+              analysisData.push({attribute:"峰度",value:res.data[fieldIds[0]].kurtosis});
+              console.log(analysisData)
+              break;
+            case "5":
+              analysisData.push({attribute:"皮尔森相关系数",value:res.data.Corr});
+              console.log(analysisData)
+              break;
+          }
+
+          resultVisible.value=true;
+        }
+      });
+
+      // ElMessage.success(`修改第 ${idx + 1} 行成功`);
+      // Object.keys(form).forEach((item) => {
+      //   tableData.value[idx][item] = form[item];
+      // });
+
+    };
+    let resultVisible= ref(false);
+  let featureTip=ref(0);
+    const selectModelTypeChange=(selectValue)=>{
+      if(selectValue==="8")featureTip.value=2;
+      else featureTip.value=1;
+      console.log(featureTip.value)
+    }
+    const configCreate = ref(false);
+    const createConfig =() => {
+      const fieldTable = ref(null)
+      //console.log(fieldTable)
+      console.log(selectData.value)
+      configCreate.value = true;
+    };
+    const saveConfig=()=>{
+      const route=useRoute()
+      const payload={fileInfoId:selectData.value[0].fileInfoId,userId:1, modelTypeId:form.type, confName:form.name , fieldIds:[]}
+      for(let i=0;i<selectData.value.length;i++){
+        payload.fieldIds.push(selectData.value[i].id);
+      }
+      addConfig(payload).then(res=>{
+        if(res.status===200) {
+          ElMessage.success(`已成功生成配置`);
+          configCreate.value = false;
+        }
+        else ElMessage.error(`生成配置失败`);
+      })
+      console.log(payload)
+    }
+    const handleSelectChange=val=>{
+      selectData.value=val;
+    };
+
+    return {
+      query,
+      AnalysisMethodName,
+      tableData,
+      pageTotal,
+      analysisVisible,
+      resultVisible,
+      form,
+      configCreate,
+      createConfig,
+      saveConfig,
+      getFeature,
+      selectData,
+      analysisData,
+      featureTip,
+      methodMsg,
+      selectModelTypeChange,
+      handleSelectChange,
+      handleSearch,
+      handlePageChange,
+      handleDelete,
+      handleAnalysis,
+      startAnalysis,
+      changeMethodMsg,
+      handleFileSelect,
+    };
+  },
+};
+
+
+</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>

+ 205 - 0
src/views/file/FileList.vue

@@ -0,0 +1,205 @@
+<template>
+  <div class="">
+    <div class="crumbs">
+      <el-breadcrumb separator="/">
+        <el-breadcrumb-item><i class="el-icon-lx-file"></i> 我的文件</el-breadcrumb-item>
+      </el-breadcrumb>
+    </div>
+
+    <div class="container">
+
+      <el-tabs v-model="currentTab">
+
+        <el-tab-pane :label="`我的文件`" name="first">
+          <el-table :data="state.fileList" :show-header="true" style="width: 100%">
+
+            <el-table-column label="文件名">
+              <template #default="scope">
+                <span class="message-title">{{scope.row.fileName}}</span>
+              </template>
+            </el-table-column>
+
+            <el-table-column width="240" label="操作">
+              <template #default="scope">
+                <!----------------------------todo------------------------------->
+                <!----------------------------获取文件详细信息、跳转到响应页面;删除文件------------------------------->
+                <div style="display:flex;width: 100%;justify-content:space-around;">
+                  <el-button size="small" @click="handleFileDetail(scope.row.fileId)">查看详情</el-button>
+
+                <!--  scope.$index 是数组下标,这里再传一个fileId             handleFileDelete(scope.$index,scope.row.fileId)   -->
+                  <el-button size="small" type="danger"  @click="handleDeleteDialog(scope.row.fileId);dialogVisible=true">
+                    删除文件
+                  </el-button>
+                </div>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-tab-pane>
+
+        <el-tab-pane :label="`我的图片`" name="second">
+          <el-table :data="state.picList" :show-header="true" style="width: 100%">
+            <el-table-column label="图片名">
+              <template #default="scope">
+                <span class="message-title">{{scope.row.picName}}</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="date" label="上传日期"></el-table-column>
+            <el-table-column width="240" label="操作">
+              <template #default="scope">
+                <div style="display:flex;width: 100%;justify-content:space-around;">
+                  <el-button size="small" type="primary" @click="handlePicDetail(scope.row.picId)">查看详情</el-button>
+
+                  <el-button size="small" @click="handlePicDelete(scope.$index)">删除图片</el-button>
+                </div>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-tab-pane>
+
+        <router-link to="/upload">
+          <el-button type="primary" size="large">文件上传</el-button>
+        </router-link>
+      </el-tabs>
+    </div>
+
+    <!--  对话框  -->
+    <el-dialog
+        v-model="dialogVisible"
+        title="确认删除"
+        width="30%"
+    >
+      <span>确认要删除该文件吗?</span>
+      <template #footer>
+      <span class="dialog-footer">
+        <el-button @click="dialogVisible = false;toDeleteFileId=0;">
+          取消
+        </el-button>
+        <el-button type="danger" @click="dialogVisible = false;toDeleteFileId=0;handleFileDelete()">
+          确认
+        </el-button>
+      </span>
+      </template>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import {ref, reactive,onMounted} from "vue";
+import {deleteFile, GetAllFile} from "../../api/file";
+import {useRouter} from "vue-router";
+import {ElMessage} from "element-plus";
+
+export default {
+  name: "fileList",
+  setup() {
+    const currentTab = ref("first");
+    const router = useRouter();
+
+    let userId=1;
+    let state = reactive({
+      fileList: [
+        {
+          fileId: "",
+          fileName:"",
+        },
+      ],
+      picList:[
+        {
+          date: "2018-04-19 20:00:00",
+          picId: "1",
+          picName:"图片1"
+        }
+      ],
+    });
+    let dialogVisible=ref(false);
+    let toDeleteFileId=ref(0);
+
+    //用户Id => 文件列表
+    const getFileList=(userId)=>{
+      GetAllFile(userId).then(res=>{
+        if(res.status===200){
+          state.fileList=res.data;
+        }
+        else{
+          console.log("getFileList Error!");
+          ElMessage.error("获取文件列表失败!")
+        }
+      })
+    };
+
+    //查看文件详情
+    const handleFileDetail=(fileId)=>{
+      router.push({
+        path:'fileDetail',
+        query:{
+          fileId:fileId,
+        }
+      })
+    }
+
+    //打开提示确认删除的对话框,将fileId保存下来
+    const handleDeleteDialog = (fileId)=>{
+      toDeleteFileId=fileId;
+      console.log("handleDeleteDialog")
+      console.log("fileId:"+fileId)
+      ElMessage.info("要删除的文件Id fileId:"+fileId)
+    }
+
+    //删除对应文件
+    const handleFileDelete = () => {
+      console.log("fileId:"+toDeleteFileId)
+      deleteFile(toDeleteFileId).then(res=>{
+        if(res.status===200){
+          ElMessage.success("删除成功!")
+          getFileList(userId);
+        }
+        else{
+          ElMessage.error("删除失败!错误码:"+res.status)
+        }
+      })
+    };
+
+    //todo:调用删除图片的接口,后面再做吧
+    const handlePicDelete = (index) => {
+      console.log("handlePicDelete")
+      console.log(index)
+    };
+    //todo:获取图片详情,把要查看的图片id传参
+    const handlePicDetail=(index)=>{
+      console.log("handlePicDetail")
+      console.log(index)
+    }
+
+    //初始化
+    onMounted(() => {
+      getFileList(userId);
+    })
+
+    return {
+      currentTab,
+      state,
+
+      dialogVisible,
+      toDeleteFileId,
+      handleDeleteDialog,
+
+      handleFileDetail,
+      handleFileDelete,
+      handlePicDetail,
+      handlePicDelete,
+      getFileList,
+    };
+  },
+};
+</script>
+
+<style>
+.message-title {
+  cursor: pointer;
+}
+.handle-row {
+  margin-top: 30px;
+}
+</style>
+

+ 249 - 0
src/views/file/Upload.vue

@@ -0,0 +1,249 @@
+<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>
+        <el-form
+            :model="form"
+            :rules="rules"
+            ref="formRef"
+            label-width="120px"
+        >
+          <!--   文件名:       -->
+          <el-form-item label="文件重命名" prop="fileName"  style="width: 400px;">
+            <el-input placeholder="在此填写上传后的文件名" v-model="form.fileName">
+              <template #append>.csv</template>
+            </el-input>
+          </el-form-item>
+
+          <el-form-item label="上传文件">
+            <!-- accept接收文件类型,auto-upload:false 关闭自动上传,drag 允许拖动,name=file,上传文件的字段名           -->
+            <!-- file-list:接收文件上传的数组,before-upload:配合accept属性,检查文件类型、后缀,before-remove:删除提醒           -->
+            <!-- on-change:获取文件,将文件保存在fileList里;limit:最多上传文件数           -->
+            <el-upload
+                ref="uploadRef"
+                accept='text/csv'
+                :auto-upload=false
+                drag
+                name="file"
+                :file-list="fileList"
+                :before-upload="beforeUploadFile"
+                :before-remove="beforeRemoveFile"
+                :on-change="getFile"
+                :on-exceed="handleExceed"
+                :limit="1"
+                class="upload-demo"
+                style="width: 500px;"
+                >
+              <div class="row-flex" style="height:100%;width:100%;">
+                <el-button icon="upload" style="border:0">点击上传或者拖拽文件上传</el-button>
+              </div>
+            </el-upload>
+
+            <span slot="tip">{{message}}</span>
+          </el-form-item>
+
+          <!--    操作:      -->
+          <el-form-item>
+            <el-button
+                type="primary"
+                @click="submitForm(formRef,uploadRef)"
+            >
+              立即创建
+            </el-button>
+
+            <el-button
+                @click="resetForm(formRef,uploadRef)"
+            >
+              重置
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { reactive, ref } from 'vue'
+import { ElMessage, ElMessageBox } from "element-plus"
+import {UploadFile} from "../../api/file";
+
+export default {
+  name: "Upload",
+  setup() {
+    //表单,不要和ref重名
+    const form= reactive({
+      fileName: '',
+    });
+    //DOM元素
+    const formRef=ref('formRef');
+    const uploadRef=ref('upload');
+    const message= '请上传csv格式的文件';
+    //文件列表
+    let fileList= [];
+    //用于放数据  FormData类型
+    let formData= new FormData();
+
+    //校验规则
+    const rules = reactive({
+      fileName:
+          [
+            {
+              max:64,
+              message: '文件名最多64个字符!',
+              trigger:  'blur',
+            },
+            {
+              required: true,
+              message: '必须填写文件名!',
+              trigger:  'blur',
+            }
+          ]
+    })
+
+    //————————————————————————————————方法区——————————————————————————————————————————————
+
+    //文件上传后,保存在数组fileList里
+    function getFile(file, files) {
+      fileList = files;
+    }
+
+    //提交表单
+    const submitForm = async (formEl,uploadEl) => {
+      if (!formEl || !uploadEl) return
+      await formEl.validate((valid, fields) => {
+        if (valid) {
+          if (fileList.length <= 0) {
+            ElMessage.error("请先上传1个文件!");
+            return;
+          }
+
+          //将表单内其他内容添加进formData
+          formData.append('fileName', form.fileName+'.csv')
+          formData.append('file', fileList[0].raw);
+          formData.append('userId', "1")
+
+          //调用接口,提交即可
+          ElMessage.success('文件名校验成功!请求已发送,请稍候.')
+          UploadFile(formData).then(res => {
+            console.log(res)
+            fileList=[]
+            formEl.resetFields()
+            uploadEl.clearFiles()
+            if (res.status === 200)
+            {
+              ElMessageBox({
+                title: '文件上传',
+                message: `文件: ${form.fileName}上传成功`,
+                confirmButtonText: '确定',
+                beforeClose: (action, instance, done) => {
+                  if (action === 'confirm') {
+                    instance.confirmButtonLoading = true
+                    instance.confirmButtonText = 'Loading...'
+                    setTimeout(() => {
+                      instance.confirmButtonLoading = false
+                      done()
+                    } ,200)
+                  } else {
+                    done()
+                  }
+                },
+              })
+            }
+            else
+              {
+                ElMessage.error("上传失败!失败码:"+res.status);
+              }
+          })
+        }
+        else {
+          ElMessage.error('校验失败!')
+          console.log(fields)
+        }
+      })
+    }
+
+    //重置表单
+    function resetForm(formEl,uploadEl){
+      fileList=[]
+      if (!formEl || !uploadEl) return
+      formEl.resetFields()
+      uploadEl.clearFiles()
+    }
+
+    //判断后缀是否符合要去
+    function isFileExtensionRight(extension){
+      return extension === 'csv' || extension === 'sas';
+    }
+
+    //上传前,配合accept属性,检查文件类型、后缀
+    function beforeUploadFile(file) {
+      let extension = file.name.substring(file.name.lastIndexOf('.') + 1);
+      if (isFileExtensionRight(extension)) {
+        ElMessage.warning('文件类型不对,目前只接受csv类型的文件'); //控制文件类型
+        return false
+      }
+    }
+
+    //移除文件时的提醒
+    function beforeRemoveFile(file) {
+      let extension = file.name.substring(file.name.lastIndexOf('.') + 1);
+      if (!isFileExtensionRight(extension)) return;
+
+      return ElMessageBox({
+        title: '移除待上传文件?',
+        message: `确定要删除文件: ${file.name} 吗?`,
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        beforeClose: (action, instance, done) => {
+          if (action === 'confirm') {
+            instance.confirmButtonLoading = true
+            instance.confirmButtonText = 'Loading...'
+            setTimeout(() => {
+              done()
+              setTimeout(() => {
+                instance.confirmButtonLoading = false
+              }, 125)
+            }, 125)
+          } else {
+            done()
+          }
+        },
+      })
+    }
+
+    //超限制
+    function handleExceed(files, fileList) {
+      ElMessage.warning("目前只能上传一个包")
+    }
+
+    return{
+      form,
+      rules,
+      message,
+      fileList,
+      formRef,
+      uploadRef,
+      submitForm,
+      resetForm,
+      getFile,
+      beforeUploadFile,
+      beforeRemoveFile,
+      handleExceed,
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 489 - 0
src/views/square.vue

@@ -0,0 +1,489 @@
+<template>
+
+  <el-container style=" height:100%;background: url(src/assets/img/earth.jpg) " direction="vertical">
+    <v-header style="height: 70px" @getCollection="getCollection()" @getMine="getMine()"></v-header>
+    <el-main>
+      <el-row :gutter="20" style="width: 100%;height: 200px">
+        <el-col :span="8" :offset="8">
+          <div class="grid-content" style="margin-top: 70px;">
+            <el-input placeholder="请输入内容" v-model="input" class="searchClass">
+              <template #append>
+                <el-button icon="el-icon-search" @click="handleSearch()"/>
+              </template>
+            </el-input>
+          </div>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20" style="width: 100%;">
+        <el-col :span="8" :offset="7">
+          <div class="postList" style="width: 800px;">
+            <div style="" v-for="(post, index) in postList" :key="post.postId"
+                 v-show="index >= (currentPage-1)*8 && index < currentPage*4">
+              <el-card shadow="hover"
+                       style="height: 120px; margin-bottom: 5px; border-radius: 10px; background-color: #262626">
+                <div class="taskTitle">
+                  <span style="font-size: 18px; font-weight: bold;color: #eeeeee">{{ post.title }}</span>
+                  <el-button type="text" style="margin-left: 15px; margin-right: 15px; color: #000000">
+                    {{ post.update_time }}
+                  </el-button>
+                </div>
+                <div class="desciption">
+                  <div class="ellipsis-line" style="font-size: 14px; width: 800px; float: left;color: #dbd0d0">
+                    {{ post.content }}
+                  </div>
+                  <div style="font-size: 5px; width: 150px;float: left;color: #dbd0d0;margin-top: 10px">
+                    <i class="el-icon-thumb" style="color: white ;"></i>
+                    {{ post.praise }}
+                    <i class="el-icon-chat-line-round" style="color: white"></i>
+                    {{ post.comment_num }}
+                    <i class="el-icon-time" style="color: white ;"></i>
+                    {{ post.updateTime }}
+                  </div>
+                  <el-button style="float: right;" size="small" type="warning" @click="handlePostDetail(post.postId)"
+                             round>查看详情
+                  </el-button>
+                </div>
+
+              </el-card>
+            </div>
+            <el-pagination
+                layout="prev, pager, next"
+                :total="pages"
+                style="float: right; margin-top: 10px; padding-bottom: 20px;"
+                :current-page.sync="currentPage"
+                background>
+            </el-pagination>
+          </div>
+        </el-col>
+      </el-row>
+    </el-main>
+  </el-container>
+  <el-dialog :title="title" v-model="collectionDetailVisble" min-width="30%" width="66%" style="">
+    <span style="font-size: 18px; font-weight: bold;color: black;">{{ currentPost.content }}</span>
+    <el-form ref="formRef" label-width="120px">
+      <el-form-item label="模型类型名:" >
+        {{config.modelTypeName}}
+      </el-form-item>
+      <el-form-item label="模型描述:" >
+        {{config.modelDes}}
+      </el-form-item>
+      <el-form-item label="模型详情:" >
+        {{}}
+      </el-form-item>
+      <el-form-item label="特征字段:" >
+        <el-table :data="tableData" border class="table"  ref="fieldTable" header-cell-class-name="table-header" @selection-change="">
+          <el-table-column label="字段名" width="120%">
+            <template #default="scope"><span>{{ scope.row.fieldName }}</span></template>
+          </el-table-column>
+          <el-table-column label="别名">
+            <template #default="scope">{{ scope.row.aliasName }}</template>
+          </el-table-column>
+          <el-table-column label="描述">
+            <template #default="scope">{{ scope.row.fieldDes }}</template>
+          </el-table-column>
+          <el-table-column label="取值类型">
+            <template #default="scope">{{ scope.row.fieldType }}</template>
+          </el-table-column>
+          <el-table-column label="分布类型">
+            <template #default="scope">{{ scope.row.conOrDis }}</template>
+          </el-table-column>
+          <el-table-column label="空值率">
+            <template #default="scope">{{ scope.row.nullsRatio }}</template>
+          </el-table-column>
+
+          <el-table-column label="值域" width="150%">
+            <template #default="scope">{{ scope.row.valueInfo }}</template>
+          </el-table-column>
+        </el-table>
+      </el-form-item>
+
+      <el-form-item label="模型列表:" >
+        <el-table :data="modelData" border class="table" ref="fieldTable" header-cell-class-name="table-header" @selection-change="">
+          <el-table-column label="模型名" width="150%">
+            <template #default="scope"><span>{{ scope.row.modelName }}</span></template>
+          </el-table-column>
+          <el-table-column label="模型类别" width="150%">
+            <template #default="scope">{{ scope.row.modelDetailName }}</template>
+          </el-table-column>
+          <el-table-column label="训练结果">
+            <template #default="scope" >
+              <div v-if="scope.row.trainedStatus===-1">accuracy:0.87</div>
+              <div v-else="">已训练</div></template>
+          </el-table-column>
+        </el-table>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary"  @click="">添加到我的配置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-collapse >
+    <el-collapse-item name="1" title="评论">
+    <div style="margin-top: 20px;border:2px solid #a6a9ad;box-shadow: 0 0 5px rgba(0,0,0,.1);padding: 5px;">
+    <v-write-comment :width="500" :post-id="currentPost.postId" style="margin-left: 250px" >
+    </v-write-comment>
+    <v-comments :comment-list="commentList" :width="800" style="margin-top: 5px;margin-left: 160px"></v-comments>
+    </div>
+    </el-collapse-item>
+      <el-collapse-item title="写信给作者————更加快捷" name="2">
+        <div style="width: 600px;margin-left: 250px">
+        <el-input
+            type="textarea"
+            autosize
+            placeholder="标题"
+            v-model="mailTitle">
+        </el-input>
+        <div style="margin: 20px 0;"></div>
+        <el-input
+            type="textarea"
+            :autosize="{ minRows: 3, maxRows: 5}"
+            placeholder="正文"
+            v-model="mailContent">
+        </el-input>
+          <el-button type="danger" icon="el-icon-message" big circle style="margin-left: 600px;" @click="sendMailTo()"></el-button>
+        </div>
+      </el-collapse-item>
+    </el-collapse>
+
+      <template #footer>
+                <span class="dialog-footer">
+                    <el-button @click="detailVisble = false">取 消</el-button>
+                    <el-button type="primary" @click="saveEdit">确 定</el-button>
+                </span>
+    </template>
+  </el-dialog>
+  <el-dialog :title="title" v-model=" squareDetailVisble" min-width="30%" width="66%" style="">
+    <span style="font-size: 18px; font-weight: bold;color: black;">{{ currentPost.content }}</span>
+    <el-form ref="formRef" label-width="120px">
+      <el-form-item label="模型类型名:" >
+        {{config.modelTypeName}}
+      </el-form-item>
+      <el-form-item label="模型描述:" >
+        {{config.modelDes}}
+      </el-form-item>
+      <el-form-item label="模型详情:" >
+        {{}}
+      </el-form-item>
+      <el-form-item label="特征字段:" >
+        <el-table :data="tableData" border class="table"  ref="fieldTable" header-cell-class-name="table-header" @selection-change="">
+          <el-table-column label="字段名" width="120%">
+            <template #default="scope"><span>{{ scope.row.fieldName }}</span></template>
+          </el-table-column>
+          <el-table-column label="别名">
+            <template #default="scope">{{ scope.row.aliasName }}</template>
+          </el-table-column>
+          <el-table-column label="描述">
+            <template #default="scope">{{ scope.row.fieldDes }}</template>
+          </el-table-column>
+          <el-table-column label="取值类型">
+            <template #default="scope">{{ scope.row.fieldType }}</template>
+          </el-table-column>
+          <el-table-column label="分布类型">
+            <template #default="scope">{{ scope.row.conOrDis }}</template>
+          </el-table-column>
+          <el-table-column label="空值率">
+            <template #default="scope">{{ scope.row.nullsRatio }}</template>
+          </el-table-column>
+
+          <el-table-column label="值域" width="150%">
+            <template #default="scope">{{ scope.row.valueInfo }}</template>
+          </el-table-column>
+        </el-table>
+      </el-form-item>
+
+      <el-form-item label="模型列表:" >
+        <el-table :data="modelData" border class="table" ref="fieldTable" header-cell-class-name="table-header" @selection-change="">
+          <el-table-column label="模型名" width="150%">
+            <template #default="scope"><span>{{ scope.row.modelName }}</span></template>
+          </el-table-column>
+          <el-table-column label="模型类别" width="150%">
+            <template #default="scope">{{ scope.row.modelDetailName }}</template>
+          </el-table-column>
+          <el-table-column label="训练结果">
+            <template #default="scope" >
+              <div v-if="scope.row.trainedStatus===-1">accuracy:0.87</div>
+              <div v-else="">已训练</div></template>
+          </el-table-column>
+        </el-table>
+      </el-form-item>
+    </el-form>
+    <v-comments :comment-list="commentList" :width="800" style="margin-top: 20px;border:2px solid #a6a9ad;box-shadow: 0 0 5px rgba(0,0,0,.1);padding: 5px;"></v-comments>
+    <template #footer>
+                <span class="dialog-footer">
+                    <el-button @click="detailVisble = false">取 消</el-button>
+                    <el-button type="primary" @click="collect(currentPost.postId)">收藏</el-button>
+                </span>
+    </template>
+  </el-dialog>
+</template>
+
+<script>
+import vHeader from "../components/SquareHeader.vue";
+import {searchPost, getPostByPostId, getUserCollection, getUserPost,collection} from "../api/posts";
+import {getComment} from "../api/comment";
+import {sendMail} from "../api/mail";
+import {ref, reactive} from "vue";
+import {getFileDetail} from "../api/file";
+import vComments from "../components/Comments.vue"
+import vWriteComment from "../components/WriteComment.vue"
+import {getOneConfig} from "../api/config";
+
+export default {
+  setup() {
+    const collectionDetailVisble = ref(false);
+    const squareDetailVisble = ref(false);
+    const tableData = ref([])
+    return {collectionDetailVisble, tableData, squareDetailVisble};
+  },
+  components: {
+    vHeader, vComments,
+    vWriteComment
+  },
+  data() {
+    return {
+      input: '',
+      select: '',
+      src: "src/assets/img/earth.jpg",
+      fit: 'cover',
+      postList: [],
+      currentPage: 1,
+      title: "12121",
+      currentPost: null,
+      commentList: [],
+      currentState: 0,
+      mailTitle:"",
+      mailContent:"",
+      config: null,
+      modelData:null
+    };
+  },
+
+  methods: {
+    sendMailTo(){
+      sendMail({"title":this.mailTitle,"fromUserId":1,"toUserId":this.currentPost.userId,"content":this.mailContent}).then(res=>{
+        if(res.success){
+          this.$message({
+            message: '发送成功!',
+            type: 'success'
+          });
+          this.mailContent=""
+          this.mailTitle=""
+        }
+        else{
+          this.$message({
+            message: '发送失败!',
+            type: 'fail'
+          });
+        }
+      })
+    },
+    collect(postId){
+      collection({"userId":1,"postId":postId}).then(res =>
+      {
+        if(res.success){
+          this.$message({
+            message: '收藏成功!',
+            type: 'success'
+          });
+        }
+      })
+    },
+    handleSearch() {
+      console.log("doing")
+      searchPost({
+        keyword: this.input,
+        flagList: "",
+        userId: 0
+      }).then(res => {
+        this.postList = res.object
+        console.log(this.postList)
+        this.currentState = 0
+      })
+    },
+    handleCollectionDetail(postId) {
+      const data = ref([])
+      getPostByPostId({"postId": postId}).then(res => {
+        const postDetail = res.object
+        const fileId = postDetail.shareFileList[0]
+        this.currentPost = postDetail
+        this.title = postDetail.title
+
+        getComment({"userId": 1}).then(res => {
+          if (fileId != null) {
+            getOneConfig({"configId":this.currentPost.configId}).then(res => {
+              this.config=res.data
+              data.value=res.data.featureList
+              this.modelData=res.data.modelInfos
+              for (var i = 0; i < data.value.length; i++) {
+                if (data.value[i].conOrDis === 1) {
+                  data.value[i].conOrDis = "连续值"
+                } else {
+                  data.value[i].conOrDis = "离散值"
+                }
+              }
+              this.tableData = data
+              console.log(data)
+              console.log("fileId=" + fileId)
+              this.collectionDetailVisble = true
+            })
+          }
+          this.commentList = res.object
+          console.log(this.commentList)
+        })
+
+      })
+    },
+    handleSearchDetail(postId) {
+      const data = ref([])
+      getPostByPostId({"postId": postId}).then(res => {
+        const postDetail = res.object
+        const fileId = postDetail.shareFileList[0]
+        this.currentPost = postDetail
+        this.title = postDetail.title
+        getComment({"userId": 1}).then(res => {
+          if (fileId != null) {
+            getOneConfig({"configId":this.currentPost.configId}).then(res => {
+              this.config=res.data
+              data.value=res.data.featureList
+              this.modelData=res.data.modelInfos
+              for (var i = 0; i < data.value.length; i++) {
+                if (data.value[i].conOrDis === 1) {
+                  data.value[i].conOrDis = "连续值"
+                } else {
+                  data.value[i].conOrDis = "离散值"
+                }
+              }
+              this.tableData = data
+              this.squareDetailVisble = true
+              console.log(data)
+              console.log("fileId=" + fileId)
+            })
+          }
+          this.commentList = res.object
+          console.log(this.commentList)
+        })
+      })
+    },
+
+    handlePostDetail(postId) {
+      console.log("ddd")
+      if (this.currentState == 1) {
+        this.handleCollectionDetail(postId)
+      }
+      if (this.currentState == 0) {
+        this.handleSearchDetail(postId)
+      }
+
+    },
+
+    getCollection() {
+      getUserCollection({userId: 0}).then(
+          res => {
+            this.postList = res.object
+            console.log(this.postList)
+            this.currentState = 1
+          }
+      )
+    },
+    getMine() {
+      getUserPost({userId: 0}).then(
+          res => {
+            this.postList = res.object
+            console.log(this.postList)
+            this.currentState = 2
+          }
+      )
+    }
+  }
+}
+
+
+</script>
+
+<style>
+.header {
+  color: #fff;
+
+}
+
+.el-dialog__title {
+  font-size: 26px !important;
+  font-weight: bold;
+  color: black
+}
+
+.searchClass {
+  border: 1px solid #262626;
+  border-radius: 20px;
+  background: #1f1e1e;
+  height: 50px;
+}
+
+.searchClass .el-input-group__prepend {
+  border: none;
+  background-color: transparent;
+  padding: 0 10px 0 30px;
+}
+
+.searchClass .el-input-group__append {
+  border: none;
+  background-color: transparent;
+}
+
+.searchClass .el-input__inner {
+  height: 50px;
+  line-height: 36px;
+  border: none;
+  background-color: transparent;
+}
+
+.searchClass .el-icon-search {
+  font-size: 16px;
+}
+
+.searchClass .centerClass {
+  height: 100%;
+  line-height: 100%;
+  display: inline-block;
+  vertical-align: middle;
+  text-align: right;
+}
+
+.searchClass .line {
+  width: 1px;
+  height: 26px;
+  background-color: #262626;
+  margin-left: 14px;
+}
+
+.searchClass:hover {
+  border: 1px solid #262626;
+  background: #262626;
+}
+
+.searchClass:hover .line {
+  background-color: #D5E3E8;
+}
+
+.searchClass:hover .el-icon-search {
+  color: #409eff;
+  font-size: 16px;
+}
+
+.el-col {
+  border-radius: 30px
+}
+
+.grid-content {
+  border-radius: 4px;
+  min-height: 36px;
+}
+
+/*.el-input__inner{*/
+/*  border-radius: 30px!important;*/
+/*  border-color: #262626!important;*/
+/*  background-color: #606266!important;*/
+/*  height: 50px!important;*/
+
+/*}*/
+</style>

+ 62 - 0
src/views/unused/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/unused/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>

+ 138 - 0
src/views/unused/BaseCharts.vue

@@ -0,0 +1,138 @@
+<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="mytTable">
+         <el-table :data="tableData" border style="width: 100%">
+         <el-table-column prop="event_type" label="目标字段" width="180" />
+        </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";
+import {useRoute} from "vue-router";
+import {use}from "../../api/model"
+
+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 = () => {
+          const route=useRoute()
+          const fileId=route.query.fileId
+          const modelId=route.query.modelId
+          console.log(fileId)
+          var data={
+            modelId:modelId,
+            fileId:fileId
+          }
+          use(data).then(res=>{
+            console.log(res.data);
+            tableData.value=res.data.data
+          })
+            console.log("getData被调用了")
+
+        };
+
+        // 相当于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/unused/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>

+ 196 - 0
src/views/unused/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: "DLForm",
+  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>

+ 139 - 0
src/views/unused/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/unused/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/unused/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/unused/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/unused/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/unused/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/unused/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>

+ 339 - 0
src/views/unused/ModelDetail.vue

@@ -0,0 +1,339 @@
+<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-option key="5" label="多层感知器分类器" value="5"></el-option>
+                  <el-option key="6" label="朴素贝叶斯" value="6"></el-option>
+                  <el-option key="7" label="随机森林回归" value="7"></el-option>
+                  <el-option key="8" label="K-均值" value="8"></el-option>
+                </el-select>
+                <!-- <el-input v-model="query.name" placeholder="模型Id" class="handle-input mr10"></el-input>
+                <el-button type="primary" icon="el-icon-search" @click="handleSearch">搜索</el-button> -->
+            </div>
+            <el-table
+                :data="tableData" border class="table" ref="multipleTable"
+                header-cell-class-name="table-header"
+                @selection-change="handleSelectionChange"
+                @row-dblclick="getConfigDetail"
+            >
+                <el-table-column width="50" type="selection"></el-table-column>
+                <el-table-column prop="confName" label="模型Id"></el-table-column>
+                <el-table-column label="模型信息">
+                    <template #default="scope">{{ scope.row.modelTypeName }}</template>
+                </el-table-column>
+              <el-table-column prop="fileName" label="待测试文件">
+                    <template #default="scope">
+                      <router-link :to="{path:'/ConfigDetail',query:{configId:scope.row.configId}}">
+                        <el-button type="text" icon="el-icon-upload" >选择文件
+                        </el-button>
+                      </router-link>
+                    </template>
+              </el-table-column>
+
+                <el-table-column label="模型训练" width="180" align="center">
+                    <template #default="scope">
+                        <el-button type="text" icon="el-icon-video-play" class="green"
+                            @click="handleDelete(scope.$index, scope.row)">模型训练</el-button> 
+                    </template>
+                </el-table-column>
+                <!-- 如果已经训练了,那么就告诉她您已经训练过该模型,但还是感觉应该放在模型配置里面,配置就可以让他进行训练! -->
+
+
+                <el-table-column label="操作" width="180" align="center">
+                    <template #default="scope">
+                        <el-button type="text" icon="el-icon-mouse" class="blue"
+                            @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-radio-group v-model="modelSty.resource">
+                  <el-radio label="分类"></el-radio>
+                  <el-radio label="聚类"></el-radio>
+                  <el-radio label="回归"></el-radio>
+                  <el-radio label="自动化分类器"></el-radio>
+                  </el-radio-group>
+                </el-form-item>
+
+                <el-form-item label="特征选择方式" required>
+<!--                    <el-checkbox v-for="f in featureList" :key="f" :label="f"></el-checkbox>-->
+                  <el-radio-group v-model="featureSty.resource">
+                    <el-radio label="手动选择"></el-radio>
+                    <el-radio label="自动选择"></el-radio>
+                  </el-radio-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="选择特征字段" 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";
+import {addConfig, deleteModelByModelId, getAllConfig} from "../../api/config";
+
+export default {
+    name: "config",
+    //训练特征
+  // data(){
+  //     return{
+  //       form:{
+  //         name:"",
+  //         file:"",
+  //       }
+  //     }
+  // },
+  setup() {
+    const featureSty = reactive({
+
+      resource: "小天才",
+
+    });
+    const modelSty = reactive({
+
+      resource: "小天才",
+
+    });
+        const query = reactive({
+            file: "",
+            name: "",
+            pageIndex: 1,
+            pageSize: 10,
+        });
+
+        //new TODO
+        const typeList=["所有","分类","聚类","回归","自动分类器"];
+        const featureList=["所有","手动选择","自动选择"];
+        const multipleSelection =ref([]);
+
+        // const tableData = ref([]);
+    const tableData = ref([
+      ]);
+
+        const pageTotal = ref(0);
+        // 获取表格数据
+
+    const getpage=()=> {
+      // console.log("getpage");
+      getAllConfig({
+        uid: 1
+      }).then(res => {
+        console.log("res",res);
+        tableData.value = res.data;
+
+      })
+    };
+     getpage();
+
+
+
+    // 查询操作
+        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);
+                  console.log("删除");
+                  let idx=tableData._rawValue[index].id;
+                  console.log(idx);
+                  deleteModelByModelId({
+                    configId:idx
+                  }).then(res=>{
+                    console.log("deleteres",res);
+                  });
+
+                })
+                .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 getConfigDetail=(row,column,event)=>{
+          var configId=row.configId;
+          //todo:双击跳转到config界面
+          console.log("跳转到config详情界面")
+        }
+        // 表格编辑时弹窗和保存
+        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];
+            // });
+          // console.log("here",featureSty.resource);
+          // const { , ,confName , fieldIds} = payload;
+
+          addConfig({
+            fileInfoId:form.file,
+            userId:0,
+            modelTypeId:modelSty.resource,
+            confName:form.name,
+            fieldIds:featureSty.resource
+            }).then(res=>{
+              console.log(res);
+            });
+        };
+
+        return {
+            query,
+            tableData,
+            pageTotal,
+            editVisible,
+            form,
+            handleSearch,
+            handlePageChange,
+            handleDelete,
+          handleSelectionChange,
+            handleBatchDelete,
+            handleEdit,
+            saveEdit,
+          getConfigDetail,
+            featureSty,
+          modelSty,
+          getpage,
+        };
+    },
+};
+</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>

+ 40 - 0
src/views/unused/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>

+ 163 - 0
src/views/unused/Upload.vue

@@ -0,0 +1,163 @@
+<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=""
+                       accept=".jpg,.png,.csv"
+                       :limit="10"
+                       :on-exceed="handleExceed"
+                       :on-remove="handleRemove"
+                       :before-remove="beforeRemove"
+                       :auto-upload="false" multiple>
+                <i class="el-icon-upload"></i>
+                <div class="el-upload__text">
+                    将文件拖到此处,或
+                    <em>点击上传</em>
+                </div>
+                <template #tip>
+                    <div class="el-upload__tip">请上传jpg/png图像文件或csv结构化文件,且不超过 500kb,一次最多上传10个文件</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";
+import { ElMessage, ElMessageBox } from "element-plus"
+
+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;
+        };
+
+        //todo:
+        const handleExceed=(files,fileList)=>{
+            console.log("handleExceed")
+            console.log(files)
+            console.log(fileList)
+            ElMessage.warning(
+              `一次最多上传10个文件, 你一次上传了${files.length}个文件`
+          )
+        }
+        const handleRemove=(file,fileList)=>{
+          console.log("handleRemove")
+          console.log(file)
+          console.log(fileList)
+        }
+      const beforeRemove = (file, filelist) => {
+        return ElMessageBox.confirm(
+            `取消上传${file.name} ?`
+        ).then(
+            () => true,
+            () => false
+        )
+      }
+        return {
+            cropper,
+            imgSrc,
+            cropImg,
+            dialogVisible,
+            setImage,
+            cropImage,
+            cancelCrop,
+            handleExceed,
+            handleRemove,
+            beforeRemove
+        };
+    },
+};
+</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>

+ 247 - 0
src/views/unused/router/index.js

@@ -0,0 +1,247 @@
+import {createRouter, createWebHashHistory} from "vue-router";
+import Home from "../Home.vue";
+import squareLayout from "../../square.vue";
+
+const routes = [
+    {
+        path: '/',
+        redirect: '/fileList'
+    },
+    {
+        path: '/square',
+        component: squareLayout,
+    },
+    {
+        path: "/",
+        name: "Home",
+        component: Home,
+        children:
+        [
+            {
+                path: "/fileList",
+                name: "fileList",
+                meta: {
+                    title: '我的文件'
+                },
+                component: () => import ( /* webpackChunkName: "dashboard" */ "../../file/FileList.vue")
+            },
+            {
+                path: "/modelList",
+                name: "modelList",
+                meta: {
+                    title: '机器学习模型'
+                },
+                component: () => import ( /* webpackChunkName: "dashboard" */ "../../ModelList.vue")
+            },
+            // {
+            //     path: "/dlModelList",
+            //     name: "dlModelList",
+            //     meta: {
+            //         title: '深度学习模型'
+            //     },
+            //     component: () => import ( /* webpackChunkName: "dashboard" */ "../views/DLModelList.vue")
+            // },
+
+            {
+                path: "/modelDetail",
+                name: "modelDetail",
+                meta: {
+                    title: '模型训练'
+                },
+                component: () => import ( /* webpackChunkName: "dashboard" */ "../ModelDetail.vue")
+            },
+
+            {
+                path: "/fileDetail",
+                name: "fileDetail",
+                meta: {
+                    title: '文件详情'
+                },
+                component: () => import ( /* webpackChunkName: "dashboard" */ "../../file/FileDetail.vue")
+            },{
+                path: "/FileAnalysis",
+                name: "FileAnalysis",
+                meta: {
+                    title: '文件分析结果'
+                },
+                component: () => import ( /* webpackChunkName: "dashboard" */ "../../file/FileAnalysis.vue")
+            },
+            {
+                path: "/config",
+                name: "config",
+                meta: {
+                    title: '模型配置'
+                },
+                component: () => import ( /* webpackChunkName: "table" */ "../../ConfigList.vue")
+            },
+            {
+                path: "/charts",
+                name: "basecharts",
+                meta: {
+                    title: '训练结果'
+                },
+                component: () => import ( /* webpackChunkName: "charts" */ "../BaseCharts.vue")
+            },
+            {
+                path: "/form",
+                name: "baseform",
+                meta: {
+                    title: '表单'
+                },
+                component: () => import ( /* webpackChunkName: "form" */ "../BaseForm.vue")
+            },
+            {
+                path: "/message",
+                name: "message",
+                meta: {
+                    title: '我的消息'
+                },
+                component: () => import ( /* webpackChunkName: "message" */ "../../user/Message.vue")
+            },
+            {
+                path: "/upload",
+                name: "upload",
+                meta: {
+                    title: '上传插件'
+                },
+                component: () => import ( /* webpackChunkName: "upload" */ "../../file/Upload.vue")
+            },
+            {
+                path: '/user',
+                name: 'user',
+                meta: {
+                    title: '个人中心'
+                },
+                component: () => import (/* webpackChunkName: "user" */ '../../user/User.vue')
+            },
+            {
+                path:'/dllearning',
+                name:'dllearning',
+                meta:{
+                    title:'深度学习页面'
+                },
+                component:()=>import(/*webpackChunkName:"dllearning" */ '../Dllearning.vue')
+            },
+            {
+                path:'/dlform',
+                name:'dlform',
+                meta:{
+                    title:'配置模型'
+                },
+                component:()=>import(/*webpackChunkName:"dllearning" */ '../DLForm.vue')
+            },
+            {
+                path:'/configform',
+                name:'configform',
+                meta:{
+                    title:'编辑配置'
+                },
+                component:()=>import(/*webpackChunkName:"configform" */ '../../ConfigForm.vue')
+            },
+            {
+                path:'/configformp/:id',
+                name:'configformp',
+                meta:{
+                    title:'更改配置'
+                },
+                component:()=>import(/*webpackChunkName:"configform" */ '../../changeConfig.vue')
+            },
+            {
+                path:'/ConfigDetail',
+                name:'configdetail',
+                meta:{
+                    title:'配置详情'
+                },
+                component:()=>import(/*webpackChunkName:"configform" */ '../../ConfigDetail.vue')
+            },
+            //无用组件or路由
+            // {
+            //     path: "/permission",
+            //     name: "permission",
+            //     meta: {
+            //         title: '权限管理',
+            //         permission: true
+            //     },
+            //     component: () => import ( /* webpackChunkName: "permission" */ "../views/unused/Permission.vue")
+            // },
+            // {
+            //     path: '/editor',
+            //     name: 'editor',
+            //     meta: {
+            //         title: '富文本编辑器'
+            //     },
+            //     component: () => import (/* webpackChunkName: "editor" */ '../views/unused/Editor.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: "/donate",
+            //     name: "donate",
+            //     meta: {
+            //         title: '鼓励作者'
+            //     },
+            //     component: () => import ( /* webpackChunkName: "donate" */ "../views/Donate.vue")
+            // },
+            // {
+            //     path: "/i18n",
+            //     name: "i18n",
+            //     meta: {
+            //         title: '国际化语言'
+            //     },
+            //     component: () => import ( /* webpackChunkName: "i18n" */ "../views/I18n.vue")
+            // },
+        ]
+    },
+    {
+        path: "/login",
+        name: "Login",
+        meta: {
+            title: '登录'
+        },
+        component: () => import ( /* webpackChunkName: "login" */ "../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;

+ 215 - 0
src/views/user/Message.vue

@@ -0,0 +1,215 @@
+<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%" @row-click="handleMailDetail">
+                        <el-table-column>
+                            <template #default="scope">
+                                <span class="message-title">{{scope.row.title}}</span>
+                            </template>
+                        </el-table-column>
+                        <el-table-column prop="time" 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>
+  <el-dialog :title="title" v-model=" mailDetailVisible" min-width="30%" width="44%" style="">
+    <div style="width: 70%;margin-left: 100px;font-size: 18px; font-weight: bold;color: black;">{{ content }}</div>
+    <div><span style="font-size: 10px; color: black;margin-top: 40px;margin-left: 700px">{{ time }}</span></div>
+
+    <div style="width: 450px;margin-left: 100px;margin-top: 50px;box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);padding: 20px">
+      <span style="font-size: 18px; font-weight: bold;color: black;margin-bottom: 20px">回信</span>
+      <el-input
+          type="textarea"
+          autosize
+          placeholder="标题"
+          v-model="mailTitle">
+      </el-input>
+      <div style="margin: 20px 0;"></div>
+      <el-input
+          type="textarea"
+          :autosize="{ minRows: 3, maxRows: 5}"
+          placeholder="正文"
+          v-model="mailContent">
+      </el-input>
+      <el-button type="danger" icon="el-icon-message" big circle style="margin-left: 400px;margin-top: 30px" @click="sendMailTo( )"></el-button>
+    </div>
+    <template #footer>
+                <span class="dialog-footer">
+                    <el-button @click="mailDetailVisible = false">取 消</el-button>
+                    <el-button type="primary" @click="">确定</el-button>
+                </span>
+    </template>
+  </el-dialog>
+</template>
+
+<script>
+import { ref, reactive } from "vue";
+import {getUserMail, sendMail} from "../../api/mail";
+import { ElMessage, ElMessageBox } from "element-plus";
+export default {
+    name: "message",
+    setup() {
+        const title=ref("");
+        const content=ref("");
+        const time=ref("");
+        const message = ref("first");
+        const mailDetailVisible=ref(false)
+      const userId=ref()
+      const fromUserId=ref()
+      const mailTitle=ref("")
+      const mailContent=ref("")
+      const sendMailTo=()=>{
+        sendMail({"title":mailTitle,"fromUserId":userId.value,"toUserId":fromUserId.value,"content":mailContent}).then(res=>{
+          if(res.success){
+
+            ElMessage.success("发送成功!")
+            mailContent.value=""
+            mailTitle.value=""
+          }
+          else{
+            ElMessage.error("发送失败!")
+          }
+        })
+      }
+        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 handleMailDetail=(row, column, event)=>{
+          console.log(row)
+          title.value=row.title
+          content.value=row.content
+          time.value=row.time
+          fromUserId.value=row.fromUserId
+          userId.value=row.toUserId
+          mailDetailVisible.value=true
+        }
+
+        const handleGetMail=()=>{
+          getUserMail({"userId":1}).then(res=>{
+            state.unread=res.object
+          })
+        }
+        handleGetMail();
+        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,
+          title,
+          content,
+          time,
+          mailDetailVisible,
+            handleRead,
+            handleDel,
+            handleRestore,
+          handleGetMail,
+          handleMailDetail,
+          fromUserId,
+          userId,
+          sendMailTo,
+          mailTitle,
+          mailContent
+        };
+    },
+};
+
+</script>
+
+<style>
+.message-title {
+    cursor: pointer;
+}
+.handle-row {
+    margin-top: 30px;
+}
+</style>
+

+ 192 - 0
src/views/user/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>

+ 26 - 0
vite.config.js

@@ -0,0 +1,26 @@
+import vue from '@vitejs/plugin-vue'
+
+export default {
+    base: './',
+    plugins: [vue()],
+    optimizeDeps: {
+        include: ['schart.js']
+    },
+
+    server:{
+        proxy: {
+            '/api': 'http://114.212.245.120:7788/',
+            // '/api': {
+            //     target: 'http://114.212.245.120:7788/',
+            //     changeOrigin: true,
+            //     // rewrite: path => path.replace(/^\/api/, '')
+            // }
+        }
+    },
+    devServer: {
+        port: 3000,
+        open: true,
+        hot: true,//自动保存
+      },
+
+}

+ 50 - 0
前端页面说明.md

@@ -0,0 +1,50 @@
+#  前端页面说明
+前端页面分为两个模块:工作台模块、用户交互模块
+
+components文件夹里面就一些组件,header、siderbar等
+
+## 工作台模块
+
+### src/views/file/FileList.vue
+
+展示用户已经上传的file列表。
+
+### src/views/file/FileDetail.vue
+
+用户查看文件详情,展示文件字段相关内容。该页面还可以选择数据分析方式进行数据分析(皮尔森系数、偏度峰度等),结果通过弹窗展示。
+
+用户可以在该页面选择特征字段来添加配置。
+
+也可以点击自动化特征选择。
+
+### src/views/file/Upload.vue
+
+上传文件
+
+###  src/views/ConfigList.vue
+
+查看用户自己的配置列表
+
+### src/views/ConfigDetail.vue
+
+查看用户的配置详情,用户可在此添加参数生成模型
+
+### src/views/ModelList.vue
+
+查看用户的模型列表,用户可在此选择对未训练的模型进行训练,或查看已经训练的模型训练结果,并使用测试文件对其测试。
+
+##  用户交互模块
+
+### src/views/square.vue
+
+用户交互基本全写在这一个页面里了。。。目前所有api都是mock的
+
+用户可以搜索帖子,收藏帖子,查看帖子详情。
+
+对帖子进行评论、给发帖人发邮件
+
+本来想着可以一键将帖子的配置添加到自己的工作台,但是还没实现。
+
+### src/views/user/Message.vue
+
+用户可以查看别人发的邮件,也可以回邮件。

+ 1101 - 0
参考/Java接口文档.md

@@ -0,0 +1,1101 @@
+# 接口文档
+
+
+
+## 1.	Response类
+
+作用:响应客户端请求,对返回的数据做一个封装。
+
+私有成员变量:时间戳和状态码
+
+子类:ErrorRes和NormalRes
+
+```java
+public class Response {
+    private final Long timestamp = System.currentTimeMillis(); //常量,时间戳
+    private int status;//状态码
+
+    public Response(int status) {
+        this.status = status;
+    }
+}
+```
+
+
+
+### ErrorRes
+
+作用:执行请求发生错误或异常时,向客户端返回该对象。
+
+继承来的变量:时间戳和状态码
+
+自身的成员变量:错误码和错误信息。
+
+父类:Response
+
+```java
+public class ErrorRes extends Response{
+    private int errorCode;
+    private String msg;
+
+    public ErrorRes() {
+        super(HttpStatus.BAD_REQUEST.value());
+        this.errorCode = 40000;
+    }
+    /**
+     * 
+     * @param errorCode
+     * @param msg
+     * 40000: Unknown error
+     * 40001: NullPointer exception
+     * 40002: Server error
+     */
+    public ErrorRes(int errorCode, String msg) {
+        this();
+        this.errorCode = errorCode;
+        this.msg = msg;
+    }
+}
+```
+
+### NormalRes
+
+作用:正常执行客户端请求结束后,向客户端返回该对象。
+
+继承来的变量:时间戳和状态码
+
+自身的成员变量:封装为Object类的数据
+
+父类:Response
+
+```java
+public class NormalRes extends Response {
+    private Object data;
+
+    public NormalRes() {
+        super(HttpStatus.OK.value());
+    }
+    
+    public NormalRes(Object data) {
+        super(HttpStatus.OK.value());
+        this.data = data;
+    }
+}
+```
+
+
+
+## 2.	Controller接口
+
+### 2.1 用户登录注册 
+
+### LoginController(/userManage)
+
+
+
+#### GET:/login
+
+###### 参数:
+
+- String:username
+- String:password
+
+###### 返回类型:LoginPojo
+
+- bool:loginStatus
+- String:userId
+- String:jwtToken
+
+###### 说明:
+
+调用loginService.verifyUser进行登录,返回NormalRes或ErrorRes;
+
+如果用户验证不通过,errorCode=40001。
+
+
+
+> 注	LoginPojo中 jwtToken 的作用:
+>
+> JSON Web Token (JWT)是一种基于 token 的认证方案。
+> JWT是一种Token的编码算法,服务器端根据一个密码和算法生成Token,然后发给客户端,客户端负责后面每次请求都在HTTP header里面带上这个Token,服务器负责验证这个Token是不是合法的,有没有过期等,并可以解析出subject和claim里面的数据。
+> ————————————————
+> 原文链接:https://blog.csdn.net/wlddhj/article/details/79726001
+
+
+
+#### POST:/register
+
+###### 参数:
+
+- User:user
+  - String:id
+  - String:username
+  - String:password
+
+###### 说明:
+
+注册,调用loginService.addUser添加新用户
+
+如果添加失败,返回errorCode=40002
+
+
+
+### 2.2 模型配置
+
+### ConfigController(/api/config)
+
+作用:ConfigController的这些接口针对结构化文件,详见学长论文P45—P48。
+
+> Web 层的 ConfigController 定义了对外提供的配置信息新增接口,通过接口调用,可以实现机器学习特征值配置的持久化保存,前端请求 ConfigController 时传递的参数包含用户填写的配置名称、文件名称、模型类别、特征字段等属性的 ConfigVO,ConfigController 依赖 ConfigService 类来实现具体业务逻辑,ConfigService 调用 data 层的 ConfigDao 类实现对前端传递的特征选择的持久化保存。
+
+
+
+#### POST: /add  
+
+**添加机器学习模型**
+
+###### 参数:
+
+- ConfigVO:configVO
+  - String:id
+  - String:fileInfoId           //文件id
+  - String:userId               //用户id
+  - String:modelTypeId   //模型类Id
+  - String:confName        //自定义模型名
+  - List\<String> fieldIds       //选择训练的特征及特征描述
+
+###### 返回类型:String
+
+###### 说明:
+
+调用configService.addConfig,ConfigService 又调用ConfigDao 类,最后为用户添加一个机器学习模型。
+
+添加失败返回ErrorRes(40002)
+
+添加成功返回NormalRes(configId)
+
+
+
+#### GET: /get/all
+
+**获取用户已有的所有机器学习模型**
+
+###### 参数:
+
+- String:userId
+
+###### 返回类型:List\<ConfigPojo>
+
+- String:fileId
+- String:fileName
+- String:configId
+- String:modelTypeId
+- String:modelTypeName
+- String:confName
+- List\<HeaderInfo> featureList
+  - int:id
+  - int:fileInfoId                            //文件Id
+  - String:fieldName                    //文件头字段信息
+  - String:aliasName
+  - String:fieldDes                        //文件的描述信息
+  - double:nullsRatio                  //field的空值比例,为百分比 如10.00%
+  - int:conOrDis                           //表示field类型,0离散,1连续,2时间
+  - String:fieldType                     //值类型
+  - String:valueInfo                    //离散值的取值或者连续值的范围
+
+###### 说明:
+
+根据用户ID,调用ConfigService.getAllConfigs,并返回用户已有的所有机器学习配置模型。
+
+返回类型NormalRes(List\<ConfigPojo>)
+
+
+
+#### GET: /get/all_new
+
+**获取用户已有的所有机器学习模型,但比/get/all 返回的数据更精简**
+
+###### 参数:
+
+- String:userId
+
+###### 返回类型:List\<_ConfigPojo>
+
+- String:fileId
+- String:fileName
+- String:configId
+- String:confName
+
+###### 说明:
+
+getAllConfig的更新版,同样也是返回该用户的所有机器学习模型设置,但返回的信息更简单,只包含这些模型的名称与Id。
+
+调用ConfigService._getAllConfigs
+
+返回类型NormalRes(List\<_ConfigPojo>)
+
+
+
+
+
+#### GET: /get/one/config
+
+**根据模型Id,获取某个机器学习模型的配置信息**
+
+###### 参数:
+
+- String:configId
+
+###### 返回类型:ConfigDetilePojo
+
+- String:configId
+- String:modelTypeId
+- String:modelTypeName
+- String:modelDes
+- String:modelDetileDes
+- List\<HeaderInfo> featureList
+  - int:id
+  - int:fileInfoId                            //文件Id
+  - String:fieldName                    //文件头字段信息
+  - String:aliasName
+  - String:fieldDes                        //文件的描述信息
+  - double:nullsRatio                  //field的空值比例,为百分比 如10.00%
+  - int:conOrDis                           //表示field类型,0离散,1连续,2时间
+  - String:fieldType                     //值类型
+  - String:valueInfo                    //离散值的取值或者连续值的范围
+- List\<ConfigModelPojo> modelInfos
+  - String:modelName
+  - String:modelDetailName
+  - int:trainedStatus
+
+###### 说明:
+
+获得某个机器学习模型的详细配置信息。
+
+调用ConfigService.getConfigInfoByConfigId()
+
+返回类型NormalRes(ConfigDetilePojo)
+
+
+
+
+
+#### GET: /change
+
+**改变某个机器学习模型的配置信息**
+
+###### 参数
+
+- String:configId
+- String:confName
+- List\<String>:trainFeatureList
+
+###### 返回类型:Response
+
+###### 说明:
+
+改变单个机器学习模型的配置信息
+
+调用ConfigService.changeConfig()
+
+如果保存失败,则返回ErrorRes(40002)
+
+
+
+#### GET: /delete
+
+**删除用户的某个机器学习模型**
+
+###### 参数:
+
+- String:configId
+
+###### 返回类型:Boolean
+
+###### 说明:
+
+根据configId删除某个机器学习模型
+
+调用configService.deleteConfigById()
+
+如果操作失败,则返回ErrorRes(),即默认的ErrorRes对象,错误码为40000。
+
+
+
+#### GET: /get/features
+
+**用户配置机器学习模型时进行自动化特征选择,然后查询这些自动化生成的特征信息**
+
+###### 参数:
+
+- String:fileId
+- String:fieldName
+
+###### 返回类型:List\<HeaderInfo>
+
+- int:id
+- int:fileInfoId                            //文件Id
+- String:fieldName                    //文件头字段信息
+- String:aliasName
+- String:fieldDes                        //文件的描述信息
+- double:nullsRatio                  //field的空值比例,为百分比 如10.00%
+- int:conOrDis                           //表示field类型,0离散,1连续,2时间
+- String:fieldType                     //值类型
+- String:valueInfo                    //离散值的取值或者连续值的范围
+
+###### 说明:
+
+该接口的参与过程参见学长论文P48。
+
+用户配置机器学习模型时进行自动化特征选择,然后查询这些自动化生成的特征信息。
+
+调用configService.getSelectedFeature()
+
+如果操作失败,则返回ErrorRes(),即默认的ErrorRes对象,错误码为40000。
+
+
+
+### 2.3 结构化文件(机器学习)
+
+### FileController(/api/file)
+
+详见学长论文P41—P44页。
+
+> 分析训练模块作为本系统的核心模块,在本系统中起着重要作用。
+>
+> 文件管理模块实现的文件相关功能都是为了通过分析训练模块来进行具体的分析功能和机器学习训练功能,……
+>
+> **(1)数据分析子模块** 
+>
+> 该子模块是负责自动化数据分析和数理函计分析两个功能点的主要模块。 在结构化文件上传之后,该子模块负责对结构化文件内容的字段进行分析,……
+>
+> FileController 为 web 层中的定义的组件接口,用于提供给前端的接口定义。
+
+
+
+#### POST: /upload
+
+**用户上传结构化文件**
+
+###### 参数:
+
+- String:userId
+- MultipartFile:file
+- String:fileName
+
+###### 返回类型:int
+
+###### 说明:
+
+大型文件加载接口,调用FileService.uploadFile()
+
+通过FileHelper获得从MultipartFile获得File类型和fileType
+
+如果fileType等于csv,调用csvLoader,否则调用SASLoader加载
+
+这里调用涉及到的CsvAdapter是scala实现,继承SparkConnect
+
+出现异常可能返回ErrorRes(40000)和ErrorRes(40002)。
+
+
+
+#### POST: /upload/bigfile
+
+**用户上传大型的结构化文件**
+
+###### 参数:
+
+- String:userId
+- String:fileLoc
+- String:fileName
+
+###### 返回类型:int
+
+###### 说明:
+
+大型文件加载接口,直接调用csvAdapter.Csv2Parquet()
+
+
+
+#### GET: /get/all
+
+**获得用户所有已上传的文件信息**
+
+###### 参数:
+
+- String:userId
+
+###### 返回类型:List\<FileNamePojo>
+
+- String:fileId
+- String:fileName
+
+###### 说明:
+
+获得用户所有文件列表,包括文件名和文件ID
+
+调用fileService.getAllFiles()
+
+
+
+#### GET:/get/allfileandfunc
+
+###### 参数:
+
+- String:userId
+
+###### 返回类型:FileAndFuncInfoPojo
+
+- List\<FileNamePojo>:fileNamePojos;
+  - String:fileId
+  - String:fileName
+- List\<FuncInfo>:funcInfos;
+  - int:id
+  - String:funcDes
+  - String:funcName
+  - int:flagOfType                //0:String,1:trucDouble,2:all
+  - int:flagOfConorDis        //0离散,1连续,2:all
+
+###### 说明:
+
+作用见学长论文P42.
+
+获取所有文件名列表和FuncInfo列表
+
+调用fileService.getAllFilesAndFunc()
+
+
+
+#### GET:/get/detail
+
+**获取文件详细信息**
+
+###### 参数:
+
+- String:fileId
+
+###### 返回类型:FileDetailPojo
+
+- String:fileName
+- Date:createTime
+- HashMap<String,String>:fileStrucInfo
+- List\<HeaderInfo>:headerInfos
+  - int:id
+  - int:fileInfoId                            //文件Id
+  - String:fieldName                    //文件头字段信息
+  - String:aliasName
+  - String:fieldDes                        //文件的描述信息
+  - double:nullsRatio                  //field的空值比例,为百分比 如10.00%
+  - int:conOrDis                           //表示field类型,0离散,1连续,2时间
+  - String:fieldType                     //值类型
+  - String:valueInfo                    //离散值的取值或者连续值的范围
+
+###### 说明:
+
+获取文件详细信息
+
+调用FileService.getFileDetailInfo()
+
+getFileDetailInfo()调用包括fileInfoDao.findById()和headerInfoDao.findByFileInfoId()
+
+```java
+val fileInfo = fileInfoDao.findById(fileId);
+val headerInfos = headerInfoDao.findByFileInfoId(fileId);
+return new FileDetailPojo(fileInfo.getFilename(), fileInfo.getUploadTime(), new Json2Object().Json2HashMap(fileInfo.getFileStrucInfo()), headerInfos);
+```
+
+
+
+
+
+#### GET:/analysis
+
+###### 方法名:analysis
+
+###### 参数:
+
+- String:fileId
+
+###### 返回类型:FileDetailPojo
+
+- String:fileName
+- Date:createTime
+- HashMap<String,String>:fileStrucInfo
+- List\<HeaderInfo>:headerInfos
+  - int:id
+  - int:fileInfoId                            //文件Id
+  - String:fieldName                    //文件头字段信息
+  - String:aliasName
+  - String:fieldDes                        //文件的描述信息
+  - double:nullsRatio                  //field的空值比例,为百分比 如10.00%
+  - int:conOrDis                           //表示field类型,0离散,1连续,2时间
+  - String:fieldType                     //值类型
+  - String:valueInfo                    //离散值的取值或者连续值的范围
+
+###### 说明:
+
+调用fileService.analysis()进行文件分析
+
+调用fileService.getFileDetailInfo()返回文件数据
+
+fileService.analysis()调用FileAnalysis.fileAnalysis()
+
+FileAnalysis由Scala实现,继承SparkConnect
+
+
+
+#### GET:/analysis/fields1
+
+###### 方法名:analysisOfFields
+
+###### 参数:
+
+- String[]:fieldIds
+
+###### 返回类型:HashMap<String, HashMap<String, Object>>
+
+###### 说明:
+
+for test 数据分布
+
+调用FileService.getFieldDistribution()进行文件数据分布分析
+
+FileService.getFieldDistribution()调用FileAnalysis.getFieldDistribution()
+
+FileAnalysis由Scala实现,继承SparkConnect
+
+
+
+#### GET:/analysis/fields
+
+###### 方法名:analysisOfFields1
+
+###### 参数:
+
+- String[]:fieldIds
+- String:funcId
+
+###### 返回值:Object
+
+| 数据分布       | getFieldDistribution        |
+| -------------- | --------------------------- |
+| 散点图         | getFieldScatterDiagram      |
+| 数据统计       | getFieldDescription         |
+| 偏度峰度       | getFieldSkewnessAndKurtosis |
+| 皮尔森相关系数 | getFieldCorr                |
+
+###### 说明:
+
+调用FileService.getFieldAnalysis()进行字段分析
+
+根据funcId查询函数信息,获得funcName
+
+funcName包括:数据分布,散点图,数据统计,偏度峰度,皮尔森相关系数
+
+
+
+#### GET:/delete
+
+**删除上传的文件**
+
+###### 方法名:delete
+
+###### 参数:
+
+- String:fileId
+
+###### 返回值:Boolean
+
+###### 说明:
+
+调用fileService.deleteFileById(),通过fileInfoDao查询并删除
+
+返回删除结果
+
+
+
+#### POST:/update
+
+**更新上传的文件信息**
+
+###### 方法名:updateFileInfo
+
+###### 参数:
+
+- HeaderInfoUpdatedPojo:headerInfoUpdatedPojo
+  - List\<InnerHeaderInfo>:headerInfo
+    - String:id
+    - String:fileInfoId                            //文件Id
+    - String:fieldName                    //文件头字段信息
+    - String:aliasName
+    - String:fieldDes                        //文件的描述信息
+    - double:nullsRatio                  //field的空值比例,为百分比 如10.00%
+    - String:fieldType                     //值类型
+    - String:valueInfo                    //离散值的取值或者连续值的范围
+    - Boolean:aliasNameEditable
+    - Boolean:fieldDesEditable
+  - List\<Integer>:headerNeedUpdate
+
+###### 返回类型:Boolean
+
+###### 说明:
+
+调用fileService.updateAllHeaders(List\<InnerHeaderInfo> innerHeaderInfos, List\<Integer> headerToUpdate)
+
+在updateAllHeaders中对每个innerheaderInfo调用updateHeaderInfo,进行更新
+
+如果更新失败,返回false
+
+
+
+### 2.4 图片文件(深度学习)
+
+### PicController(/api/picture)
+
+#### POST:/upload
+
+**上传图片**
+
+###### 方法名:fileLoader
+
+###### 参数:
+
+- String:userId
+- MutipartFile:file
+- String:fileName
+
+###### 返回参数:NormalRes&ErrorRes
+
+###### 说明:
+
+调用pictureService.uploadPic(userId,file,filename)
+
+pictureService.uploadPic()中会创建BufferedOutputStream对象
+
+会异步创建MyThread线程,执行parseZipFile(fileAbsolutePath, userId, picAbsolutePath);
+
+如果加载失败则返回ErrorRes(40002)6
+
+
+
+
+
+#### GET:/get/all/proj
+
+**获取该用户所有图片列表,但图片信息只包括图片ID和图片名**
+
+###### 方法名:getAllProj
+
+###### 参数:
+
+- String:userId
+
+###### 返回类型:List\<PicFilePojo>
+
+- String:fileId
+- String:fileName
+
+###### 说明:
+
+调用PictureService.getAllProj()获取该用户所有PicFile列表
+
+PictureService.getAllProj()通过PictureFileDao获得userId的List\<PicFile>,然后转化为List\<PicFilePojo>
+
+
+
+#### GET:/get/one/proj
+
+**根据图片ID,获取该图片的分类信息(图片类别名、类别ID)**
+
+###### 方法名:getOneProj
+
+###### 参数:
+
+- String:picFileId
+
+###### 返回类型:List\<PicCategoryPojo>
+
+- String:categoryId
+- String:categoryName
+
+###### 说明:
+
+调用PictureService.getOneProj(picFileId)
+
+PictureService.getOneProj()通过PictureCategoryDao获得picFileId的List\<PicCategory>,然后转化为List\<PicCategoryPojo>
+
+
+
+#### GET:/get/pics
+
+**根据图片分类(标签),获取该类所有图片的信息**
+
+###### 方法名:getPicInfos
+
+###### 参数:
+
+- String:picTag
+
+###### 返回类型:List\<PicInfoPojo>
+
+- String:picId
+- String:picName
+- String:picLoc
+
+###### 说明:
+
+根据picTag,调用PictureService.getAllPicAddr()
+
+通过PictureInfoDao.findByCategoryId获得PicInfoPojo的
+
+
+
+#### GET:/update/picinfo
+
+**更新图片信息**
+
+###### 方法名:updateFileInfo
+
+###### 参数:
+
+- String:picId
+- String:picCategory
+- String:picTag
+
+###### 返回类型:NormalRes&ErrorRes
+
+###### 说明:
+
+调用PictureService.updatePicInfo进行更新
+
+如果更新失败,则返回ErrorRes(40002)
+
+
+
+### 2.5 模型相关ModelController(/api/model)
+
+> 学长论文P47
+>
+> ModelController 向外提供的服务可以实现对机器学习和深度学习的模型信息的持久化保存。ModelController 类的业务逻辑的实现依赖于 ModelService,ModelService 分别调用 ModelDao 和 DLModelDao 的服务将两种 模型信息持久化保存在数据库中。
+
+
+
+#### POST:/add
+
+**添加机器学习模型**
+
+###### 方法名:addModel
+
+###### 参数:
+
+- ModelVO:model
+  - String:id
+  - String:modelTypeId                 //模型类别
+  - String:configId                          //文件配置ID
+  - String:fileInfoId                        //文件信息ID
+  - String:modelName                  //自定义训练模型名
+  - Boolean:isTrained                   //是否训练
+  - String:modelPath                    //具体训练出的model
+  - HashMap<String,String>:resOfModel    //模型训练的result
+  - HashMap<String,String>:arguments      //模型的具体参数取值
+
+###### 返回类型:NormalRes(int)&ErrorRes
+
+###### 说明:
+
+调用ModelService.addModel(model)
+
+如果添加失败,则返回ErrorRes(40002)
+
+如果添加成功,则返回模型ID=Model.getId()
+
+
+
+
+
+#### GET:/get/all
+
+**获得某个用户的所有(机器学习)模型**
+
+###### 方法名:getAllModel
+
+###### 参数:
+
+- String:userId
+
+###### 返回类型:List\<ModelPojo>
+
+- String:configid
+- String:configName                   //文件配置名
+- String:modelTypeId                 //模型类别
+- String:modelTypeName               
+- String:modelDetailName
+- String:modelDetailDes  
+- String:modelDes
+- String:modelId            
+- String:modelName                  //自定义训练模型名
+- int:trainedStatus                      //是否训练
+- HashMap<String,String>:arguments      //模型的具体参数取值
+- HashMap<String,String>:resOfModel    //模型训练的result
+
+###### 说明:
+
+调用modelService.getAllModelByUserId(userId)
+
+返回该用户所有Model信息列表
+
+
+
+
+
+#### GET:/get/all/dl
+
+**获得所有深度学习模型**
+
+###### 方法名:getAllDLModel
+
+###### 参数:
+
+- String:userId
+
+###### 返回类型:List\<DLGeneralModelPojo>
+
+- String:modelId
+- String:modelName
+- String:fileId
+- String:fileName
+- boolean:isTrain
+- boolean:hasResult
+
+###### 说明:
+
+调用ModelService.getAllGeneralModelByUserId(userId)获得所有DL深度学习Model信息
+
+ModelService.getAllGeneralModelByUserId中,枚举userId的所有PicFile,DLModel
+
+通过MapReduce生成DLGeneralModelPojo
+
+
+
+
+
+#### GET:/get/detail/dl
+
+**根据模型ID,获得某个深度学习模型的详细信息**
+
+###### 方法名:getDLDetaiModel
+
+###### 参数:
+
+- String:modelId
+
+###### 返回类型:DLModelPojo
+
+- String:modelTypeId                 //模型类别
+- String:picFileId                          //文件信息ID
+- String:configName                   //文件配置名        
+- String:modelName                  //自定义训练模型名
+- boolean:isTrained                      //是否训练
+- String:modelPath    
+- HashMap<String,String>:resOfModel    //模型训练的result
+- HashMap<String,String>:arguments      //模型的具体参数取值
+
+###### 说明:
+
+调用ModelService.getDLModelDetailById,返回具体的DL深度学习模型信息
+
+
+
+#### POST:/add/dl
+
+**添加深度学习模型**
+
+###### 方法名:addDLModel
+
+###### 参数:
+
+- DLModelVO:model
+  - String:id
+  - String:modelTypeId                 //模型类别
+  - String:configId                          //文件配置ID
+  - String:fileInfoId                        //文件信息ID
+  - String:modelName                  //自定义训练模型名
+  - Boolean:isTrained                   //是否训练
+  - String:modelPath                    //具体训练出的model
+  - HashMap<String,String>:resOfModel    //模型训练的result
+  - HashMap<String,String>:arguments      //模型的具体参数取值
+
+###### 返回类型:NormalRes(int)&ErrorRes
+
+###### 说明:
+
+调用ModelService.addDlModel(model)添加DL模型
+
+如果添加失败,则返回ErrorRes(40002)
+
+如果添加成功,则返回模型ID=Model.getId()
+
+
+
+#### GET:/change
+
+**改变模型名称和类型**
+
+###### 方法名:changeModel
+
+###### 参数:
+
+- String:modelId
+- String:modelName
+- String:modelTypeId
+
+###### 返回类型:NormalRes&ErrorRes
+
+###### 说明:
+
+调用ModelService.changeModel(modelId,modelName,modelTypeId),对Model信息进行修改
+
+用modelId获得现有Model,修改modelName和modelTypeId,然后保存
+
+根据修改结果返回NormalRes或ErrorRes
+
+
+
+#### GET:/get/models
+
+**获得某个模型类型的名称**
+
+###### 方法名:getModelType
+
+###### 参数:
+
+- String:modelTypeName
+
+###### 返回类型:List\<ModelType>
+
+- int:id
+- String:modelTypeName
+- String:modelDetailName
+- String:arguments
+- String:modelDetailDes
+- String:modelDes
+
+###### 说明:
+
+调用ModelService.getModelTypeByModelTypeName()获得ModelType类型信息
+
+ModelService.getModelTypeByModelTypeName()中,通过modelTypeDao通过TypeName查询
+
+
+
+
+
+#### GET:/train
+
+**使用机器学习模型进行训练,并返回训练结果**
+
+###### 方法名:trainModel
+
+###### 参数:
+
+- String:modelId
+
+###### 返回类型:boolean
+
+###### 说明:
+
+调用modelService.trainTheModel()对模型进行训练
+
+modelService.trainTheModel()中,首先修改model的TrainedStatus
+
+根据modelDetailName,包含如下的模型训练类型:
+
+- LogisticRegression:逻辑回归
+- DecisionTree:决策树
+- RandomForest:随机森林
+- GBDT
+- K-means
+- MultilayerPerceptronClassifier:(MLPC)多层感知器分类器
+- NaiveBayes:朴素贝叶斯
+- RandomForestRegression:随机森林回归
+
+boolean返回类型返回训练结果
+
+
+
+#### GET:/delete
+
+**通过模型ID删除某个机器学习/深度学习模型**
+
+###### 方法名:deleteModelByModelId
+
+###### 参数:
+
+- String:modelId
+
+###### 返回类型:boolean
+
+###### 说明:
+
+调用ModelService.deleteModel(),删除modelId对应的Model
+
+ModelService.deleteModel()通过ModelDao进行查找和删除
+
+返回删除结果
+
+
+
+#### POST:/use/upload
+
+**上传模型需要的测试文件**
+
+###### 方法名:uploadTestFile
+
+###### 参数:
+
+- String:userId
+- MultipartFile:file
+- String:fileName
+
+###### 返回类型:TestFileValuePojo
+
+- String:fileId
+- List<Map<String, String>>:values
+
+###### 说明:
+
+调用**FileService**.uploadTestFile(),上传测试文件
+
+fileService.uploadTestFile()中,先调用FileService.uoloadFile上传文件。再通过返回值FileId,通过FileInfoDao获取文件位置。
+
+然后调用csvAdapter.parquetFileReader获取文件内容values,创建TestFileValuePojo类型返回值
+
+
+
+#### GET:/use
+
+**使用模型进行预测**
+
+> 学长论文P51—P52
+>
+> ModelController 组件调用 ModelService 接口来实现模型预测的业务逻辑,ModelService 依赖于 FitTestData 进行具体的模型预测,FitTestData 对测试数据的读取需要调用 FileInfoDAO 组件,对模型的加载需要调用到 ModelDAO 组件。
+
+###### 方法名:useModel
+
+###### 参数:
+
+- String:fileId
+- String:ModelId
+
+###### 返回类型:List<Map<String, String>>
+
+###### 说明:
+
+调用modelService.useModel(),使用模型对文件进行处理
+
+modelService.useModel()中调用FitTestData.transformData
+
+FitTestData由Scala实现,继承SparkConnect
+
+不过数据转换后,会删除fileId对应的源文件
+

+ 246 - 0
参考/Python接口文档.md

@@ -0,0 +1,246 @@
+# Python接口文档
+
+### Response
+
+```
+def response(data={}, code=200):
+    resp = {
+        "timestamp": int(round(time.time() * 1000)),
+        "status": code,
+        "data": data
+    }
+    response = make_response(jd(resp))
+    response.headers['Status Code'] = resp['status']
+    response.headers['Content-Type'] = "application/json"
+    return response
+```
+
+### Controller
+
+#### GET:/get/file
+
+###### 方法名:application.hello()
+
+###### 参数:
+
+- 文件Id:fileId
+
+###### 实现:
+
+```
+@app.route('/get/file', methods=['GET'])
+def hello():
+    value = request.args
+    app.logger.info('value: %s', value)
+    try:
+        return response(fileInfoDao.getFileInfoById(value.get('fileId')))
+    except Exception as error:
+        return response({}, 400)
+```
+
+其中fileInfoDao是FileInfo类的实例,用于获得文件信息
+
+否则返回status code=400
+
+#### GET:/api/model/dl/train
+
+###### 方法名:application.train()
+
+###### 参数:
+
+- 模型Id:modelId
+
+###### 实现:
+
+深度学习模型训练
+
+```python
+@app.route('/api/model/dl/train', methods=['GET'])
+def train():
+    value = request.args
+    app.logger.info('value: %s', value)
+    try:
+        # args
+        modelId = value.get('modelId')
+        modelEntity = dlModelDao.getModelById(modelId)
+        print("model: ", modelEntity)
+        # pic entity
+        print(modelEntity[2])
+        picEntity = picFileDao.getPicFileById(str(modelEntity[2]))
+        print("pic: ", picEntity)
+        # model entity
+        modelTypeEntity = modelTypeDao.getModelTypeById(str(modelEntity[1]))
+        print("modelType: ", modelTypeEntity)
+        # args
+        modelArgs = json.loads(modelEntity[7])
+        epochs = int(modelArgs['epochs'])
+        steps_per_epoch = int(modelArgs['steps_per_epoch'])
+        valid_steps = int(modelArgs['valid_steps'])
+        # train location
+        trainLoc = picEntity[3]
+        modelDetailName = modelTypeEntity[2]
+        trainGen = picHelper.trainGen(trainLoc)
+        # calculate time
+        startTime = datetime.datetime.now()
+        if modelDetailName == 'CNN':
+            base = Cnn.Cnn(trainGen, epochs, steps_per_epoch, valid_steps)
+            accs, model = base.train()
+        elif modelDetailName == 'VGG':
+            base = Vgg.Vgg(trainGen, epochs, steps_per_epoch, valid_steps)
+            accs, model = base.train()
+        elif modelDetailName == 'HirRnn':
+            base = HirRnn.HirRnn(trainGen, epochs, steps_per_epoch, valid_steps)
+            accs, model = base.train()
+        else:
+            raise Exception
+        endTime = datetime.datetime.now()
+        #path = hdfsHelper.saveToHDFS(model,modelEntity[3])
+        path = "/Users/cyz/Documents/idea_workspace/Desktop/glaucus/glaucus/python/src/model/"+modelId+".h5"
+        model.save(path)
+        # print(model)
+        # payload = {'model': model, 'modelId': 4,'dlOrNot':1}
+        # r = requests.get('http://localhost:8080/api/model/savemodel', params=payload)
+        # r.encoding = 'utf-8'
+        # content = r.text
+        # print(content)
+        dlModelDao.setModelPath(modelId,path)
+        dlModelDao.setModelResult(modelId, accs, (endTime-startTime).seconds)
+        dlModelDao.setModelTrained(modelId, True)
+        return response(True)
+    except Exception as error:
+        print(error)
+        return response({}, 400)
+```
+
+从DlModelDAo通过modelId获得模型信息modelEntity,然后根据modelEntity获得图片信息picEntity和模型类型信息modelTypeEntity。
+
+提取出相关训练信息,比如路径。根据模型细节:CNN、VGG、HirRnn进行深度学习,然后对结果模型进行保存,并通过DLModelDao的更改数据库信息
+
+#### GET:/api/config/get/features
+
+###### 方法名:application.featureSelection()
+
+###### 参数:
+
+- String:fileId
+- String:fieldName
+- String:methodId
+
+###### 返回数据:array
+
+- fieldName
+- value
+- id
+
+###### 实现:
+
+特征选择获取
+
+```
+@app.route('/api/config/get/features', methods=['GET'])
+def featureSelection():
+    value = request.args
+    app.logger.info('value: %s', value)
+    try:
+        fileId = value.get('fileId')
+        fieldName = value.get('fieldName')
+        methodId = value.get('methodId')
+        fileEntity = fileInfoDao.getFileInfoById(fileId)
+        print(fileEntity)
+        fileLoc = fileEntity[1]
+        # read parquet file
+        processor = FileProcessor(fileLoc)
+        (x, y, names) = processor.processor(fieldName)
+        featureSelector = FeatureSelector(x, y, names)
+        # train the feature
+        if methodId == 'RL':
+            res = featureSelector.selectWithRandomizedLasso()
+        elif methodId == 'RF':
+            res = featureSelector.selectWithRandomForest()
+        else:
+            raise Exception()
+        print(res)
+        resData = list(map(lambda pair: {
+            'fieldName': str(pair[1]),
+            'value': pair[0],
+            'id': str(headerInfoDao.getByFileIdAndFieldName(fileId, str(pair[1]))[0])
+        }, res))
+        size = len(resData)
+        return response(resData[:int(size * 0.2)])
+    except Exception as error:
+        print(error)
+        return response({}, 400)
+```
+
+fileInfoDao是FileInfo类的实例,用于通过fileId获得文件信息,同时获取文件位置fileLoc等参数
+
+这里通过preprocess目录下的类FileProcess对FileLoc下的文件进行处理
+
+FileProcess.\__init__()通过Spark对文件进行读取
+
+FileProcess.process()用fieldName对文件进行处理,返回的三元组(x,y,name)用于特征选择类FeatureSelector的初始化参数
+
+然后根据methodId的值:RL(随机罗森)、RF(随机森林)分别调用FeatureSelector的selectWithRandomizedLasso()和selectWithRandomForest()
+
+最后选择前20%的特征,返回其数组列表
+
+#### GET:/api/automl
+
+###### 方法名:application.autoMl()
+
+###### 参数:
+
+- String:fileId
+- String:fieldId
+- String:modelId
+
+###### 实现:
+
+自动化机器学习
+
+```
+@app.route('/api/automl', methods=['GET'])
+def autoMl():
+    value = request.args
+    app.logger.info('value: %s', value)
+    try:
+        fileId = value.get('fileId')
+        modelId = value.get('modelId')
+        fieldId = value.get('fieldId')
+        headerEntity = headerInfoDao.getHeaderInfoById(fieldId)
+        fileEntity = fileInfoDao.getFileInfoById(fileId)
+        file_loc = fileEntity[1]
+        traget_feature = headerEntity[2]
+        # get files
+        dc = DataCleaning.DataCleaning(file_loc, traget_feature)
+        X, y, is_classification = dc.dataTrans()
+        if is_classification:
+            classifier = Classification.AutoClassification(X, y)
+            score, time = classifier.fit()
+        else:
+            regressor = Regression.AutoRegression(X, y)
+            score, time = regressor.fit()
+
+        print("Accuracy score: ", score)
+        print("Cost time: ", time)
+        modelDao.setModelTrained(modelId, True)
+        modelDao.setModelResult(modelId, score, other_key='CostTime', other_value=time.total_seconds())
+        return response()
+    except Exception as error:
+        print(error)
+        return response({}, 400)
+```
+
+headInfoDao是HeadInfo类的实例,其他Dao类似
+
+headInfoDao通过fieldId获得headerEntity头部信息,提取出目标特征
+
+fileInfoDao通过fileId获得fileEntity头部信息,提取出文件位置
+
+创建DataCleaning实例,dataTrans()对数据进行清洗和转化
+
+如果分类任务,则调用Classification.AutoClassification
+
+否则为回归任务,调用Regression.AutoRegression
+
+然后通过modelDao对model模型信息进行修改,标记为已训练,保存训练结果

BIN
参考/web前端结构.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
+

+ 237 - 0
参考/前后端逻辑整理.md

@@ -0,0 +1,237 @@
+### 逻辑模块划分
+
+- 文件模块
+  - 文件上传
+  - 列表
+  - 文件修改
+- 数据分析模块
+  - 选择文件
+  - 选择特征字段,函数分析
+  - 分析结果
+- 模型管理
+  - 机器学习模型
+    - 特征字段选择
+    - 模型参数
+  - 深度学习模型
+    - 模型参数属性
+  - 模型属性参数列表
+- 模型训练和使用
+  - 模型训练
+  - 模型使用
+  - 模型结果
+
+
+
+### 文件模块逻辑
+
+#### 文件上传
+
+| API接口          | 输入数据                 | 返回数据     |
+| ---------------- | ------------------------ | ------------ |
+| /api/file/upload | 用户id,文件内容,文件名 | 文件上传结果 |
+
+补充:处理时建议加上用户id前缀,不然感觉会重名
+
+#### 文件列表展示
+
+| API接口                      | 输入数据 | 返回数据             |
+| ---------------------------- | -------- | -------------------- |
+| /api/file/get/all            | 用户id   | 文件id和名列表       |
+| /api/file/get/detail         | 文件id   | FileDetail数据       |
+| /api/file/get/allfileandfunc | 用户id   | 文件名和分析函数列表 |
+
+暂定逻辑:
+
+先通过get/all获取所有文件id,依次查询get/detail获取详细信息。当用户选择显示分析函数时,调用get/allfileandfunc
+
+#### 文件修改
+
+| API接口          | 输入数据 | 返回数据 |
+| ---------------- | -------- | -------- |
+| /api/file/delete | 文件id   | 删除结果 |
+
+暂定逻辑:包括修改和删除
+
+用户选择删除文件时,前端调用/delete,传入get/all中获取的文件id
+
+/update暂时不太明白如何使用,参数太多
+
+
+
+### 数据分析模块
+
+#### 选择文件
+
+| API接口              | 输入数据 | 返回数据       |
+| -------------------- | -------- | -------------- |
+| /api/file/get/all    | 用户id   | 文件id和名列表 |
+| /api/file/get/detail | 文件id   | FileDetail数据 |
+
+#### 特征字段选择,函数分析
+
+| API接口                   | 输入数据           | 返回数据                       |
+| ------------------------- | ------------------ | ------------------------------ |
+| /api/file/analysis        | 文件id             | 获取文件分析信息,包括字段列表 |
+| /api/file/analysis/fields | 字段id列表和函数id | 分析结果object                 |
+
+注意:根据funcId查询函数信息,获得funcName
+
+需要在后端数据库导入函数数据才能调用analysis/fields
+
+注意:这里的fieldId(字段ID)对应的应该是/analysis接口中返回的headinfo中的id
+
+
+
+##### 暂定逻辑:
+
+先通过analysis进行自动分析,获得字段列表
+
+在选择字段界面选择后,传入字段id列表,调用/analysis/fields进行字段分析
+
+用户可以选择保存为config
+
+#### 分析结果
+
+| API接口                      | 输入数据 | 返回数据             |
+| ---------------------------- | -------- | -------------------- |
+| /api/file/get/detail         | 文件id   | FileDetail数据       |
+| /api/file/get/allfileandfunc | 用户id   | 文件名和分析函数列表 |
+
+##### 用户查看函数分析结果:
+
+对/analysis的字段列表和/analysis/fields返回的分析数据进行可视化
+
+目前后端似乎并没有找到持久化保存文件分析结果的相关接口和逻辑,只有几个获取文件数据的接口可用
+
+
+
+### 模型配置模块(机器学习模型)
+
+现有问题:后端并没有可以更改model的config内容的接口,所以只能先创建config,在创建模型时要求填入
+
+后端针对modelController的修改只有/change:**改变模型名称和类型**
+
+#### 获取模型列表
+
+| API接口            | 输入数据 | 返回数据     |
+| ------------------ | -------- | ------------ |
+| /api/model/get/all | 用户id   | 模型数据列表 |
+
+#### 添加模型
+
+| API接口        | 输入数据 | 返回数据 |
+| -------------- | -------- | -------- |
+| /api/model/add | modelVO  | 添加结果 |
+
+传入一部分模型的基本数据
+
+- 注意,这里modelVO的一部分属性不是必须值,可以由前端传入默认值(比如0号id)
+- 这里的modelType是必须数据,选择模型类型后,通过/api/model/get/models,获得指定模型名,参数等详细信息呈现
+- 在获得模型参数后,需要用户填写参数,填入modelVO传入
+- 通过读取模型配置列表,选择填入已有模型配置ConfigId
+
+modelVO的结构见接口文档
+
+#### 删除模型
+
+| API接口           | 输入数据 | 返回数据 |
+| ----------------- | -------- | -------- |
+| /api/model/delete | modelId  | 删除结果 |
+
+暂定逻辑:
+
+modelId通过get/all获取,然后用户触发删除后调用/delete,传入modelId
+
+#### 获得某个模型类型属性
+
+| API接口               | 输入数据      | 返回数据       |
+| --------------------- | ------------- | -------------- |
+| /api/model/get/models | modelTypeName | 模型名,参数等 |
+
+在用户选择模型后,调用/api/model/get/models获取需要的参数,让用户填写
+
+#### 添加模型配置
+
+| API接口         | 输入数据 | 返回数据 |
+| --------------- | -------- | -------- |
+| /api/config/add | configVO | 添加结果 |
+
+暂定逻辑:
+
+用户可以在文件列表中选择文件,自定义模型名,特征字段,由前端再传入id数据
+
+文件id由选择文件功能的/api/file/get/all获得
+
+#### 获得模型配置列表
+
+| API接口             | 输入数据 | 返回数据     |
+| ------------------- | -------- | ------------ |
+| /api/config/get/all | 用户id   | 模型配置列表 |
+
+暂定逻辑:
+
+用户可以在文件列表中选择文件,自定义模型名,训练特征,由前端再传入id数据
+
+文件id由选择文件功能的/api/file/get/all获得
+
+#### 修改/删除配置
+
+| API接口            | 输入数据                     | 返回数据 |
+| ------------------ | ---------------------------- | -------- |
+| /api/config/change | 配置id,配置名,训练特征列表 |          |
+| /api/config/delete | 配置id                       | 删除结果 |
+
+修改配置可以修改自定义配置名和特征字段的列表
+
+#### 模型配置-自动化特征选择
+
+| API接口                  | 输入数据       | 返回数据             |
+| ------------------------ | -------------- | -------------------- |
+| /api/config/get/features | 文件id和文件名 | headInfo特征字段列表 |
+
+暂定逻辑:
+
+用户在进行模型配置时,可以选择手动填入特征字段或自动特征选择,选择后者
+
+则要求用户选择进行自动特征选择的文件,触发该接口
+
+#### 选择文件
+
+同上,让用户在列表中选择文件
+
+| API接口              | 输入数据 | 返回数据       |
+| -------------------- | -------- | -------------- |
+| /api/file/get/all    | 用户id   | 文件id和名列表 |
+| /api/file/get/detail | 文件id   | FileDetail数据 |
+
+/api/file/get/detail会返回文件字段列表
+
+
+
+### 模型训练和使用模块(机器学习模型)
+
+#### 模型训练
+
+| API接口          | 输入数据 | 返回数据 |
+| ---------------- | -------- | -------- |
+| /api/model/train | 模型id   | 训练结果 |
+
+#### 模型使用
+
+| API接口        | 输入数据       | 返回数据                  |
+| -------------- | -------------- | ------------------------- |
+| /api/model/use | 文件id和模型id | List<Map<String, String>> |
+
+模型对指定文件进行预测,返回的数据如何利用需要研究,由前端进行可视化
+
+
+
+### 模型配置模块(深度学习模型)
+
+跟机器学习差不多,不过文件从结构化文件变成图片,调用picController的接口
+
+
+
+### 模型训练使用模块(深度学习模型)
+
+调用的接口似乎和机器学习模型一致,但是可能要区分一下

BIN
参考/接口.xlsx


BIN
参考/接口测试.pdf


BIN
参考/接口测试md/接口测试.assets/image-20220207152620531.png


BIN
参考/接口测试md/接口测试.assets/image-20220207152908085.png


BIN
参考/接口测试md/接口测试.assets/image-20220207153409659.png


BIN
参考/接口测试md/接口测试.assets/image-20220207162707754.png


BIN
参考/接口测试md/接口测试.assets/image-20220207163557482.png


BIN
参考/接口测试md/接口测试.assets/image-20220207163711420.png


BIN
参考/接口测试md/接口测试.assets/image-20220207163917993.png


BIN
参考/接口测试md/接口测试.assets/image-20220207163943482.png


BIN
参考/接口测试md/接口测试.assets/image-20220207164150453.png


BIN
参考/接口测试md/接口测试.assets/image-20220207164158117.png


BIN
参考/接口测试md/接口测试.assets/image-20220207164445827.png


BIN
参考/接口测试md/接口测试.assets/image-20220207164636503.png


BIN
参考/接口测试md/接口测试.assets/image-20220207164651547.png


BIN
参考/接口测试md/接口测试.assets/image-20220207165209667.png


BIN
参考/接口测试md/接口测试.assets/image-20220207165314803.png


BIN
参考/接口测试md/接口测试.assets/image-20220207165510867.png


BIN
参考/接口测试md/接口测试.assets/image-20220207165530711.png


BIN
参考/接口测试md/接口测试.assets/image-20220207165753287.png


BIN
参考/接口测试md/接口测试.assets/image-20220207165837625.png


BIN
参考/接口测试md/接口测试.assets/image-20220207165913815.png


BIN
参考/接口测试md/接口测试.assets/image-20220207170139844.png


BIN
参考/接口测试md/接口测试.assets/image-20220207170203829.png


BIN
参考/接口测试md/接口测试.assets/image-20220207170315922.png


BIN
参考/接口测试md/接口测试.assets/image-20220207170318027.png


BIN
参考/接口测试md/接口测试.assets/image-20220207170415247.png


BIN
参考/接口测试md/接口测试.assets/image-20220207170606466.png


Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff