Browse Source

宝智达冷链后台

huangyan 11 months ago
commit
dc192bb3c8
51 changed files with 5422 additions and 0 deletions
  1. 1 0
      .gitignore
  2. 8 0
      .idea/.gitignore
  3. 8 0
      .idea/modules.xml
  4. 6 0
      .idea/vcs.xml
  5. 9 0
      .idea/vue3-zhifou.iml
  6. 3 0
      .vscode/extensions.json
  7. 7 0
      README.md
  8. 13 0
      index.html
  9. 1892 0
      package-lock.json
  10. 25 0
      package.json
  11. 1 0
      public/vite.svg
  12. 9 0
      src/App.vue
  13. 24 0
      src/api/contents.js
  14. 24 0
      src/api/product.js
  15. 28 0
      src/api/resource.js
  16. 27 0
      src/api/serve.js
  17. 20 0
      src/api/user.js
  18. BIN
      src/assets/img/avator.jpg
  19. BIN
      src/assets/img/bg.jpg
  20. BIN
      src/assets/img/favicon.ico
  21. BIN
      src/assets/img/index.gif
  22. BIN
      src/assets/img/index.jpg
  23. 10 0
      src/assets/js/common.js
  24. 5 0
      src/assets/js/constant.js
  25. 1 0
      src/assets/vue.svg
  26. 18 0
      src/components/HelloWorld.vue
  27. 82 0
      src/components/Home.vue
  28. 22 0
      src/main.js
  29. 136 0
      src/router/index.js
  30. 17 0
      src/style.css
  31. 81 0
      src/utils/http/axios.js
  32. 43 0
      src/utils/http/http.js
  33. 95 0
      src/view/EditorWithBinding.vue
  34. 181 0
      src/view/Home.vue
  35. 111 0
      src/view/Login.vue
  36. 18 0
      src/view/Welcome.vue
  37. 75 0
      src/view/contents/Detail.vue
  38. 74 0
      src/view/contents/add.vue
  39. 121 0
      src/view/contents/contents.vue
  40. 100 0
      src/view/editor.vue
  41. 100 0
      src/view/product/Detail.vue
  42. 149 0
      src/view/product/add.vue
  43. 186 0
      src/view/product/product.vue
  44. 41 0
      src/view/resource/Detail.vue
  45. 130 0
      src/view/resource/Index.vue
  46. 69 0
      src/view/resource/upload.vue
  47. 109 0
      src/view/serve/Detail.vue
  48. 125 0
      src/view/serve/add.vue
  49. 139 0
      src/view/serve/serves.vue
  50. 18 0
      vite.config.js
  51. 1061 0
      yarn.lock

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+node_modules

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/vue3-zhifou.iml" filepath="$PROJECT_DIR$/.idea/vue3-zhifou.iml" />
+    </modules>
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 9 - 0
.idea/vue3-zhifou.iml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="Go" enabled="true" />
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 3 - 0
.vscode/extensions.json

@@ -0,0 +1,3 @@
+{
+  "recommendations": ["Vue.volar"]
+}

+ 7 - 0
README.md

@@ -0,0 +1,7 @@
+# Vue 3 + Vite
+
+This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
+
+## Recommended IDE Setup
+
+- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar)

+ 13 - 0
index.html

@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <link rel="icon" type="image/svg+xml" href="/src/assets/img/favicon.ico" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>知否在线课堂</title>
+  </head>
+  <body>
+    <div id="app"></div>
+    <script type="module" src="/src/main.js"></script>
+  </body>
+</html>

+ 1892 - 0
package-lock.json

@@ -0,0 +1,1892 @@
+{
+  "name": "vue3-zhifou",
+  "version": "0.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "vue3-zhifou",
+      "version": "0.0.0",
+      "dependencies": {
+        "@element-plus/icons-vue": "^2.0.10",
+        "@wangeditor/editor-for-vue": "^5.1.12",
+        "axios": "^1.2.0",
+        "element-plus": "^2.2.25",
+        "qs": "^6.11.0",
+        "vue": "^3.2.41",
+        "vue-quill-editor": "^3.0.6",
+        "vue-router": "^4.0.13"
+      },
+      "devDependencies": {
+        "@vitejs/plugin-vue": "^3.2.0",
+        "vite": "^3.2.3"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.20.5",
+      "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.20.5.tgz",
+      "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==",
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/runtime": {
+      "version": "7.24.5",
+      "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.24.5.tgz",
+      "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==",
+      "peer": true,
+      "dependencies": {
+        "regenerator-runtime": "^0.14.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@ctrl/tinycolor": {
+      "version": "3.4.1",
+      "resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz",
+      "integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@element-plus/icons-vue": {
+      "version": "2.0.10",
+      "resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.0.10.tgz",
+      "integrity": "sha512-ygEZ1mwPjcPo/OulhzLE7mtDrQBWI8vZzEWSNB2W/RNCRjoQGwbaK4N8lV4rid7Ts4qvySU3njMN7YCiSlSaTQ==",
+      "peerDependencies": {
+        "vue": "^3.2.0"
+      }
+    },
+    "node_modules/@esbuild/android-arm": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.15.18.tgz",
+      "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-loong64": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz",
+      "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@floating-ui/core": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.0.2.tgz",
+      "integrity": "sha512-Skfy0YS3NJ5nV9us0uuPN0HDk1Q4edljaOhRBJGDWs9EBa7ZVMYBHRFlhLvvmwEoaIM9BlH6QJFn9/uZg0bACg=="
+    },
+    "node_modules/@floating-ui/dom": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.0.7.tgz",
+      "integrity": "sha512-6RsqvCYe0AYWtsGvuWqCm7mZytnXAZCjWtsWu1Kg8dI3INvj/DbKlDsZO+mKSaQdPT12uxIW9W2dAWJkPx4Y5g==",
+      "dependencies": {
+        "@floating-ui/core": "^1.0.2"
+      }
+    },
+    "node_modules/@popperjs/core": {
+      "name": "@sxzz/popperjs-es",
+      "version": "2.11.7",
+      "resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
+      "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ=="
+    },
+    "node_modules/@transloadit/prettier-bytes": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmmirror.com/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz",
+      "integrity": "sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==",
+      "peer": true
+    },
+    "node_modules/@types/event-emitter": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmmirror.com/@types/event-emitter/-/event-emitter-0.3.5.tgz",
+      "integrity": "sha512-zx2/Gg0Eg7gwEiOIIh5w9TrhKKTeQh7CPCOPNc0el4pLSwzebA8SmnHwZs2dWlLONvyulykSwGSQxQHLhjGLvQ==",
+      "peer": true
+    },
+    "node_modules/@types/lodash": {
+      "version": "4.14.191",
+      "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.191.tgz",
+      "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ=="
+    },
+    "node_modules/@types/lodash-es": {
+      "version": "4.17.6",
+      "resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.6.tgz",
+      "integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==",
+      "dependencies": {
+        "@types/lodash": "*"
+      }
+    },
+    "node_modules/@types/web-bluetooth": {
+      "version": "0.0.16",
+      "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
+      "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
+    },
+    "node_modules/@uppy/companion-client": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmmirror.com/@uppy/companion-client/-/companion-client-2.2.2.tgz",
+      "integrity": "sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==",
+      "peer": true,
+      "dependencies": {
+        "@uppy/utils": "^4.1.2",
+        "namespace-emitter": "^2.0.1"
+      }
+    },
+    "node_modules/@uppy/core": {
+      "version": "2.3.4",
+      "resolved": "https://registry.npmmirror.com/@uppy/core/-/core-2.3.4.tgz",
+      "integrity": "sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==",
+      "peer": true,
+      "dependencies": {
+        "@transloadit/prettier-bytes": "0.0.7",
+        "@uppy/store-default": "^2.1.1",
+        "@uppy/utils": "^4.1.3",
+        "lodash.throttle": "^4.1.1",
+        "mime-match": "^1.0.2",
+        "namespace-emitter": "^2.0.1",
+        "nanoid": "^3.1.25",
+        "preact": "^10.5.13"
+      }
+    },
+    "node_modules/@uppy/store-default": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmmirror.com/@uppy/store-default/-/store-default-2.1.1.tgz",
+      "integrity": "sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ==",
+      "peer": true
+    },
+    "node_modules/@uppy/utils": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmmirror.com/@uppy/utils/-/utils-4.1.3.tgz",
+      "integrity": "sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==",
+      "peer": true,
+      "dependencies": {
+        "lodash.throttle": "^4.1.1"
+      }
+    },
+    "node_modules/@uppy/xhr-upload": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmmirror.com/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz",
+      "integrity": "sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==",
+      "peer": true,
+      "dependencies": {
+        "@uppy/companion-client": "^2.2.2",
+        "@uppy/utils": "^4.1.2",
+        "nanoid": "^3.1.25"
+      },
+      "peerDependencies": {
+        "@uppy/core": "^2.3.3"
+      }
+    },
+    "node_modules/@vitejs/plugin-vue": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-3.2.0.tgz",
+      "integrity": "sha512-E0tnaL4fr+qkdCNxJ+Xd0yM31UwMkQje76fsDVBBUCoGOUPexu2VDUYHL8P4CwV+zMvWw6nlRw19OnRKmYAJpw==",
+      "dev": true,
+      "engines": {
+        "node": "^14.18.0 || >=16.0.0"
+      },
+      "peerDependencies": {
+        "vite": "^3.0.0",
+        "vue": "^3.2.25"
+      }
+    },
+    "node_modules/@vue/compiler-core": {
+      "version": "3.2.45",
+      "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.2.45.tgz",
+      "integrity": "sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A==",
+      "dependencies": {
+        "@babel/parser": "^7.16.4",
+        "@vue/shared": "3.2.45",
+        "estree-walker": "^2.0.2",
+        "source-map": "^0.6.1"
+      }
+    },
+    "node_modules/@vue/compiler-dom": {
+      "version": "3.2.45",
+      "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz",
+      "integrity": "sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==",
+      "dependencies": {
+        "@vue/compiler-core": "3.2.45",
+        "@vue/shared": "3.2.45"
+      }
+    },
+    "node_modules/@vue/compiler-sfc": {
+      "version": "3.2.45",
+      "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz",
+      "integrity": "sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q==",
+      "dependencies": {
+        "@babel/parser": "^7.16.4",
+        "@vue/compiler-core": "3.2.45",
+        "@vue/compiler-dom": "3.2.45",
+        "@vue/compiler-ssr": "3.2.45",
+        "@vue/reactivity-transform": "3.2.45",
+        "@vue/shared": "3.2.45",
+        "estree-walker": "^2.0.2",
+        "magic-string": "^0.25.7",
+        "postcss": "^8.1.10",
+        "source-map": "^0.6.1"
+      }
+    },
+    "node_modules/@vue/compiler-ssr": {
+      "version": "3.2.45",
+      "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz",
+      "integrity": "sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ==",
+      "dependencies": {
+        "@vue/compiler-dom": "3.2.45",
+        "@vue/shared": "3.2.45"
+      }
+    },
+    "node_modules/@vue/devtools-api": {
+      "version": "6.4.5",
+      "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.4.5.tgz",
+      "integrity": "sha512-JD5fcdIuFxU4fQyXUu3w2KpAJHzTVdN+p4iOX2lMWSHMOoQdMAcpFLZzm9Z/2nmsoZ1a96QEhZ26e50xLBsgOQ=="
+    },
+    "node_modules/@vue/reactivity": {
+      "version": "3.2.45",
+      "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.2.45.tgz",
+      "integrity": "sha512-PRvhCcQcyEVohW0P8iQ7HDcIOXRjZfAsOds3N99X/Dzewy8TVhTCT4uXpAHfoKjVTJRA0O0K+6QNkDIZAxNi3A==",
+      "dependencies": {
+        "@vue/shared": "3.2.45"
+      }
+    },
+    "node_modules/@vue/reactivity-transform": {
+      "version": "3.2.45",
+      "resolved": "https://registry.npmmirror.com/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz",
+      "integrity": "sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ==",
+      "dependencies": {
+        "@babel/parser": "^7.16.4",
+        "@vue/compiler-core": "3.2.45",
+        "@vue/shared": "3.2.45",
+        "estree-walker": "^2.0.2",
+        "magic-string": "^0.25.7"
+      }
+    },
+    "node_modules/@vue/runtime-core": {
+      "version": "3.2.45",
+      "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.2.45.tgz",
+      "integrity": "sha512-gzJiTA3f74cgARptqzYswmoQx0fIA+gGYBfokYVhF8YSXjWTUA2SngRzZRku2HbGbjzB6LBYSbKGIaK8IW+s0A==",
+      "dependencies": {
+        "@vue/reactivity": "3.2.45",
+        "@vue/shared": "3.2.45"
+      }
+    },
+    "node_modules/@vue/runtime-dom": {
+      "version": "3.2.45",
+      "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz",
+      "integrity": "sha512-cy88YpfP5Ue2bDBbj75Cb4bIEZUMM/mAkDMfqDTpUYVgTf/kuQ2VQ8LebuZ8k6EudgH8pYhsGWHlY0lcxlvTwA==",
+      "dependencies": {
+        "@vue/runtime-core": "3.2.45",
+        "@vue/shared": "3.2.45",
+        "csstype": "^2.6.8"
+      }
+    },
+    "node_modules/@vue/server-renderer": {
+      "version": "3.2.45",
+      "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.2.45.tgz",
+      "integrity": "sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g==",
+      "dependencies": {
+        "@vue/compiler-ssr": "3.2.45",
+        "@vue/shared": "3.2.45"
+      },
+      "peerDependencies": {
+        "vue": "3.2.45"
+      }
+    },
+    "node_modules/@vue/shared": {
+      "version": "3.2.45",
+      "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.2.45.tgz",
+      "integrity": "sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg=="
+    },
+    "node_modules/@vueuse/core": {
+      "version": "9.6.0",
+      "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-9.6.0.tgz",
+      "integrity": "sha512-qGUcjKQXHgN+jqXEgpeZGoxdCbIDCdVPz3QiF1uyecVGbMuM63o96I1GjYx5zskKgRI0FKSNsVWM7rwrRMTf6A==",
+      "dependencies": {
+        "@types/web-bluetooth": "^0.0.16",
+        "@vueuse/metadata": "9.6.0",
+        "@vueuse/shared": "9.6.0",
+        "vue-demi": "*"
+      }
+    },
+    "node_modules/@vueuse/metadata": {
+      "version": "9.6.0",
+      "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.6.0.tgz",
+      "integrity": "sha512-sIC8R+kWkIdpi5X2z2Gk8TRYzmczDwHRhEFfCu2P+XW2JdPoXrziqsGpDDsN7ykBx4ilwieS7JUIweVGhvZ93w=="
+    },
+    "node_modules/@vueuse/shared": {
+      "version": "9.6.0",
+      "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.6.0.tgz",
+      "integrity": "sha512-/eDchxYYhkHnFyrb00t90UfjCx94kRHxc7J1GtBCqCG4HyPMX+krV9XJgVtWIsAMaxKVU4fC8NSUviG1JkwhUQ==",
+      "dependencies": {
+        "vue-demi": "*"
+      }
+    },
+    "node_modules/@wangeditor/basic-modules": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/basic-modules/-/basic-modules-1.1.7.tgz",
+      "integrity": "sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==",
+      "peer": true,
+      "dependencies": {
+        "is-url": "^1.2.4"
+      },
+      "peerDependencies": {
+        "@wangeditor/core": "1.x",
+        "dom7": "^3.0.0",
+        "lodash.throttle": "^4.1.1",
+        "nanoid": "^3.2.0",
+        "slate": "^0.72.0",
+        "snabbdom": "^3.1.0"
+      }
+    },
+    "node_modules/@wangeditor/code-highlight": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/code-highlight/-/code-highlight-1.0.3.tgz",
+      "integrity": "sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==",
+      "peer": true,
+      "dependencies": {
+        "prismjs": "^1.23.0"
+      },
+      "peerDependencies": {
+        "@wangeditor/core": "1.x",
+        "dom7": "^3.0.0",
+        "slate": "^0.72.0",
+        "snabbdom": "^3.1.0"
+      }
+    },
+    "node_modules/@wangeditor/core": {
+      "version": "1.1.19",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/core/-/core-1.1.19.tgz",
+      "integrity": "sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==",
+      "peer": true,
+      "dependencies": {
+        "@types/event-emitter": "^0.3.3",
+        "event-emitter": "^0.3.5",
+        "html-void-elements": "^2.0.0",
+        "i18next": "^20.4.0",
+        "scroll-into-view-if-needed": "^2.2.28",
+        "slate-history": "^0.66.0"
+      },
+      "peerDependencies": {
+        "@uppy/core": "^2.1.1",
+        "@uppy/xhr-upload": "^2.0.3",
+        "dom7": "^3.0.0",
+        "is-hotkey": "^0.2.0",
+        "lodash.camelcase": "^4.3.0",
+        "lodash.clonedeep": "^4.5.0",
+        "lodash.debounce": "^4.0.8",
+        "lodash.foreach": "^4.5.0",
+        "lodash.isequal": "^4.5.0",
+        "lodash.throttle": "^4.1.1",
+        "lodash.toarray": "^4.4.0",
+        "nanoid": "^3.2.0",
+        "slate": "^0.72.0",
+        "snabbdom": "^3.1.0"
+      }
+    },
+    "node_modules/@wangeditor/editor": {
+      "version": "5.1.23",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/editor/-/editor-5.1.23.tgz",
+      "integrity": "sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==",
+      "peer": true,
+      "dependencies": {
+        "@uppy/core": "^2.1.1",
+        "@uppy/xhr-upload": "^2.0.3",
+        "@wangeditor/basic-modules": "^1.1.7",
+        "@wangeditor/code-highlight": "^1.0.3",
+        "@wangeditor/core": "^1.1.19",
+        "@wangeditor/list-module": "^1.0.5",
+        "@wangeditor/table-module": "^1.1.4",
+        "@wangeditor/upload-image-module": "^1.0.2",
+        "@wangeditor/video-module": "^1.1.4",
+        "dom7": "^3.0.0",
+        "is-hotkey": "^0.2.0",
+        "lodash.camelcase": "^4.3.0",
+        "lodash.clonedeep": "^4.5.0",
+        "lodash.debounce": "^4.0.8",
+        "lodash.foreach": "^4.5.0",
+        "lodash.isequal": "^4.5.0",
+        "lodash.throttle": "^4.1.1",
+        "lodash.toarray": "^4.4.0",
+        "nanoid": "^3.2.0",
+        "slate": "^0.72.0",
+        "snabbdom": "^3.1.0"
+      }
+    },
+    "node_modules/@wangeditor/editor-for-vue": {
+      "version": "5.1.12",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/editor-for-vue/-/editor-for-vue-5.1.12.tgz",
+      "integrity": "sha512-0Ds3D8I+xnpNWezAeO7HmPRgTfUxHLMd9JKcIw+QzvSmhC5xUHbpCcLU+KLmeBKTR/zffnS5GQo6qi3GhTMJWQ==",
+      "peerDependencies": {
+        "@wangeditor/editor": ">=5.1.0",
+        "vue": "^3.0.5"
+      }
+    },
+    "node_modules/@wangeditor/list-module": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/list-module/-/list-module-1.0.5.tgz",
+      "integrity": "sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==",
+      "peer": true,
+      "peerDependencies": {
+        "@wangeditor/core": "1.x",
+        "dom7": "^3.0.0",
+        "slate": "^0.72.0",
+        "snabbdom": "^3.1.0"
+      }
+    },
+    "node_modules/@wangeditor/table-module": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/table-module/-/table-module-1.1.4.tgz",
+      "integrity": "sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==",
+      "peer": true,
+      "peerDependencies": {
+        "@wangeditor/core": "1.x",
+        "dom7": "^3.0.0",
+        "lodash.isequal": "^4.5.0",
+        "lodash.throttle": "^4.1.1",
+        "nanoid": "^3.2.0",
+        "slate": "^0.72.0",
+        "snabbdom": "^3.1.0"
+      }
+    },
+    "node_modules/@wangeditor/upload-image-module": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/upload-image-module/-/upload-image-module-1.0.2.tgz",
+      "integrity": "sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==",
+      "peer": true,
+      "peerDependencies": {
+        "@uppy/core": "^2.0.3",
+        "@uppy/xhr-upload": "^2.0.3",
+        "@wangeditor/basic-modules": "1.x",
+        "@wangeditor/core": "1.x",
+        "dom7": "^3.0.0",
+        "lodash.foreach": "^4.5.0",
+        "slate": "^0.72.0",
+        "snabbdom": "^3.1.0"
+      }
+    },
+    "node_modules/@wangeditor/video-module": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/video-module/-/video-module-1.1.4.tgz",
+      "integrity": "sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==",
+      "peer": true,
+      "peerDependencies": {
+        "@uppy/core": "^2.1.4",
+        "@uppy/xhr-upload": "^2.0.7",
+        "@wangeditor/core": "1.x",
+        "dom7": "^3.0.0",
+        "nanoid": "^3.2.0",
+        "slate": "^0.72.0",
+        "snabbdom": "^3.1.0"
+      }
+    },
+    "node_modules/async-validator": {
+      "version": "4.2.5",
+      "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz",
+      "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
+    },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+    },
+    "node_modules/axios": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmmirror.com/axios/-/axios-1.6.0.tgz",
+      "integrity": "sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==",
+      "dependencies": {
+        "follow-redirects": "^1.15.0",
+        "form-data": "^4.0.0",
+        "proxy-from-env": "^1.1.0"
+      }
+    },
+    "node_modules/call-bind": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.7.tgz",
+      "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+      "dependencies": {
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
+        "set-function-length": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/clone": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmmirror.com/clone/-/clone-2.1.2.tgz",
+      "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/compute-scroll-into-view": {
+      "version": "1.0.20",
+      "resolved": "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz",
+      "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==",
+      "peer": true
+    },
+    "node_modules/csstype": {
+      "version": "2.6.21",
+      "resolved": "https://registry.npmmirror.com/csstype/-/csstype-2.6.21.tgz",
+      "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w=="
+    },
+    "node_modules/d": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/d/-/d-1.0.2.tgz",
+      "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==",
+      "peer": true,
+      "dependencies": {
+        "es5-ext": "^0.10.64",
+        "type": "^2.7.2"
+      },
+      "engines": {
+        "node": ">=0.12"
+      }
+    },
+    "node_modules/dayjs": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.6.tgz",
+      "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ=="
+    },
+    "node_modules/deep-equal": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmmirror.com/deep-equal/-/deep-equal-1.1.2.tgz",
+      "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==",
+      "dependencies": {
+        "is-arguments": "^1.1.1",
+        "is-date-object": "^1.0.5",
+        "is-regex": "^1.1.4",
+        "object-is": "^1.1.5",
+        "object-keys": "^1.1.1",
+        "regexp.prototype.flags": "^1.5.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/define-data-property": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz",
+      "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+      "dependencies": {
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/define-properties": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmmirror.com/define-properties/-/define-properties-1.2.1.tgz",
+      "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+      "dependencies": {
+        "define-data-property": "^1.0.1",
+        "has-property-descriptors": "^1.0.0",
+        "object-keys": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/dom7": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmmirror.com/dom7/-/dom7-3.0.0.tgz",
+      "integrity": "sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==",
+      "peer": true,
+      "dependencies": {
+        "ssr-window": "^3.0.0-alpha.1"
+      }
+    },
+    "node_modules/element-plus": {
+      "version": "2.2.25",
+      "resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.2.25.tgz",
+      "integrity": "sha512-HC8CWY31e6pPyBpgqI0QnWkBgs0vRzdYnEw3mpdM/NlKfp0PtNFX7NESQLomqoIulH5ftL09hjQmJNvZBQpthQ==",
+      "dependencies": {
+        "@ctrl/tinycolor": "^3.4.1",
+        "@element-plus/icons-vue": "^2.0.6",
+        "@floating-ui/dom": "^1.0.1",
+        "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
+        "@types/lodash": "^4.14.182",
+        "@types/lodash-es": "^4.17.6",
+        "@vueuse/core": "^9.1.0",
+        "async-validator": "^4.2.5",
+        "dayjs": "^1.11.3",
+        "escape-html": "^1.0.3",
+        "lodash": "^4.17.21",
+        "lodash-es": "^4.17.21",
+        "lodash-unified": "^1.0.2",
+        "memoize-one": "^6.0.0",
+        "normalize-wheel-es": "^1.2.0"
+      },
+      "peerDependencies": {
+        "vue": "^3.2.0"
+      }
+    },
+    "node_modules/es-define-property": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.0.tgz",
+      "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+      "dependencies": {
+        "get-intrinsic": "^1.2.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-errors": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz",
+      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es5-ext": {
+      "version": "0.10.64",
+      "resolved": "https://registry.npmmirror.com/es5-ext/-/es5-ext-0.10.64.tgz",
+      "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==",
+      "hasInstallScript": true,
+      "peer": true,
+      "dependencies": {
+        "es6-iterator": "^2.0.3",
+        "es6-symbol": "^3.1.3",
+        "esniff": "^2.0.1",
+        "next-tick": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/es6-iterator": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmmirror.com/es6-iterator/-/es6-iterator-2.0.3.tgz",
+      "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+      "peer": true,
+      "dependencies": {
+        "d": "1",
+        "es5-ext": "^0.10.35",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "node_modules/es6-symbol": {
+      "version": "3.1.4",
+      "resolved": "https://registry.npmmirror.com/es6-symbol/-/es6-symbol-3.1.4.tgz",
+      "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==",
+      "peer": true,
+      "dependencies": {
+        "d": "^1.0.2",
+        "ext": "^1.7.0"
+      },
+      "engines": {
+        "node": ">=0.12"
+      }
+    },
+    "node_modules/esbuild": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.15.18.tgz",
+      "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==",
+      "dev": true,
+      "hasInstallScript": true,
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "optionalDependencies": {
+        "@esbuild/android-arm": "0.15.18",
+        "@esbuild/linux-loong64": "0.15.18",
+        "esbuild-android-64": "0.15.18",
+        "esbuild-android-arm64": "0.15.18",
+        "esbuild-darwin-64": "0.15.18",
+        "esbuild-darwin-arm64": "0.15.18",
+        "esbuild-freebsd-64": "0.15.18",
+        "esbuild-freebsd-arm64": "0.15.18",
+        "esbuild-linux-32": "0.15.18",
+        "esbuild-linux-64": "0.15.18",
+        "esbuild-linux-arm": "0.15.18",
+        "esbuild-linux-arm64": "0.15.18",
+        "esbuild-linux-mips64le": "0.15.18",
+        "esbuild-linux-ppc64le": "0.15.18",
+        "esbuild-linux-riscv64": "0.15.18",
+        "esbuild-linux-s390x": "0.15.18",
+        "esbuild-netbsd-64": "0.15.18",
+        "esbuild-openbsd-64": "0.15.18",
+        "esbuild-sunos-64": "0.15.18",
+        "esbuild-windows-32": "0.15.18",
+        "esbuild-windows-64": "0.15.18",
+        "esbuild-windows-arm64": "0.15.18"
+      }
+    },
+    "node_modules/esbuild-android-64": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz",
+      "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-android-arm64": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz",
+      "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-darwin-64": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz",
+      "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-darwin-arm64": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz",
+      "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-freebsd-64": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz",
+      "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-freebsd-arm64": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz",
+      "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-linux-32": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz",
+      "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-linux-64": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz",
+      "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-linux-arm": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz",
+      "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-linux-arm64": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz",
+      "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-linux-mips64le": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz",
+      "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-linux-ppc64le": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz",
+      "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-linux-riscv64": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz",
+      "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-linux-s390x": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz",
+      "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-netbsd-64": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz",
+      "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-openbsd-64": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz",
+      "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-sunos-64": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz",
+      "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-windows-32": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz",
+      "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-windows-64": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz",
+      "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-windows-arm64": {
+      "version": "0.15.18",
+      "resolved": "https://registry.npmmirror.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz",
+      "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+    },
+    "node_modules/esniff": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/esniff/-/esniff-2.0.1.tgz",
+      "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==",
+      "peer": true,
+      "dependencies": {
+        "d": "^1.0.1",
+        "es5-ext": "^0.10.62",
+        "event-emitter": "^0.3.5",
+        "type": "^2.7.2"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/estree-walker": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz",
+      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
+    },
+    "node_modules/event-emitter": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmmirror.com/event-emitter/-/event-emitter-0.3.5.tgz",
+      "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
+      "peer": true,
+      "dependencies": {
+        "d": "1",
+        "es5-ext": "~0.10.14"
+      }
+    },
+    "node_modules/eventemitter3": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-2.0.3.tgz",
+      "integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg=="
+    },
+    "node_modules/ext": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmmirror.com/ext/-/ext-1.7.0.tgz",
+      "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
+      "peer": true,
+      "dependencies": {
+        "type": "^2.7.2"
+      }
+    },
+    "node_modules/extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+    },
+    "node_modules/fast-diff": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmmirror.com/fast-diff/-/fast-diff-1.1.2.tgz",
+      "integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig=="
+    },
+    "node_modules/follow-redirects": {
+      "version": "1.15.2",
+      "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz",
+      "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/form-data": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz",
+      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
+    },
+    "node_modules/functions-have-names": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz",
+      "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="
+    },
+    "node_modules/get-intrinsic": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+      "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "has-proto": "^1.0.1",
+        "has-symbols": "^1.0.3",
+        "hasown": "^2.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/gopd": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.0.1.tgz",
+      "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+      "dependencies": {
+        "get-intrinsic": "^1.1.3"
+      }
+    },
+    "node_modules/has-property-descriptors": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+      "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+      "dependencies": {
+        "es-define-property": "^1.0.0"
+      }
+    },
+    "node_modules/has-proto": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.3.tgz",
+      "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz",
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/has-tostringtag": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+      "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+      "dependencies": {
+        "has-symbols": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/hasown": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
+      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+      "dependencies": {
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/html-void-elements": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/html-void-elements/-/html-void-elements-2.0.1.tgz",
+      "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==",
+      "peer": true
+    },
+    "node_modules/i18next": {
+      "version": "20.6.1",
+      "resolved": "https://registry.npmmirror.com/i18next/-/i18next-20.6.1.tgz",
+      "integrity": "sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==",
+      "peer": true,
+      "dependencies": {
+        "@babel/runtime": "^7.12.0"
+      }
+    },
+    "node_modules/immer": {
+      "version": "9.0.21",
+      "resolved": "https://registry.npmmirror.com/immer/-/immer-9.0.21.tgz",
+      "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==",
+      "peer": true
+    },
+    "node_modules/is-arguments": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmmirror.com/is-arguments/-/is-arguments-1.1.1.tgz",
+      "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/is-core-module": {
+      "version": "2.13.1",
+      "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.13.1.tgz",
+      "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
+      "dev": true,
+      "dependencies": {
+        "hasown": "^2.0.0"
+      }
+    },
+    "node_modules/is-date-object": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmmirror.com/is-date-object/-/is-date-object-1.0.5.tgz",
+      "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
+      "dependencies": {
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/is-hotkey": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmmirror.com/is-hotkey/-/is-hotkey-0.2.0.tgz",
+      "integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==",
+      "peer": true
+    },
+    "node_modules/is-plain-object": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-5.0.0.tgz",
+      "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-regex": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmmirror.com/is-regex/-/is-regex-1.1.4.tgz",
+      "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/is-url": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmmirror.com/is-url/-/is-url-1.2.4.tgz",
+      "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==",
+      "peer": true
+    },
+    "node_modules/lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+    },
+    "node_modules/lodash-es": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz",
+      "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
+    },
+    "node_modules/lodash-unified": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz",
+      "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==",
+      "peerDependencies": {
+        "@types/lodash-es": "*",
+        "lodash": "*",
+        "lodash-es": "*"
+      }
+    },
+    "node_modules/lodash.camelcase": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmmirror.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+      "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
+      "peer": true
+    },
+    "node_modules/lodash.clonedeep": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmmirror.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+      "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
+      "peer": true
+    },
+    "node_modules/lodash.debounce": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+      "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
+      "peer": true
+    },
+    "node_modules/lodash.foreach": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmmirror.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
+      "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==",
+      "peer": true
+    },
+    "node_modules/lodash.isequal": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmmirror.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+      "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
+      "peer": true
+    },
+    "node_modules/lodash.throttle": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmmirror.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
+      "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==",
+      "peer": true
+    },
+    "node_modules/lodash.toarray": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmmirror.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
+      "integrity": "sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==",
+      "peer": true
+    },
+    "node_modules/magic-string": {
+      "version": "0.25.9",
+      "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.25.9.tgz",
+      "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==",
+      "dependencies": {
+        "sourcemap-codec": "^1.4.8"
+      }
+    },
+    "node_modules/memoize-one": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz",
+      "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
+    },
+    "node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/mime-match/-/mime-match-1.0.2.tgz",
+      "integrity": "sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==",
+      "peer": true,
+      "dependencies": {
+        "wildcard": "^1.1.0"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/namespace-emitter": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/namespace-emitter/-/namespace-emitter-2.0.1.tgz",
+      "integrity": "sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==",
+      "peer": true
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.7",
+      "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.7.tgz",
+      "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/next-tick": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/next-tick/-/next-tick-1.1.0.tgz",
+      "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==",
+      "peer": true
+    },
+    "node_modules/normalize-wheel-es": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz",
+      "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw=="
+    },
+    "node_modules/object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-inspect": {
+      "version": "1.12.2",
+      "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.2.tgz",
+      "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ=="
+    },
+    "node_modules/object-is": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmmirror.com/object-is/-/object-is-1.1.6.tgz",
+      "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/object-keys": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz",
+      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/parchment": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmmirror.com/parchment/-/parchment-1.1.4.tgz",
+      "integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg=="
+    },
+    "node_modules/path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+      "dev": true
+    },
+    "node_modules/picocolors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz",
+      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+    },
+    "node_modules/postcss": {
+      "version": "8.4.38",
+      "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.38.tgz",
+      "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
+      "dependencies": {
+        "nanoid": "^3.3.7",
+        "picocolors": "^1.0.0",
+        "source-map-js": "^1.2.0"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/preact": {
+      "version": "10.22.0",
+      "resolved": "https://registry.npmmirror.com/preact/-/preact-10.22.0.tgz",
+      "integrity": "sha512-RRurnSjJPj4rp5K6XoP45Ui33ncb7e4H7WiOHVpjbkvqvA3U+N8Z6Qbo0AE6leGYBV66n8EhEaFixvIu3SkxFw==",
+      "peer": true
+    },
+    "node_modules/prismjs": {
+      "version": "1.29.0",
+      "resolved": "https://registry.npmmirror.com/prismjs/-/prismjs-1.29.0.tgz",
+      "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==",
+      "peer": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/proxy-from-env": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+    },
+    "node_modules/qs": {
+      "version": "6.11.0",
+      "resolved": "https://registry.npmmirror.com/qs/-/qs-6.11.0.tgz",
+      "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+      "dependencies": {
+        "side-channel": "^1.0.4"
+      },
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/quill": {
+      "version": "1.3.7",
+      "resolved": "https://registry.npmmirror.com/quill/-/quill-1.3.7.tgz",
+      "integrity": "sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==",
+      "dependencies": {
+        "clone": "^2.1.1",
+        "deep-equal": "^1.0.1",
+        "eventemitter3": "^2.0.3",
+        "extend": "^3.0.2",
+        "parchment": "^1.1.4",
+        "quill-delta": "^3.6.2"
+      }
+    },
+    "node_modules/quill-delta": {
+      "version": "3.6.3",
+      "resolved": "https://registry.npmmirror.com/quill-delta/-/quill-delta-3.6.3.tgz",
+      "integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==",
+      "dependencies": {
+        "deep-equal": "^1.0.1",
+        "extend": "^3.0.2",
+        "fast-diff": "1.1.2"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/regenerator-runtime": {
+      "version": "0.14.1",
+      "resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+      "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
+      "peer": true
+    },
+    "node_modules/regexp.prototype.flags": {
+      "version": "1.5.2",
+      "resolved": "https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
+      "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==",
+      "dependencies": {
+        "call-bind": "^1.0.6",
+        "define-properties": "^1.2.1",
+        "es-errors": "^1.3.0",
+        "set-function-name": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/resolve": {
+      "version": "1.22.8",
+      "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.8.tgz",
+      "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
+      "dev": true,
+      "dependencies": {
+        "is-core-module": "^2.13.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      }
+    },
+    "node_modules/rollup": {
+      "version": "2.79.1",
+      "resolved": "https://registry.npmmirror.com/rollup/-/rollup-2.79.1.tgz",
+      "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
+      "dev": true,
+      "bin": {
+        "rollup": "dist/bin/rollup"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/scroll-into-view-if-needed": {
+      "version": "2.2.31",
+      "resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz",
+      "integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==",
+      "peer": true,
+      "dependencies": {
+        "compute-scroll-into-view": "^1.0.20"
+      }
+    },
+    "node_modules/set-function-length": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz",
+      "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+      "dependencies": {
+        "define-data-property": "^1.1.4",
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
+        "gopd": "^1.0.1",
+        "has-property-descriptors": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/set-function-name": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmmirror.com/set-function-name/-/set-function-name-2.0.2.tgz",
+      "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
+      "dependencies": {
+        "define-data-property": "^1.1.4",
+        "es-errors": "^1.3.0",
+        "functions-have-names": "^1.2.3",
+        "has-property-descriptors": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/side-channel": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz",
+      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+      "dependencies": {
+        "call-bind": "^1.0.0",
+        "get-intrinsic": "^1.0.2",
+        "object-inspect": "^1.9.0"
+      }
+    },
+    "node_modules/slate": {
+      "version": "0.72.8",
+      "resolved": "https://registry.npmmirror.com/slate/-/slate-0.72.8.tgz",
+      "integrity": "sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==",
+      "peer": true,
+      "dependencies": {
+        "immer": "^9.0.6",
+        "is-plain-object": "^5.0.0",
+        "tiny-warning": "^1.0.3"
+      }
+    },
+    "node_modules/slate-history": {
+      "version": "0.66.0",
+      "resolved": "https://registry.npmmirror.com/slate-history/-/slate-history-0.66.0.tgz",
+      "integrity": "sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==",
+      "peer": true,
+      "dependencies": {
+        "is-plain-object": "^5.0.0"
+      },
+      "peerDependencies": {
+        "slate": ">=0.65.3"
+      }
+    },
+    "node_modules/snabbdom": {
+      "version": "3.6.2",
+      "resolved": "https://registry.npmmirror.com/snabbdom/-/snabbdom-3.6.2.tgz",
+      "integrity": "sha512-ig5qOnCDbugFntKi6c7Xlib8bA6xiJVk8O+WdFrV3wxbMqeHO0hXFQC4nAhPVWfZfi8255lcZkNhtIBINCc4+Q==",
+      "peer": true,
+      "engines": {
+        "node": ">=12.17.0"
+      }
+    },
+    "node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-js": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.0.tgz",
+      "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sourcemap-codec": {
+      "version": "1.4.8",
+      "resolved": "https://registry.npmmirror.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
+      "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
+      "deprecated": "Please use @jridgewell/sourcemap-codec instead"
+    },
+    "node_modules/ssr-window": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmmirror.com/ssr-window/-/ssr-window-3.0.0.tgz",
+      "integrity": "sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==",
+      "peer": true
+    },
+    "node_modules/supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/tiny-warning": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/tiny-warning/-/tiny-warning-1.0.3.tgz",
+      "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
+      "peer": true
+    },
+    "node_modules/type": {
+      "version": "2.7.2",
+      "resolved": "https://registry.npmmirror.com/type/-/type-2.7.2.tgz",
+      "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==",
+      "peer": true
+    },
+    "node_modules/vite": {
+      "version": "3.2.10",
+      "resolved": "https://registry.npmmirror.com/vite/-/vite-3.2.10.tgz",
+      "integrity": "sha512-Dx3olBo/ODNiMVk/cA5Yft9Ws+snLOXrhLtrI3F4XLt4syz2Yg8fayZMWScPKoz12v5BUv7VEmQHnsfpY80fYw==",
+      "dev": true,
+      "dependencies": {
+        "esbuild": "^0.15.9",
+        "postcss": "^8.4.18",
+        "resolve": "^1.22.1",
+        "rollup": "^2.79.1"
+      },
+      "bin": {
+        "vite": "bin/vite.js"
+      },
+      "engines": {
+        "node": "^14.18.0 || >=16.0.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      },
+      "peerDependencies": {
+        "@types/node": ">= 14",
+        "less": "*",
+        "sass": "*",
+        "stylus": "*",
+        "sugarss": "*",
+        "terser": "^5.4.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "less": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "stylus": {
+          "optional": true
+        },
+        "sugarss": {
+          "optional": true
+        },
+        "terser": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vue": {
+      "version": "3.2.45",
+      "resolved": "https://registry.npmmirror.com/vue/-/vue-3.2.45.tgz",
+      "integrity": "sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA==",
+      "dependencies": {
+        "@vue/compiler-dom": "3.2.45",
+        "@vue/compiler-sfc": "3.2.45",
+        "@vue/runtime-dom": "3.2.45",
+        "@vue/server-renderer": "3.2.45",
+        "@vue/shared": "3.2.45"
+      }
+    },
+    "node_modules/vue-demi": {
+      "version": "0.13.11",
+      "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz",
+      "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
+      "hasInstallScript": true,
+      "bin": {
+        "vue-demi-fix": "bin/vue-demi-fix.js",
+        "vue-demi-switch": "bin/vue-demi-switch.js"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "peerDependencies": {
+        "@vue/composition-api": "^1.0.0-rc.1",
+        "vue": "^3.0.0-0 || ^2.6.0"
+      },
+      "peerDependenciesMeta": {
+        "@vue/composition-api": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vue-quill-editor": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmmirror.com/vue-quill-editor/-/vue-quill-editor-3.0.6.tgz",
+      "integrity": "sha512-g20oSZNWg8Hbu41Kinjd55e235qVWPLfg4NvsLW6d+DhgBTFbEuMpcWlUdrD6qT3+Noim6DRu18VLM9lVShXOQ==",
+      "dependencies": {
+        "object-assign": "^4.1.1",
+        "quill": "^1.3.4"
+      },
+      "engines": {
+        "node": ">= 4.0.0",
+        "npm": ">= 3.0.0"
+      }
+    },
+    "node_modules/vue-router": {
+      "version": "4.0.13",
+      "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.0.13.tgz",
+      "integrity": "sha512-LmXrC+BkDRLak+d5xTMgUYraT3Nj0H/vCbP+7usGvIl9Viqd1UP6AsP0i69pSbn9O0dXK/xCdp4yPw21HqV9Jw==",
+      "dependencies": {
+        "@vue/devtools-api": "^6.0.0"
+      },
+      "peerDependencies": {
+        "vue": "^3.2.0"
+      }
+    },
+    "node_modules/wildcard": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmmirror.com/wildcard/-/wildcard-1.1.2.tgz",
+      "integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==",
+      "peer": true
+    }
+  }
+}

+ 25 - 0
package.json

@@ -0,0 +1,25 @@
+{
+  "name": "vue3-zhifou",
+  "private": true,
+  "version": "0.0.0",
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "build": "vite build",
+    "preview": "vite preview"
+  },
+  "dependencies": {
+    "@element-plus/icons-vue": "^2.0.10",
+    "@wangeditor/editor-for-vue": "^5.1.12",
+    "axios": "^1.2.0",
+    "element-plus": "^2.2.25",
+    "qs": "^6.11.0",
+    "vue": "^3.2.41",
+    "vue-quill-editor": "^3.0.6",
+    "vue-router": "^4.0.13"
+  },
+  "devDependencies": {
+    "@vitejs/plugin-vue": "^3.2.0",
+    "vite": "^3.2.3"
+  }
+}

+ 1 - 0
public/vite.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

+ 9 - 0
src/App.vue

@@ -0,0 +1,9 @@
+<template>
+  <div>
+    <router-view></router-view>
+  </div>
+</template>
+<script setup>
+</script>
+<style scoped>
+</style>

+ 24 - 0
src/api/contents.js

@@ -0,0 +1,24 @@
+import http from '../utils/http/http.js'
+// 获取资源列表
+const  getAllrecruit=  (params) => {
+    return http.post('/allrecruit', params)
+};
+// 获取资源详情
+const  getRecruitDetail= (params) => {
+    return http.get('/recruit', params)
+};
+// 添加资源
+const   addRecruit= (params) => {
+    return http.post('/recruit', params)
+};
+// 修改资源
+const   updateRecruit=(params) => {
+    return http.put('/recruit', params)
+};
+// 删除资源
+const   deleteRecruit= (params) => {
+    return http.del('/recruit', params)
+}
+export default {
+    getAllrecruit, deleteRecruit, updateRecruit, addRecruit, getRecruitDetail
+}

+ 24 - 0
src/api/product.js

@@ -0,0 +1,24 @@
+import http from '../utils/http/http.js'
+// 获取资源列表
+const  getProductList=  (params) => {
+    return http.post('/productAll', params)
+};
+// 获取资源详情
+const   getProductDetail= (params) => {
+    return http.get('/product', params)
+};
+// 添加资源
+const   addProduct= (params) => {
+    return http.post('/product', params)
+};
+// 修改资源
+const  updateProduct=(params) => {
+    return http.put('/product', params)
+};
+// 删除资源
+const   deleteProduct= (params) => {
+    return http.del('/product', params)
+}
+export default {
+    getProductList, getProductDetail, addProduct, updateProduct, deleteProduct
+}

+ 28 - 0
src/api/resource.js

@@ -0,0 +1,28 @@
+import http from '../utils/http/http.js'
+// 获取资源列表
+const getResourceList = (params) => {
+    return http.post('/resource', params)
+};
+// 获取资源详情
+const getResourceDetail = (params) => {
+    return http.get('/resource', params)
+};
+// 添加资源
+const addResource = (params) => {
+    return http.post('/upload', params)
+};
+// 修改资源
+const updateResource = (params) => {
+    return http.put('/updateResource', params)
+};
+// 删除资源
+const deleteResource = (params) => {
+    return http.del('/resource', params)
+}
+const uploadResource = (params) => {
+    return http.post('/upload', params)
+}
+
+export default {
+    getResourceList, getResourceDetail, addResource, updateResource, deleteResource,uploadResource
+}

+ 27 - 0
src/api/serve.js

@@ -0,0 +1,27 @@
+import http from '../utils/http/http.js'
+// 获取资源列表
+const  getAllService=  (params) => {
+    return http.post('/allservice', params)
+};
+// 获取资源详情
+const  getServiceDetail= (params) => {
+    return http.get('/service', params)
+};
+// 添加资源
+const   addService= (params) => {
+    return http.post('/service', params)
+};
+// 修改资源
+const   updateService=(params) => {
+    return http.put('/service', params)
+};
+// 删除资源
+const   deleteService= (params) => {
+    return http.del('/service', params)
+}
+const   GetServiceType= (params) => {
+    return http.get('/getservice', params)
+}
+export default {
+    deleteService, updateService, addService, getServiceDetail,getAllService,GetServiceType
+}

+ 20 - 0
src/api/user.js

@@ -0,0 +1,20 @@
+import http from '../utils/http/http.js'
+
+const login = (data) => {
+    return http.post("/logon", data);
+};
+const getUserList = (data) => {
+    return http.get("/user/list", data);
+};
+const saveUser = (data) => {
+    return http.post("/user/save", data);
+};
+const delUser = (data) => {
+    return http.del("/user/delete", data);
+};
+const getUserDetail = (data) => {
+    return http.get("/user/detail", data);
+};
+export default {
+    login, getUserList, saveUser, delUser, getUserDetail
+}

BIN
src/assets/img/avator.jpg


BIN
src/assets/img/bg.jpg


BIN
src/assets/img/favicon.ico


BIN
src/assets/img/index.gif


BIN
src/assets/img/index.jpg


+ 10 - 0
src/assets/js/common.js

@@ -0,0 +1,10 @@
+import router from '../../router/index.js'
+export default {
+  // 路由跳转
+  changeView(url, queryParams) {
+    router.push({
+      path: url,
+      query: queryParams,
+    })
+  }
+}

+ 5 - 0
src/assets/js/constant.js

@@ -0,0 +1,5 @@
+// 全局变量
+export default {
+  name: '知否君',
+  officialAccount: '知否技术'
+}

+ 1 - 0
src/assets/vue.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

+ 18 - 0
src/components/HelloWorld.vue

@@ -0,0 +1,18 @@
+<template>
+  <div>
+    {{ name }}
+  </div>
+</template>
+
+<script setup lang="ts">
+import { onMounted, ref } from 'vue';
+import userApi from '../api/user'
+const name = ref("关亚奇");
+  onMounted(() => {
+    userApi.getUserList().then(res=>{
+      console.log('------->');
+      console.log(res);
+    })
+  })
+</script>
+

+ 82 - 0
src/components/Home.vue

@@ -0,0 +1,82 @@
+<template>
+  <div>
+    <p>{{ msg }}</p>
+    <p>姓名:{{ user.name }}</p>
+    <p>年龄:{{ user.age }}</p>
+    <button @click="changeAge">点击</button>
+    <p>单独姓名:{{ name }}</p>
+    <button @click="changeName">修改姓名</button>
+    <p>单独年龄:{{ age }}</p>
+    <button @click="changeRefAge">修改年龄</button>
+    <p>诗人:{{ poet }}</p>
+    <button @click="changePoet">修改诗人</button>
+    <p>computed:{{ newPoet }}</p>
+    <!-- 父子传值 -->
+    <Son :user="user" />
+  </div>
+</template>
+<script >
+import { reactive, ref, toRef, toRefs } from "@vue/reactivity";
+import { computed, watch, provide } from "vue";
+import Son from "./Son.vue";
+export default {
+  components: {
+    Son,
+  },
+  setup() {
+    let msg = "hello";
+    // reactive是一个函数,它可以将复杂数据类型变成响应式数据。
+    let user = reactive({
+      name: "张无忌",
+      age: 12,
+    });
+    const changeAge = () => {
+      user.age++;
+    };
+    // toRef是函数,将对象中某个属性为单独的响应式数据
+    const name = toRef(user, "name");
+    const changeName = () => {
+      name.value = "赵敏";
+    };
+    // toRefs是函数,将对象中所有属性为单独响应式数据
+    const refUser = toRefs(user);
+    const changeRefAge = () => {
+      refUser.age.value = 18;
+    };
+    //   ref函数,常用于简单数据类型定义为响应式数据,再修改值,获取值的时候,需要.value
+    let poet = ref("李白");
+    const changePoet = () => {
+      poet.value = "杜甫";
+    };
+    // computed 计算
+    const newPoet = computed(() => {
+      return poet.value + ",白居易";
+    });
+    // watch 监听
+    watch(user, () => {
+      console.log("user改变了");
+    });
+    watch(
+      () => user.age,
+      () => {
+        console.log("age改变了");
+      }
+    );
+    // provide
+    provide("poet", poet);
+    provide("changePoet", changePoet);
+    return {
+      msg,
+      user,
+      name,
+      changeAge,
+      changeName,
+      changeRefAge,
+      ...refUser,
+      poet,
+      changePoet,
+      newPoet,
+    };
+  },
+};
+</script>

+ 22 - 0
src/main.js

@@ -0,0 +1,22 @@
+import { createApp } from 'vue'
+import './style.css'
+import App from './App.vue'
+import router from './router/index.js'
+import locale from 'element-plus/lib/locale/lang/zh-cn'
+import ElementPlus from 'element-plus'
+import 'element-plus/dist/index.css'
+import * as Icons from '@element-plus/icons-vue'
+import commonJs from './assets/js/common'
+import QuillEditor from 'vue-quill-editor'
+// 引入富文本组件样式
+import 'quill/dist/quill.core.css'
+import 'quill/dist/quill.snow.css'
+import 'quill/dist/quill.bubble.css'
+const app = createApp(App)
+for (let i in Icons) {
+    app.component(i, Icons[i])
+}
+app.use(router).use(ElementPlus, { locale })
+app.use(QuillEditor)
+app.config.globalProperties.$commonJs = commonJs
+app.mount('#app')

+ 136 - 0
src/router/index.js

@@ -0,0 +1,136 @@
+import { createRouter, createWebHashHistory } from 'vue-router'
+const routes = [
+    {
+        path: '/',
+        redirect: '/login'
+    },
+    {
+        path: '/login',
+        name: 'login',
+        meta: {
+            title: '登录'
+        },
+        component: () => import('../view/Login.vue')
+    },
+    {
+        path: '/home',
+        name: '主页',
+        meta: {
+            title: '主页'
+        },
+        component: () => import('../view/Home.vue'),
+        redirect: '/index',
+        children: [
+            {
+                path: '/index',
+                meta: {
+                    title: '首页'
+                },
+                component: () => import('../view/Welcome.vue')
+            },
+            {
+                path: '/user/list',
+                meta: {
+                    title: '资源管理'
+                },
+                component: () => import('../view/resource/Index.vue'),
+            },
+            {
+                path: '/product/list',
+                meta: {
+                    title: '产品管理'
+                },
+                component: () => import('../view/product/product.vue'),
+            },
+            {
+                path: '/product/detail',
+                meta: {
+                    title: '产品详情'
+                },
+                component: () => import('../view/product/Detail.vue'),
+            },
+            {
+                path: '/product/add',
+                meta: {
+                    title: '添加产品'
+                },
+                component: () => import('../view/product/add.vue'),
+            },
+            {
+                path: '/contents/list',
+                meta: {
+                    title: '招募和新闻管理'
+                },
+                component: () => import('../view/contents/contents.vue'),
+            },
+            {
+                path: '/contents/detail',
+                meta: {
+                    title: '招募和新闻详情'
+                },
+                component: () => import('../view/contents/Detail.vue'),
+            },
+            {
+                path: '/contents/add',
+                meta: {
+                    title: '添加招募和新闻详情'
+                },
+                component: () => import('../view/contents/add.vue'),
+            },
+            {
+                path: '/serves/add',
+                meta: {
+                    title: '添加服务'
+                },
+                component: () => import('../view/serve/add.vue'),
+            },
+            {
+                path: '/serves/detail',
+                meta: {
+                    title: '服务详情'
+                },
+                component: () => import('../view/serve/Detail.vue'),
+            },
+            {
+                path: '/serves/list',
+                meta: {
+                    title: '服务管理'
+                },
+                component: () => import('../view/serve/serves.vue'),
+            },
+            {
+                path: '/user/detail',
+                meta: {
+                    title: '用户详情'
+                },
+                component: () => import('../view/resource/Detail.vue'),
+            },
+        ]
+    },
+]
+const router = createRouter({
+    history: createWebHashHistory(),
+    routes
+})
+// 挂载路由导航守卫:to表示将要访问的路径,from表示从哪里来,next是下一个要做的操作
+router.beforeEach((to, from, next) => {
+    // 修改页面 title
+    if (to.meta.title) {
+      document.title = '知否课堂后台管理系统 - ' + to.meta.title
+    }
+    // 放行登录页面
+    if (to.path === '/login') {
+      return next()
+    }
+    // 获取token
+    // const token= sessionStorage.getItem('token')
+    // if (!token) {
+    //   return next('/login')
+    // } else {
+    //   next()
+    // }
+    return next()
+  })
+  
+// 导出路由
+export default router

+ 17 - 0
src/style.css

@@ -0,0 +1,17 @@
+html,
+body {
+    padding: 0px;
+    margin: 0px;
+    height: 100%;
+    background: #fff;
+}
+
+/* 表格统一样式 */
+.el-table .el-table__header-wrapper thead th,
+.el-table .el-table__fixed-header-wrapper thead th {
+    padding: 0;
+    background-color: #F9F9F9;
+    height: 50px;
+    line-height: 40px;
+    color: #283543;
+}

+ 81 - 0
src/utils/http/axios.js

@@ -0,0 +1,81 @@
+import axios from "axios";
+import {ElMessage} from 'element-plus'
+// 1. 创建axios实例
+const instance = axios.create({
+    // 接口
+    baseURL: "http://localhost:8080/api",
+    // 超时时间
+    timeout: 50000,
+});
+// 2.请求拦截
+instance.interceptors.request.use(
+    config => {
+        let token = sessionStorage.getItem('token')
+        if (token) {
+            config.headers['token'] = token
+        }
+        return config;
+    },
+    error => {
+        //  请求发生错误,抛出异常
+        Promise.reject(error);
+    }
+);
+
+// 3.响应拦截
+instance.interceptors.response.use(
+    res => {
+        return res;
+    },
+    error => {
+        if (error && error.response) {
+            const status = error.response.status
+            switch (status) {
+                case 400:
+                    ElMessage.error("请求错误");
+                    break;
+                case 401:
+                    ElMessage.error("未授权,请重新登录");
+                    break;
+                case 403:
+                    ElMessage.error("拒绝访问");
+                    break;
+                case 404:
+                    ElMessage.error("请求错误,未找到相应的资源");
+                    break;
+                case 408:
+                    ElMessage.error("请求超时");
+                    break;
+                case 500:
+                    ElMessage.error("服务器内部错误");
+                    break;
+                case 501:
+                    ElMessage.error("网络未实现");
+                    break;
+                case 502:
+                    ElMessage.error("网络错误");
+                    break;
+                case 503:
+                    ElMessage.error("服务不可用");
+                    break;
+                case 504:
+                    ElMessage.error("网络超时");
+                    break;
+                case 505:
+                    ElMessage.error("HTTP版本不支持该请求");
+                    break;
+                default:
+                    ElMessage.error("请求失败");
+            }
+        } else {
+            if (JSON.stringify(error).includes("timeout")) {
+                ElMessage.error("服务器响应超时,请刷新页面");
+            }
+            ElMessage.error("连接服务器失败");
+        }
+        return Promise.reject(error);
+    }
+);
+// 4.导出 axios 实例
+export default instance;
+

+ 43 - 0
src/utils/http/http.js

@@ -0,0 +1,43 @@
+import instance from "./axios"
+
+const post = (url, data) => {
+    return new Promise((resolve, reject) => {
+        instance.post(url, data).then(res => {
+            resolve(res)
+        }).catch(err => {
+            reject(err)
+        })
+    })
+}
+const get = (url, data) => {
+    return new Promise((resolve, reject) => {
+        instance.get(url, { params: data }).then(res => {
+            resolve(res)
+        }).catch(err => {
+            reject(err)
+        })
+    })
+}
+const put = (url, data) => {
+    return new Promise((resolve, reject) => {
+        instance.put(url, data).then(res => {
+            resolve(res)
+        }).catch(err => {
+            reject(err)
+        })
+    })
+}
+
+const del = (url, data) => {
+    return new Promise((resolve, reject) => {
+        instance.delete(url, { params: data }).then(res => {
+            resolve(res)
+        }).catch(err => {
+            reject(err)
+        })
+    })
+}
+
+export default {
+    post, get, put, del
+}

+ 95 - 0
src/view/EditorWithBinding.vue

@@ -0,0 +1,95 @@
+<template>
+  <div style="border: 1px solid #ccc; width: 100%; margin: 10px auto">
+    <Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" mode="default"/>
+    <Editor style="height: 500px; overflow-y: hidden" v-model="valueHtml" :defaultConfig="editorConfig" mode="default"
+            @onCreated="handleCreated" @customPaste="customPaste" @input="handleChange"/>
+  </div>
+<!--  <el-button style="margin: 0 auto" @click="getEditorHTML">获取富文本HTML内容</el-button>-->
+</template>
+<script setup>
+// 富文本编辑器文档链接: https://www.wangeditor.com/v5/getting-started.html
+// 引入富文本编辑器CSS
+import '@wangeditor/editor/dist/css/style.css';
+import {onBeforeUnmount, ref, shallowRef, watch,defineEmits} from 'vue';
+// 导入富文本编辑器的组件
+import {Editor, Toolbar} from '@wangeditor/editor-for-vue';
+import resource from "../api/resource.js";
+
+// 编辑器实例,必须用 shallowRef
+const editorRef = shallowRef();
+
+// 内容 HTML
+// const valueHtml = ref('');
+const toolbarConfig = {};
+const editorConfig = ref({placeholder: '请输入内容...', MENU_CONF: {}});
+// 新增 props
+const props = defineProps({
+  modelValue: {
+    type: String,
+    default: '',
+  },
+});
+
+// 新增 data
+const valueHtml = ref(props.modelValue);
+const emit=defineEmits(['input'])
+// 新增事件处理方法
+watch(
+    () => props.modelValue,
+    (newVal) => {
+      valueHtml.value = newVal; // 确保内部数据与外部modelValue同步
+    },
+    {immediate: true} // 立即执行,确保初始化时也能同步
+);
+const handleChange = (content) => {
+  console.log('content', content);
+  emit('input', editorRef.value.getHtml());
+};
+// 自定义图片上传
+editorConfig.value.MENU_CONF['uploadImage'] = {
+  async customUpload(file, insertFn) {
+    let dataForm = new FormData();
+    dataForm.append('types', "serve")
+    dataForm.append('file', file)
+    const fileRes = await resource.uploadResource(dataForm)
+    // 这里的file为上传的图片对象,insertFn传入
+    insertFn(fileRes.data.Data, 'img');
+  },
+};
+
+// 自定义视频上传
+editorConfig.value.MENU_CONF['uploadVideo'] = {
+  async customUpload(file, insertFn) {
+    // console.log('上传视频', file);
+  },
+};
+
+// 富文本编辑器生成后触发
+const handleCreated = editor => {
+  editorRef.value = editor; // 记录 editor 实例,重要!
+  // console.log(editorConfig.value.MENU_CONF, 'editorConfig.value');
+};
+
+// 监听富文本编辑器粘贴行为
+const customPaste = (editor, event, callback) => {
+  // 获取粘贴的纯文本
+  const text = event.clipboardData.getData('text/plain');
+  if (text) {
+    editor.insertText(text);
+    event.preventDefault();
+    callback(false);
+  }
+};
+
+// 获取富文本html内容
+const getEditorHTML = () => {
+  console.log(editorRef.value.getHtml());
+};
+
+// 组件销毁时,也及时销毁编辑器
+onBeforeUnmount(() => {
+  const editor = editorRef.value;
+  if (editor == null) return;
+  editor.destroy();
+});
+</script>

+ 181 - 0
src/view/Home.vue

@@ -0,0 +1,181 @@
+<template>
+    <div>
+        <el-container class="home-container">
+            <!-- header -->
+            <el-header>
+                <el-row>
+                    <el-col :span="4">
+                        <p class="system-name">宝智达冷链后台管理系统</p>
+                    </el-col>
+                    <el-col :offset="12" :span="8" style="min-width: 150px">
+                        <el-dropdown style="float: right; margin: 20px 10px">
+                            <span class="el-dropdown-link" style="color: #fff; cursor: pointer">
+                                管理员
+                            </span>
+                            <template #dropdown>
+                                <el-dropdown-menu>
+                                    <el-dropdown-item @click.native="logout">退出系统</el-dropdown-item>
+                                </el-dropdown-menu>
+                            </template>
+                        </el-dropdown>
+                    </el-col>
+                </el-row>
+            </el-header>
+
+            <el-container style="overflow: auto">
+                <!-- 菜单 -->
+                <el-aside>
+                    <div class="toggle-button" @click="isCollapse = !isCollapse">
+                        <el-icon :size="20">
+                            <Expand v-if="isCollapse" />
+                            <Fold v-if="!isCollapse" />
+                        </el-icon>
+                    </div>
+                    <el-menu router :default-active="activePath" class="el-menu-vertical-demo" :collapse="isCollapse">
+                        <el-menu-item index="/index" @click="saveActiveNav('/index')">
+                            <el-icon>
+                                <house />
+                            </el-icon>
+                            <span>首页</span>
+                        </el-menu-item>
+                        <el-sub-menu index="1">
+                            <template #title>
+                                <el-icon>
+                                    <Setting />
+                                </el-icon>
+                                <span>系统设置</span>
+                            </template>
+                            <el-menu-item index="2-1">权限管理</el-menu-item>
+                        </el-sub-menu>
+                        <el-menu-item index="/user/list" @click="saveActiveNav('/user/list')">
+                            <el-icon>
+                                <user />
+                            </el-icon>
+                            <span>资源管理</span>
+                        </el-menu-item>
+                      <el-menu-item index="/product/list" @click="saveActiveNav('/product/list')">
+                        <el-icon>
+                          <user />
+                        </el-icon>
+                        <span>产品管理</span>
+                      </el-menu-item>
+                      <el-menu-item index="/contents/list" @click="saveActiveNav('/contents/list')">
+                        <el-icon>
+                          <user />
+                        </el-icon>
+                        <span>招募新闻管理</span>
+                      </el-menu-item>
+                      <el-menu-item index="/serves/list" @click="saveActiveNav('/serves/list')">
+                        <el-icon>
+                          <user />
+                        </el-icon>
+                        <span>服务管理</span>
+                      </el-menu-item>
+                    </el-menu>
+                </el-aside>
+                <el-container>
+                    <el-main>
+                        <!-- 面包屑 -->
+                        <!-- <Breadcrumb /> -->
+                        <!-- 主要内容 -->
+                        <router-view></router-view>
+                    </el-main>
+                </el-container>
+            </el-container>
+        </el-container>
+    </div>
+</template>
+<script setup>
+import { onBeforeMount, ref } from 'vue';
+import avatar from "../assets/img/avator.jpg"
+import { useRouter } from 'vue-router'
+const router = useRouter();
+// 挂载 DOM 之前
+onBeforeMount(() => {
+    activePath.value = sessionStorage.getItem("activePath")
+        ? sessionStorage.getItem("activePath")
+        : "/index"
+})
+let isCollapse = ref(false);
+let activePath = ref("");
+// 保存链接的激活状态
+const saveActiveNav = (path) => {
+    sessionStorage.setItem("activePath", path);
+    activePath.value = path;
+}
+const logout = () => {
+    // 清除缓存
+    sessionStorage.clear();
+    router.push("/login");
+}
+</script>
+
+<style scoped>
+.home-container {
+    position: absolute;
+    height: 100%;
+    top: 0px;
+    left: 0px;
+    width: 100%;
+    background: #f2f3f5;
+}
+
+.el-header {
+    background: #2661ef;
+    padding: 0 10px;
+    overflow: hidden;
+}
+
+.system-name {
+    color: #fff;
+    font-size: 18px;
+}
+
+.el-aside {
+    background: white;
+    width: auto !important;
+}
+
+.el-menu-vertical-demo:not(.el-menu--collapse) {
+    width: 200px;
+    min-height: 400px;
+}
+
+.el-footer {
+    color: #cccccc;
+    text-align: center;
+    line-height: 60px;
+}
+
+.el-footer:hover {
+    color: #2661ef;
+}
+
+.toggle-button {
+    background-color: #d9e0e7;
+    font-size: 18px;
+    line-height: 24px;
+    color: #fff;
+    text-align: center;
+    letter-spacing: 0.2em;
+    cursor: pointer;
+    color: black;
+}
+
+.el-menu-vertical-demo:not(.el-menu--collapse) {
+    width: 200px;
+    min-height: 400px;
+}
+
+.el-menu-item.is-active {
+    color: #fff !important;
+    font-size: 15px;
+    font-weight: bold;
+    background-color: #2661ef !important;
+    border-radius: 2px;
+    height: 50px;
+    line-height: 50px;
+    box-sizing: border-box;
+    margin: 2px 5px 0px 2px;
+}
+</style>

+ 111 - 0
src/view/Login.vue

@@ -0,0 +1,111 @@
+<template>
+    <div>
+        <el-container>
+            <el-header>
+                <div style="width:400px">
+                    <p style="float: left;">
+                        <el-icon color="#409EFF" :size="50">
+                            <ElementPlus/>
+                        </el-icon>
+                    </p>
+                    <p style="float: left;font-size: 25px; font-weight: bold">
+                        欢迎来到宝智达冷链
+                    </p>
+                </div>
+
+            </el-header>
+            <el-main>
+                <el-card class="login_card">
+                    <el-form :model="form" :rules="rules" ref="ruleFormRef" label-width="80px">
+                        <el-form-item label="账号:" prop="username">
+                            <el-input v-model="form.username" placeholder="请输入账号"/>
+                        </el-form-item>
+                        <el-form-item label="密码:" prop="password">
+                            <el-input type="password" placeholder="请输入密码" v-model="form.password"/>
+                        </el-form-item>
+                        <el-form-item>
+                            <el-button type="primary" @click="onSubmit()">登录</el-button>
+                            <el-button type="primary" @click="resetForm()">重置</el-button>
+                        </el-form-item>
+                    </el-form>
+                </el-card>
+            </el-main>
+
+        </el-container>
+    </div>
+</template>
+
+<script setup>
+import userApi from "../api/user";
+import {reactive, ref, getCurrentInstance} from "vue";
+import {ElMessage} from "element-plus";
+import router from "../router/index";
+
+const {proxy} = getCurrentInstance();
+const form = reactive({
+    username: "",
+    password: "",
+});
+const ruleFormRef = ref();
+const rules = reactive({
+    username: [{required: true, message: "账号不能为空", trigger: "blur"}],
+    password: [{required: true, message: "密码不能为空", trigger: "blur"}],
+});
+const onSubmit = () => {
+    if (!ruleFormRef) return;
+    ruleFormRef.value.validate(async (valid) => {
+        if (valid) {
+            const res = await userApi.login(form);
+            console.log(res.data.Code);
+            if (res.data) {
+                if (res.data.Code===200) {
+                    // proxy.$commonJs.changeView('/home');
+                    localStorage.setItem("token", res.data.Data);
+                    router.push("/home");
+                } else {
+                    ElMessage.error(res.data.Msg);
+                }
+            } else {
+                ElMessage.error("服务器内部错误");
+            }
+        } else {
+            return false;
+        }
+    });
+};
+const resetForm = () => {
+    if (!ruleFormRef) return;
+    ruleFormRef.value.resetFields();
+};
+</script>
+
+<style scoped>
+.el-container {
+    height: 800px;
+}
+
+.el-header {
+    height: 10%;
+}
+
+.el-main {
+    height: 80%;
+    background-image: url("../assets/img/bg.jpg");
+    background-repeat: no-repeat;
+    background-size: 100% 120%;
+    background-position-y: bottom;
+}
+
+.login_card {
+    margin: 100px 200px;
+    width: 20%;
+    min-width: 300px;
+    height: 200px;
+    border-radius: 10px;
+}
+
+.el-footer {
+    height: 10%;
+    text-align: center;
+}
+</style>

+ 18 - 0
src/view/Welcome.vue

@@ -0,0 +1,18 @@
+<template>
+    <div class="main">
+
+    </div>
+</template>
+
+<style  scoped>
+.main {
+    text-align: center;
+    padding: 5px;
+    background: white;
+    height: 100%;
+    background-image: url("../assets/img/index.gif");
+    background-repeat: no-repeat;
+    background-size: 100% 100%;
+    background-position-y: bottom;
+}
+</style>

+ 75 - 0
src/view/contents/Detail.vue

@@ -0,0 +1,75 @@
+<template>
+  <div>
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <span>详情</span>
+          <el-button size="mini" style="float:right" @click="router.go(-1)">返回</el-button>
+          <el-button size="mini" style="float:right" type="primary" @click="updateContent">修改</el-button>
+        </div>
+      </template>
+      <el-form>
+        <el-form-item label="标题:">
+          <el-input v-model="contentsDetail.title" placeholder="请输入标题" />
+        </el-form-item>
+        <el-form-item label="简介:">
+          <el-input v-model="contentsDetail.synopsis" placeholder="请输入简介" />
+        </el-form-item>
+        <el-form-item label="详情:">
+          <editor :initial-value="contentsDetail.detail" @update:html="handleEditorChange"/>
+        </el-form-item>
+      </el-form>
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import {onBeforeMount, reactive, ref} from 'vue';
+import {useRoute, useRouter} from 'vue-router'
+import contents from "../../api/contents.js";
+import Editor from "../editor.vue";
+import {ElMessage} from "element-plus";
+
+const route = useRoute();
+const router = useRouter();
+const contentsDetail = reactive({
+  title: '',
+  detail: '',
+  synopsis: '',
+  types: '',
+})
+const parentHtmlContent = ref(''); // 父组件中的数据
+const handleEditorChange = (newHtml) => {
+  console.log(newHtml)
+  contentsDetail.detail = newHtml; // 当子组件编辑器内容变化时,更新父组件的数据
+};
+const updateContent = async () => {
+  const res = await contents.updateRecruit({
+    id: parseInt(route.query.id),
+    title: contentsDetail.title,
+    synopsis: contentsDetail.synopsis,
+    detail: contentsDetail.detail,
+    types: contentsDetail.types,
+  });
+  if (res.data.Code === 200) {
+    ElMessage.success("修改成功")
+    await getRecruitDetail()
+  } else {
+    ElMessage.error(res.data.Msg)
+  }
+}
+const getRecruitDetail = async () => {
+  const res = await contents.getRecruitDetail({id: route.query.id})
+  Object.assign(contentsDetail, res.data.Data);
+}
+onBeforeMount(async () => {
+  if (route.query.id) {
+    const res = await contents.getRecruitDetail({id: route.query.id})
+    Object.assign(contentsDetail, res.data.Data);
+  }
+})
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 74 - 0
src/view/contents/add.vue

@@ -0,0 +1,74 @@
+<template>
+  <div>
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <span>详情</span>
+          <el-button size="mini" style="float:right" type="primary" @click="addContent">提交</el-button>
+          <el-button size="mini" style="float:right" type="info" @click="router.go(-1)">返回</el-button>
+        </div>
+      </template>
+      <el-form>
+        <el-form-item label="标题:">
+          <el-input v-model="contentsDetail.title" placeholder="请输入标题"/>
+        </el-form-item>
+        <el-form-item>
+          <el-switch v-model="contentsDetail.types" active-value="1" inactive-value="0" active-text="招聘" inactive-text="公告"/>
+        </el-form-item>
+        <el-form-item label="简介:">
+          <el-input v-model="contentsDetail.synopsis" placeholder="请输入简介"/>
+        </el-form-item>
+        <el-form-item label="详情:">
+          {{ contentsDetail.synopsis }}
+          <editor v-model="contentsDetail.synopsis"></editor>
+        </el-form-item>
+
+      </el-form>
+    </el-card>
+
+  </div>
+</template>
+<script setup>
+import {onBeforeMount, reactive} from 'vue';
+import {useRoute, useRouter} from 'vue-router'
+import contents from "../../api/contents.js";
+import Editor from "../editor.vue";
+import {ElMessage} from "element-plus";
+
+const route = useRoute();
+const router = useRouter();
+const contentsDetail = reactive({
+  title: '',
+  detail: '',
+  synopsis: '',
+  types: '',
+})
+const addContent = async () => {
+  const res = await contents.addRecruit({
+    id: parseInt(route.query.id),
+    title: contentsDetail.title,
+    synopsis: contentsDetail.synopsis,
+    detail: contentsDetail.detail,
+    types: contentsDetail.types,
+  });
+  if (res.data.Code === 200) {
+    ElMessage.success("添加成功")
+    await getRecruitDetail()
+  } else {
+    ElMessage.error(res.data.Msg)
+  }
+}
+const getRecruitDetail = async () => {
+  const res = await contents.getRecruitDetail({id: route.query.id})
+  Object.assign(contentsDetail, res.data.Data);
+}
+onBeforeMount(async () => {
+  if (route.query.id) {
+    const res = await contents.getRecruitDetail({id: route.query.id})
+    Object.assign(contentsDetail, res.data.Data);
+  }
+})
+</script>
+
+
+<style lang="scss" scoped></style>

+ 121 - 0
src/view/contents/contents.vue

@@ -0,0 +1,121 @@
+<template>
+  <div>
+    <el-card>
+      <!-- 添加el-dialog组件 -->
+      <el-button type="primary"
+                 @click="() => router.push({ path: '/contents/add'})">添加
+      </el-button>
+      <el-table :data="tableData" border style="width: 100%;margin-top:20px">
+        <el-table-column label="序号" width="60">
+          <template #default="scope">
+            {{ scope.$index + 1 }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="title" label="名称" width="180">
+          <template #default="scope">
+            {{ scope.row.title }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="synopsis" label="简介" width="180">
+          <template #default="scope">
+            {{ scope.row.synopsis }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="type" label="类型" width="180">
+          <template #default="scope">
+            {{ typeMapping[scope.row.types] || '其他' }}
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="200">
+          <template #default="scope">
+            <el-button type="danger" size="small" @click="deleteProduct(scope.row.ID)">删除</el-button>
+            <!--            <el-button type="primary" size="small" @click="deleteResource(scope.row.ID)">修改</el-button>-->
+            <el-button size="small"
+                       @click="() => router.push({ path: '/contents/detail', query: { id: scope.row.ID } })">详情
+            </el-button>
+
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- 分页 -->
+      <el-pagination style="margin-top:20px" :current-page="searchForm.page" :page-size="searchForm.size"
+                     :total="total"
+                     @current-change="handleCurrentChange"/>
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import {onMounted, reactive, ref} from "vue";
+import {ElMessage, ElMessageBox} from 'element-plus';
+import {useRouter} from 'vue-router'
+import contents from "../../api/contents.js";
+const router = useRouter();
+// Dom 挂载之后
+onMounted(() => {
+  getRecruitAll();
+})
+// 资源数据
+const typeMapping = {
+  recruit: '招募',
+  about: '关于我们',
+}
+const showUpload = ref(false);
+const showUploadDialog = ref(false);
+let tableData = ref([]);
+let total = ref(0);
+const toggleUpload = () => {
+  showUpload.value = !showUpload.value;
+};
+// 搜索条件
+const searchForm = reactive({
+  page: 1,
+  size: 5,
+  desc: ''
+})
+// 获取资源列表
+const getRecruitAll = async () => {
+  const res = await contents.getAllrecruit(searchForm);
+  tableData.value = res.data.Data.Data;
+  total.value = res.data.Data.Size;
+}
+
+function imageUrlWithPrefix(url) {
+  const prefix = 'http://localhost:8080'; // 这里替换为你的图片服务器基础路径
+  return prefix + url;
+}
+const handleCurrentChange = (current) => {
+  searchForm.page = current;
+  getRecruitAll();
+}
+const searchUser = () => {
+  searchForm.current = 1;
+  getRecruitAll();
+}
+// 删除资源信息
+const deleteProduct = (id) => {
+  ElMessageBox.confirm(
+      '确定要删除该资源信息吗?',
+      {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      }
+  ).then(async () => {
+    const res = await contents.deleteRecruit({id: id});
+    if (res.data.Code === 200) {
+      ElMessage.success("删除成功")
+      await getRecruitAll();
+    } else {
+      ElMessage.error(res.data.Msg)
+    }
+  }).catch(() => {
+    ElMessage({
+      type: 'info',
+      message: '取消删除',
+    })
+  })
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 100 - 0
src/view/editor.vue

@@ -0,0 +1,100 @@
+<template>
+  <div style="border: 1px solid #ccc; width: 100%; margin: 20px auto">
+    <Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" mode="default" />
+    <Editor style="height: 500px; overflow-y: hidden" v-model="data.localValueHtml"/>
+
+  </div>
+<!--  <el-button style="margin: 0 auto" @click="getEditorHTML">获取富文本HTML内容</el-button>-->
+</template>
+
+<script setup>
+// 富文本编辑器文档链接: https://www.wangeditor.com/v5/getting-started.html
+// 引入富文本编辑器CSS
+import '@wangeditor/editor/dist/css/style.css';
+import {onBeforeUnmount, ref, reactive, shallowRef, defineProps, onMounted, watch} from 'vue';
+// 导入富文本编辑器的组件
+import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
+
+// 定义接收外部传入内容的 prop
+const props = defineProps({
+  initialValue: {
+    type: String,
+    default: '', // 默认为空字符串
+  },
+  detailData: {
+    type: String,
+    default: '', // 默认为空字符串
+  },
+});
+
+// 编辑器实例,必须用 shallowRef
+const editorRef = shallowRef();
+//添加自定义事件
+const emit = defineEmits(['update:html']);
+
+// 内容 HTML
+const  data = reactive({
+  localValueHtml:'12344'
+})
+const toolbarConfig = {};
+const editorConfig = ref({ placeholder: '请输入内容...', MENU_CONF: {} });
+
+watch(()=>props.detailData,(newData)=>{
+  data.localValueHtml = newData
+},{deep:true,immediatet:true})
+
+// 自定义图片上传
+editorConfig.value.MENU_CONF['uploadImage'] = {
+  async customUpload(file, insertFn) {
+    console.log('上传图片', file);
+    // 将上传的file图片转换为base64
+    const base64 = URL.createObjectURL(file);
+
+    // 这里的file为上传的图片对象,insertFn传入
+    insertFn(base64, 'img');
+  },
+};
+
+// 自定义视频上传
+editorConfig.value.MENU_CONF['uploadVideo'] = {
+  async customUpload(file, insertFn) {
+    console.log('上传视频', file);
+  },
+};
+
+// 富文本编辑器生成后触发
+// const handleCreated = editor => {
+//   editorRef.value = editor; // 记录 editor 实例,重要!
+//   console.log(editorConfig.value.MENU_CONF, 'editorConfig.value');
+// };
+
+// 监听富文本编辑器粘贴行为
+const customPaste = (editor, event, callback) => {
+  // 获取粘贴的纯文本
+  const text = event.clipboardData.getData('text/plain');
+  if (text) {
+    editor.insertText(text);
+    event.preventDefault();
+    callback(false);
+  }
+};
+
+// 获取富文本html内容
+const getEditorHTML = () => {
+  console.log(editorRef.value.getHtml());
+};
+onMounted(async () => {
+  if (!props.initialValue) {
+    await new Promise((resolve) => setTimeout(resolve, 200)); // 等待200毫秒,模拟异步数据加载
+  }
+  if (props.initialValue) {
+    editorRef.value.setHtml(props.initialValue);
+  }
+});
+// 组件销毁时,也及时销毁编辑器
+onBeforeUnmount(() => {
+  const editor = editorRef.value;
+  if (editor == null) return;
+  editor.destroy();
+});
+</script>

+ 100 - 0
src/view/product/Detail.vue

@@ -0,0 +1,100 @@
+<template>
+  <div>
+
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <span>产品详情</span>
+          <el-button size="mini" style="float:right" @click="router.go(-1)">返回</el-button>
+          <el-button size="mini" style="float:right" type="primary" @click="updateProduct">修改</el-button>
+        </div>
+      </template>
+      <el-form>
+        <el-form-item label="标题:">
+          <el-input v-model="productDetail.title"></el-input>
+        </el-form-item>
+        <el-form-item label="图片:">
+          <img :src="productDetail.url" style="width: 100px;height: 100px;">
+        </el-form-item>
+        <el-form-item label="简介:">
+          <el-input v-model="productDetail.synopsis"></el-input>
+        </el-form-item>
+        <el-form-item label="详情:">
+          <editor v-model="productDetail.detail"></editor>
+        </el-form-item>
+        <el-form-item label="产品介绍:">
+          <editor v-if="productDetail.product_introduction"
+                  :initial-value="productDetail.product_introduction"></editor>
+        </el-form-item>
+        <el-form-item label="技术参数:">
+          <editor v-if="productDetail.technical_parameters"
+                  :initial-value="productDetail.technical_parameters"></editor>
+        </el-form-item>
+        <el-form-item label="使用说明:">
+          <editor v-if="productDetail.instructions" :initial-value="productDetail.instructions"></editor>
+        </el-form-item>
+        <el-form-item label="支持软件:">
+          <editor v-if="productDetail.supporting_software" :initial-value="productDetail.supporting_software"></editor>
+        </el-form-item>
+        <el-form-item label="可选配件:">
+          <editor v-if="productDetail.optional_accessories"
+                  :initial-value="productDetail.optional_accessories"></editor>
+        </el-form-item>
+      </el-form>
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import {onBeforeMount, reactive} from 'vue';
+import {useRoute, useRouter} from 'vue-router'
+import product from "../../api/product.js";
+import Editor from "../editor.vue";
+import {ElMessage} from "element-plus";
+import EditorWithBinding from "../EditorWithBinding.vue";
+
+const route = useRoute();
+const router = useRouter();
+const productDetail = reactive({
+  id: '',
+  title: '',
+  synopsis: '',
+  detail: '',
+  url: '',
+  product_introduction: '',
+  technical_parameters: '',
+  instructions: '',
+  supporting_software: '',
+  optional_accessories: '',
+})
+const updateProduct = async () => {
+  const res = await product.updateRecruit({
+    id: parseInt(route.query.id),
+    title: productDetail.title,
+    synopsis: productDetail.synopsis,
+    detail: productDetail.detail,
+    url: productDetail.url,
+    product_introduction: productDetail.product_introduction,
+    technical_parameters: productDetail.technical_parameters,
+    instructions: productDetail.instructions,
+    supporting_software: productDetail.supporting_software,
+    optional_accessories: productDetail.optional_accessories,
+  });
+  if (res.data.Code === 200) {
+    ElMessage.success("修改成功")
+  } else {
+    ElMessage.error(res.data.Msg)
+  }
+}
+onBeforeMount(async () => {
+  if (route.query.id) {
+    const res = await product.getProductDetail({id: route.query.id})
+    console.log(res.data)
+    Object.assign(productDetail, res.data.Data);
+  }
+})
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 149 - 0
src/view/product/add.vue

@@ -0,0 +1,149 @@
+<template>
+  <div>
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <span>添加产品</span>
+          <el-button size="mini" style="float:right" @click="router.go(-1)">返回</el-button>
+          <el-button size="mini" style="float:right" type="primary" @click="addProduct">添加</el-button>
+        </div>
+      </template>
+      <el-form>
+        <el-form-item label="标题:">
+          <el-input v-model="productDetail.title"></el-input>
+        </el-form-item>
+        <el-form-item label="图片:">
+          <el-upload
+              :http-request="httpRequest"
+              multiple
+              :show-file-list="true"
+              list-type="picture-card"
+          >
+            <el-icon>
+              <Plus/>
+            </el-icon>
+          </el-upload>
+        </el-form-item>
+        <el-form-item label="类型:">
+          <el-select v-model="productDetail.type" @change="handleTypeChange" placeholder="请选择添加类型">
+            <el-option label="服务" value="serve"/>
+            <el-option label="产品" value="product"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="产品类型:">
+          <el-select v-model="productDetail.ptype" :disabled="productDetail.type === 'serve'"  placeholder="请选择软件或者硬件" style="width: 20vw">
+            <el-option label="硬件" value="hardware"/>
+            <el-option label="软件" value="software"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="是否首页展示:">
+            <el-select v-model="productDetail.isIndex"  placeholder="请选择是否首页显示" style="width: 20vw">
+              <el-option label="是" value="true"/>
+              <el-option label="否" value="false"/>
+            </el-select>
+        </el-form-item>
+        <el-form-item label="简介:">
+          <el-input v-model="productDetail.synopsis"></el-input>
+        </el-form-item>
+        <el-form-item label="详情:">
+          <EditorWithBinding v-model="productDetail.content"></EditorWithBinding>
+        </el-form-item>
+        <el-form-item label="产品介绍:">
+          <EditorWithBinding v-model="productDetail.product_introduction"></EditorWithBinding>
+        </el-form-item>
+        <el-form-item label="技术参数:">
+          <EditorWithBinding v-model="productDetail.technical_parameters"></EditorWithBinding>
+        </el-form-item>
+        <el-form-item label="使用说明:">
+          <EditorWithBinding v-model="productDetail.instructions"></EditorWithBinding>
+        </el-form-item>
+        <el-form-item label="支持软件:">
+          <EditorWithBinding v-model="productDetail.supporting_software"></EditorWithBinding>
+        </el-form-item>
+        <el-form-item label="可选配件:">
+          <EditorWithBinding v-model="productDetail.optional_accessories"></EditorWithBinding>
+        </el-form-item>
+      </el-form>
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import {onBeforeMount, reactive, ref} from 'vue';
+import {useRoute, useRouter} from 'vue-router'
+import product from "../../api/product.js";
+import {ElMessage} from "element-plus";
+import EditorWithBinding from "../EditorWithBinding.vue";
+import {Plus} from "@element-plus/icons-vue";
+import resource from "../../api/resource.js";
+
+const route = useRoute();
+const router = useRouter();
+const productDetail = reactive({
+  title: '',
+  synopsis: '',
+  detail: '',
+  ptype: '',
+  type: '',
+  url: '',
+  isIndex: '',
+  product_introduction: '',
+  technical_parameters: '',
+  instructions: '',
+  supporting_software: '',
+  optional_accessories: '',
+})
+const handleTypeChange = (value) => {
+  if (value === 'serve') {
+    productDetail.ptype = '';
+  }
+}
+const fileList = ref([])
+
+function httpRequest(option) {
+//将图片存到数组中
+  fileList.value.push(option)
+}
+
+const addProduct = async () => {
+  let dataForm = new FormData();
+  dataForm.append('types', "serve")
+  //将图片的二进制通过表单的形式发送到后台
+  fileList.value.forEach((it, index) => {
+    dataForm.append('file', it.file)
+  })
+  const fileRes = await resource.uploadResource(dataForm)
+  productDetail.url = fileRes.data.Data
+  const res = await product.addProduct({
+    title: productDetail.title,
+    synopsis: productDetail.synopsis,
+    detail: productDetail.detail,
+    url: productDetail.url,
+    ptype: productDetail.ptype,
+    type: productDetail.type,
+    isIndex: productDetail.isIndex,
+    product_introduction: productDetail.product_introduction,
+    technical_parameters: productDetail.technical_parameters,
+    instructions: productDetail.instructions,
+    supporting_software: productDetail.supporting_software,
+    optional_accessories: productDetail.optional_accessories,
+  });
+  if (res.data.Code === 200) {
+    ElMessage.success("添加成功")
+    productDetail.clear()
+  } else {
+    ElMessage.error(res.data.Msg)
+  }
+}
+onBeforeMount(async () => {
+  if (route.query.id) {
+    const res = await product.getProductDetail({id: route.query.id})
+    console.log(res.data)
+    Object.assign(productDetail, res.data.Data);
+  }
+})
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 186 - 0
src/view/product/product.vue

@@ -0,0 +1,186 @@
+<template>
+  <div>
+    <el-card>
+      <el-button type="primary"
+                 @click="() => router.push({ path: '/product/add'})">添加产品服务
+      </el-button>
+      <!-- 添加el-dialog组件 -->
+      <el-table :data="tableData" border style="width: 100%;margin-top:20px">
+        <el-table-column label="序号" width="60">
+          <template #default="scope">
+            {{ scope.$index + 1 }}
+          </template>
+        </el-table-column>
+        <el-table-column label="图片" width="120">
+          <template #default="scope">
+            <img :src="imageUrlWithPrefix(scope.row.url)" alt="图片" style="max-width: 100%; height: auto;">
+          </template>
+        </el-table-column>
+        <el-table-column prop="title" label="名称" width="180">
+          <template #default="scope">
+            {{ scope.row.title }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="title" label="是否首页显示" width="180">
+          <template #default="scope">
+            <el-switch
+                v-model="scope.row.isIndex"
+                size="large"
+                active-text="显示"
+                inactive-text="不显示"
+                @change="handleSwitchChange(scope.row)"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column prop="ptype" label="产品类型" width="180">
+          <template #default="scope">
+            {{ ptypeMapping[scope.row.ptype] || '服务' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="type" label="类型" width="180">
+          <template #default="scope">
+            {{ typeMapping[scope.row.type] || '其他' }}
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="200">
+          <template #default="scope">
+            <el-button type="danger" size="small" @click="deleteProduct(scope.row.ID)">删除</el-button>
+            <!--            <el-button type="primary" size="small" @click="deleteResource(scope.row.ID)">修改</el-button>-->
+                        <el-button size="small"
+                                   @click="() => router.push({ path: '/product/detail', query: { id: scope.row.ID } })">详情
+                        </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- 分页 -->
+      <el-pagination style="margin-top:20px" :current-page="searchForm.page" :page-size="searchForm.size"
+                     :total="total"
+                     @current-change="handleCurrentChange"/>
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import {onMounted, reactive, ref} from "vue";
+import {ElMessage, ElMessageBox} from 'element-plus';
+import {useRouter} from 'vue-router'
+import resource from "../../api/resource";
+import product from "../../api/product.js";
+
+const router = useRouter();
+// Dom 挂载之后
+onMounted(() => {
+  getProductAll();
+})
+// 资源数据
+const ptypeMapping = {
+  hardware: '硬件',
+  software: '软件',
+  example: '合作案列',
+  4: ''
+}
+const typeMapping = {
+  serve: '服务',
+  product: '产品',
+  example: '合作案列',
+  4: ''
+}
+const productDetail = reactive({
+  ID: '',
+  type: '',
+  isIndex:'',
+  ptype: '',
+  title: '',
+  parentId:'',
+  synopsis: '',
+  detail: '',
+  url: '',
+  product_introduction: '',
+  technical_parameters: '',
+  instructions: '',
+  supporting_software: '',
+  optional_accessories: '',
+  is_active: '',
+})
+const showUpload = ref(false);
+const showUploadDialog = ref(false);
+let tableData = ref([]);
+let total = ref(0);
+const toggleUpload = () => {
+  showUpload.value = !showUpload.value;
+};
+// 搜索条件
+const searchForm = reactive({
+  page: 1,
+  size: 5,
+  desc: ''
+})
+// 获取资源列表
+const getProductAll = async () => {
+  const res = await product.getProductList(searchForm);
+  tableData.value = res.data.Data.Data;
+  total.value = res.data.Data.Size;
+}
+const handleSwitchChange = async (row) => {
+  try {
+    // 这里根据实际情况调用你的修改方法,例如 updateProduct
+    await updateProduct(row.ID, row.isIndex);
+    await getProductAll();
+  } catch (error) {
+    ElMessage.error('更新状态时出错');
+  }
+}
+const updateProduct = async (id,isIndex) => {
+  const res = await product.updateProduct({id: id, isIndex: isIndex});
+  if (res.data.Code === 200) {
+    ElMessage.success("修改成功")
+    await getProductAll();
+  } else {
+    ElMessage.error(res.data.Msg)
+  }
+}
+
+function imageUrlWithPrefix(url) {
+  const prefix = 'http://localhost:8080'; // 这里替换为你的图片服务器基础路径
+  return prefix + url;
+}
+
+const handleSizeChange = (size) => {
+  searchForm.size = size;
+  getProductList();
+}
+const handleCurrentChange = (current) => {
+  searchForm.page = current;
+  getProductAll();
+}
+const searchUser = () => {
+  searchForm.current = 1;
+  getProductAll();
+}
+// 删除资源信息
+const deleteProduct = (id) => {
+  ElMessageBox.confirm(
+      '确定要删除该资源信息吗?',
+      {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      }
+  ).then(async () => {
+    const res = await product.deleteProduct({id: id});
+    if (res.data.code === 200) {
+      ElMessage.success("删除成功")
+      await getProductAll();
+    } else {
+      ElMessage.error(res.data.Msg)
+    }
+  }).catch(() => {
+    ElMessage({
+      type: 'info',
+      message: '取消删除',
+    })
+  })
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 41 - 0
src/view/resource/Detail.vue

@@ -0,0 +1,41 @@
+<template>
+    <div>
+        <el-card class="box-card">
+            <template #header>
+                <div class="card-header">
+                    <span>用户详情</span>
+                    <el-button size="mini" style="float:right" @click="router.go(-1)">返回</el-button>
+                </div>
+            </template>
+            <el-form>
+                <el-form-item label="姓名:">
+                    {{ userDetail.name }}
+                </el-form-item>
+                <el-form-item label="年龄:">
+                    {{ userDetail.age }}
+                </el-form-item>
+            </el-form>
+        </el-card>
+    </div>
+</template>
+
+<script setup>
+import { onBeforeMount, reactive, ref } from 'vue';
+import { useRouter, useRoute } from 'vue-router'
+import userApi from "../../api/user";
+const route = useRoute();
+const router = useRouter();
+const userDetail = reactive({
+    id: ''
+})
+onBeforeMount(async () => {
+    if (route.query.id) {
+        const res = await userApi.getUserDetail({ id: route.query.id })
+        Object.assign(userDetail, res.data.data);
+    }
+})
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 130 - 0
src/view/resource/Index.vue

@@ -0,0 +1,130 @@
+<template>
+  <div>
+    <el-card>
+      <!-- 添加el-button触发弹窗 -->
+      <!-- 添加一个按钮来控制显示Upload组件 -->
+      <el-button type="primary" @click="toggleUpload">上传图片</el-button>
+
+      <!-- 使用v-if根据showUpload的值来决定是否渲染Upload组件 -->
+      <upload v-if="showUpload"></upload>
+      <!-- 添加el-dialog组件 -->
+      <el-table :data="tableData" border style="width: 100%;margin-top:20px">
+        <el-table-column label="序号" width="60">
+          <template #default="scope">
+            {{ scope.$index + 1 }}
+          </template>
+        </el-table-column>
+        <el-table-column label="图片" width="120">
+          <template #default="scope">
+            <img :src="imageUrlWithPrefix(scope.row.url)" alt="图片" style="max-width: 100%; height: auto;">
+          </template>
+        </el-table-column>
+        <el-table-column prop="type" label="类型" width="180">
+          <template #default="scope">
+            {{ typeMapping[scope.row.type] || '未知类型' }}
+          </template>
+        </el-table-column>
+
+        <el-table-column label="操作" width="100">
+          <template #default="scope">
+            <el-button type="danger" size="small" @click="deleteResource(scope.row.ID)">删除</el-button>
+<!--            <el-button type="primary" size="small" @click="deleteResource(scope.row.ID)">修改</el-button>-->
+<!--            <el-button size="small"-->
+<!--                       @click="() => router.push({ path: '/user/detail', query: { id: scope.row.id } })">详情-->
+<!--            </el-button>-->
+
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- 分页 -->
+      <el-pagination style="margin-top:20px" :current-page="searchForm.page" :page-size="searchForm.size"
+                      :total="total"
+                     @current-change="handleCurrentChange"/>
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import {onMounted, reactive, ref} from "vue";
+import {ElMessage, ElMessageBox} from 'element-plus';
+import {useRouter} from 'vue-router'
+import resource from "../../api/resource";
+import Upload from "./upload.vue";
+
+const router = useRouter();
+// Dom 挂载之后
+onMounted(() => {
+  getResourceList();
+})
+// 资源数据
+const typeMapping = {
+  banner: '轮播图',
+  honor: '资质荣耀',
+  example: '合作案列',
+  4: '其他'
+}
+const showUpload = ref(false);
+const showUploadDialog = ref(false);
+let tableData = ref([]);
+let total = ref(0);
+const toggleUpload = () => {
+  showUpload.value = !showUpload.value;
+};
+// 搜索条件
+const searchForm = reactive({
+  page: 1,
+  size: 5,
+  desc: ''
+})
+// 获取资源列表
+const getResourceList = async () => {
+  const res = await resource.getResourceList(searchForm);
+  console.log(res.data.Data)
+  tableData.value = res.data.Data.Data;
+  total.value = res.data.Data.Size;
+}
+
+function imageUrlWithPrefix(url) {
+  const prefix = 'http://localhost:8080'; // 这里替换为你的图片服务器基础路径
+  return prefix + url;
+}
+
+const handleSizeChange = (size) => {
+  searchForm.size = size;
+  getResourceList();
+}
+const handleCurrentChange = (current) => {
+  searchForm.page = current;
+  getResourceList();
+}
+const searchUser = () => {
+  searchForm.page = 1;
+  getResourceList();
+}
+// 删除资源信息
+const deleteResource = (id) => {
+  ElMessageBox.confirm(
+      '确定要删除该资源信息吗?',
+      {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      }
+  ).then(async () => {
+    const res = await resource.deleteResource({id: id});
+    if (res.data.Code === 200) {
+      ElMessage.success("删除成功")
+      getResourceList();
+    } else {
+      ElMessage.error(res.data.Msg)
+    }
+  }).catch(() => {
+    ElMessage({
+      type: 'info',
+      message: '取消删除',
+    })
+  })
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 69 - 0
src/view/resource/upload.vue

@@ -0,0 +1,69 @@
+<template>
+  <div v-if="isUploading">
+    <h3>图片上传</h3>
+    <el-form :model="formData">
+      <el-form-item label="图片类型:" label-width="100">
+        <el-select v-model="formData.types" placeholder="请选择图片类型" style="width: 20vw">
+          <el-option label="轮播图" value="banner"/>
+          <el-option label="荣耀资质" value="honor"/>
+          <el-option label="合作案例" value="example"/>
+          <el-option label="服务" value="serve"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="图片" label-width="100">
+        <el-upload
+            :http-request="httpRequest"
+            multiple
+            :show-file-list="true"
+            list-type="picture-card"
+        >
+          <el-icon>
+            <Plus/>
+          </el-icon>
+        </el-upload>
+      </el-form-item>
+      <div>
+        <el-button>取消</el-button>
+        <el-button type="primary" @click="onBtn">添加</el-button>
+      </div>
+    </el-form>
+  </div>
+</template>
+
+<script setup>
+import {reactive, ref} from "vue";
+import {Plus} from '@element-plus/icons-vue'
+import resource from "../../api/resource.js";
+import {ElMessage} from "element-plus";
+
+const formData = reactive({
+  types: '',
+});
+
+//定义一个响应式数组用来接收图片
+const fileList = ref([])
+
+//自定义函数用来覆盖原有的XHR行为(默认提交行为)
+function httpRequest(option) {
+//将图片存到数组中
+  fileList.value.push(option)
+}
+const isUploading = ref(true);
+async function onBtn() {
+  let dataForm = new FormData();
+  dataForm.append('types', formData.types)
+
+//将图片的二进制通过表单的形式发送到后台
+  fileList.value.forEach((it, index) => {
+    dataForm.append('file', it.file)
+  })
+  const res = await resource.uploadResource(dataForm)
+  if (res.data.Code === 200) {
+    ElMessage.success("上传成功")
+    dataForm.set('file', '')
+  } else {
+    ElMessage.error(res.data.Msg)
+  }
+//设置请求参数的规则
+}
+</script>

+ 109 - 0
src/view/serve/Detail.vue

@@ -0,0 +1,109 @@
+<template>
+  <div>
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <span>详情</span>
+          <el-button size="mini" style="float:right" @click="router.go(-1)">返回</el-button>
+          <el-button size="mini" style="float:right" type="primary" @click="updateServe">修改</el-button>
+        </div>
+      </template>
+      <el-form>
+        <el-form-item label="标题:">
+          <el-input v-model="serveDetail.title" placeholder="请输入标题"/>
+        </el-form-item>
+        <el-form-item label="简介:">
+          <el-input v-model="serveDetail.synopsis" placeholder="请输入简介"/>
+        </el-form-item>
+        <el-form-item label="图片:">
+          <el-image
+              v-model="serveDetail.image"
+              style="width: 100px; height: 100px; margin-right: 10px"
+              fit="cover"></el-image>
+          <el-upload
+              :http-request="httpRequest"
+              multiple
+              :show-file-list="true"
+              list-type="picture-card"
+          >
+            <el-icon>
+              <Plus/>
+            </el-icon>
+          </el-upload>
+        </el-form-item>
+        <el-form-item label="详情:">
+          <EditorWithBinding v-model="serveDetail.detail"/>
+        </el-form-item>
+      </el-form>
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import {nextTick, onBeforeMount, reactive, ref} from 'vue';
+import {useRoute, useRouter} from 'vue-router'
+import serve from "../../api/serve.js";
+import {ElMessage} from "element-plus";
+import EditorWithBinding from "../EditorWithBinding.vue";
+import {Plus} from "@element-plus/icons-vue";
+import resource from "../../api/resource.js";
+
+const fileList = ref([])
+
+const route = useRoute();
+const router = useRouter();
+const serveDetail = reactive({
+  title: '',
+  detail: '',
+  synopsis: '',
+  types: '',
+  image: '',
+  product_id: ''
+})
+
+function httpRequest(option) {
+//将图片存到数组中
+  fileList.value.push(option)
+}
+
+const updateServe = async () => {
+  let dataForm = new FormData();
+  dataForm.append('types', "serve")
+  //将图片的二进制通过表单的形式发送到后台
+  fileList.value.forEach((it, index) => {
+    dataForm.append('file', it.file)
+  })
+  const fileRes = await resource.uploadResource(dataForm)
+  serveDetail.image = fileRes.data.Data
+  const res = await serve.updateService({
+    id: parseInt(route.query.id),
+    title: serveDetail.title,
+    synopsis: serveDetail.synopsis,
+    detail: serveDetail.detail,
+    types: serveDetail.types,
+    product_id: serveDetail.product_id,
+    image: serveDetail.image,
+  })
+  if (res.data.Code === 200) {
+    ElMessage.success("修改成功")
+    await getServiceDetail()
+  } else {
+    ElMessage.error(res.data.Msg)
+  }
+}
+const getServiceDetail = async () => {
+  const res = await serve.getServiceDetail({id: route.query.id})
+  Object.assign(serveDetail, res.data.Data);
+}
+onBeforeMount(async () => {
+  if (route.query.id) {
+    const res = await serve.getServiceDetail({id: route.query.id})
+    Object.assign(serveDetail, res.data.Data);
+  }
+})
+
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 125 - 0
src/view/serve/add.vue

@@ -0,0 +1,125 @@
+<template>
+  <div>
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <span>详情</span>
+          <el-button size="mini" style="float:right" type="primary" @click="addContent">提交</el-button>
+          <el-button size="mini" style="float:right" type="info" @click="router.go(-1)">返回</el-button>
+        </div>
+      </template>
+      <el-form>
+        <el-form-item label="标题:">
+          <el-input v-model="serveDetail.title" placeholder="请输入标题"/>
+        </el-form-item>
+        <el-form-item label="图片:">
+          <el-upload
+              :http-request="httpRequest"
+              multiple
+              :show-file-list="true"
+              list-type="picture-card"
+          >
+            <el-icon>
+              <Plus/>
+            </el-icon>
+          </el-upload>
+        </el-form-item>
+        <el-form-item label="分类:">
+          <el-select
+              @click="getServeType"
+              v-model="serveDetail.product_id"
+              clearable
+              placeholder="选择分类信息"
+              style="width: 240px"
+          >
+            <el-option
+                v-for="item in ServeType.value"
+                :key="item.ID"
+                :label="item.title"
+                :value="item.ID"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="简介:">
+          <el-input v-model="serveDetail.synopsis" placeholder="请输入简介"/>
+        </el-form-item>
+        <el-form-item label="详情:">
+          <editor v-model="serveDetail.synopsis"></editor>
+        </el-form-item>
+
+      </el-form>
+    </el-card>
+
+  </div>
+</template>
+<script setup>
+import {onMounted, reactive, ref} from 'vue';
+import {useRoute, useRouter} from 'vue-router'
+import serve from "../../api/serve.js";
+import Editor from "../editor.vue";
+import {ElMessage} from "element-plus";
+import {Plus} from "@element-plus/icons-vue";
+import resource from "../../api/resource.js";
+
+const value = ref('')
+const route = useRoute();
+const router = useRouter();
+const serveDetail = reactive({
+  title: '',
+  detail: '',
+  synopsis: '',
+  types: '',
+  image: '',
+  product_id: ''
+})
+const ServeType = reactive([{}])
+const fileList = ref([])
+const formData = reactive({
+  types: '',
+});
+function httpRequest(option) {
+//将图片存到数组中
+  fileList.value.push(option)
+}
+
+const addContent = async () => {
+  let dataForm = new FormData();
+  dataForm.append('types', "serve")
+  //将图片的二进制通过表单的形式发送到后台
+  fileList.value.forEach((it, index) => {
+    dataForm.append('file', it.file)
+  })
+  const fileRes = await resource.uploadResource(dataForm)
+  serveDetail.image=fileRes.data.Data
+  const res = await serve.addService({
+    id: parseInt(route.query.id),
+    title: serveDetail.title,
+    synopsis: serveDetail.synopsis,
+    detail: serveDetail.detail,
+    types: serveDetail.types,
+    image: serveDetail.image,
+    product_id: parseInt(serveDetail.product_id)
+  });
+  if (res.data.Code === 200) {
+    ElMessage.success("添加成功")
+    serveDetail.title = '';
+    serveDetail.synopsis = '';
+    serveDetail.detail = '';
+    serveDetail.types = '';
+    serveDetail.image = '';
+    serveDetail.product_id = '';
+    fileList.value=[];
+  } else {
+    ElMessage.error(res.data.Msg)
+  }
+}
+const getServeType = async () => {
+  const res = await serve.GetServiceType();
+  ServeType.value = res.data.Data;
+  console.log(ServeType.value)
+}
+onMounted(() => {
+  getServeType();
+})
+</script>
+<style lang="scss" scoped></style>

+ 139 - 0
src/view/serve/serves.vue

@@ -0,0 +1,139 @@
+<template>
+  <div>
+    <el-card>
+      <!-- 添加el-dialog组件 -->
+      <el-button type="primary"
+                 @click="() => router.push({ path: '/serves/add'})">添加
+      </el-button>
+      <el-table :data="tableData" border style="width: 100%;margin-top:20px">
+        <el-table-column label="序号" width="60">
+          <template #default="scope">
+            {{ scope.$index + 1 }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="title" label="名称" width="180">
+          <template #default="scope">
+            {{ scope.row.title }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="synopsis" label="简介" width="180">
+          <template #default="scope">
+            {{ scope.row.synopsis }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="type" label="归属" width="300">
+          <el-select
+              v-model="value"
+              placeholder="Select"
+              size="large"
+              style="width: 240px"
+          >
+            <el-option
+                v-for="item in ServeType.value"
+                :key="item.id"
+                :label="item.title"
+                :value="item.title"
+            />
+          </el-select>
+        </el-table-column>
+        <el-table-column label="操作" width="200">
+          <template #default="scope">
+            <el-button type="danger" size="small" @click="deleteServe(scope.row.ID)">删除</el-button>
+            <!--            <el-button type="primary" size="small" @click="deleteResource(scope.row.ID)">修改</el-button>-->
+            <el-button size="small"
+                       @click="() => router.push({ path: '/serves/detail', query: { id: scope.row.ID } })">详情
+            </el-button>
+
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- 分页 -->
+      <el-pagination style="margin-top:20px" :current-page="searchForm.page" :page-size="searchForm.size"
+                     :total="total"
+                     @current-change="handleCurrentChange"/>
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import {onMounted, reactive, ref} from "vue";
+import {ElMessage, ElMessageBox} from 'element-plus';
+import {useRouter} from 'vue-router'
+import serve from "../../api/serve.js";
+const router = useRouter();
+// Dom 挂载之后
+onMounted(() => {
+  getServeAll();
+  getServeType();
+})
+// 资源数据
+const typeMapping = {
+  recruit: '招募',
+  about: '关于我们',
+}
+const showUpload = ref(false);
+const value = ref('');
+const showUploadDialog = ref(false);
+let tableData = ref([]);
+let total = ref(0);
+const toggleUpload = () => {
+  showUpload.value = !showUpload.value;
+};
+// 搜索条件
+const searchForm = reactive({
+  page: 1,
+  size: 5,
+  desc: ''
+})
+const ServeType = reactive([{}])
+// 获取资源列表
+const getServeAll = async () => {
+  const res = await serve.getAllService(searchForm);
+  tableData.value = res.data.Data.Data;
+  total.value = res.data.Data.Size;
+}
+
+const handleSizeChange = (size) => {
+  searchForm.size = size;
+  getServeAll();
+}
+const handleCurrentChange = (current) => {
+  searchForm.page = current;
+  getServeAll();
+}
+const searchUser = () => {
+  searchForm.current = 1;
+  getServeAll();
+}
+const getServeType = async () => {
+  const res = await serve.GetServiceType();
+  ServeType.value = res.data.Data;
+  console.log(ServeType.value)
+}
+// 删除资源信息
+const deleteServe = (id) => {
+  ElMessageBox.confirm(
+      '确定要删除该资源信息吗?',
+      {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      }
+  ).then(async () => {
+    const res = await serve.deleteService({id: id});
+    if (res.data.Code === 200) {
+      ElMessage.success("删除成功")
+      await getServeAll();
+    } else {
+      ElMessage.error(res.data.Msg)
+    }
+  }).catch(() => {
+    ElMessage({
+      type: 'info',
+      message: '取消删除',
+    })
+  })
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 18 - 0
vite.config.js

@@ -0,0 +1,18 @@
+import {defineConfig} from 'vite'
+import vue from '@vitejs/plugin-vue'
+
+export default defineConfig({
+    plugins: [vue()],
+    server: {
+        open: false,
+        port: 3000,
+        proxy: {
+            '/api': {
+                target: 'http://localhost:8080', // 
+                changeOrigin: true,
+                rewrite: (path) => path.replace(/^\/api/, '')
+            },
+        },
+    },
+
+})

+ 1061 - 0
yarn.lock

@@ -0,0 +1,1061 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@babel/parser@^7.16.4":
+  version "7.20.5"
+  resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.20.5.tgz"
+  integrity sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==
+
+"@babel/runtime@^7.12.0":
+  version "7.24.5"
+  resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.24.5.tgz"
+  integrity sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==
+  dependencies:
+    regenerator-runtime "^0.14.0"
+
+"@ctrl/tinycolor@^3.4.1":
+  version "3.4.1"
+  resolved "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz"
+  integrity sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==
+
+"@element-plus/icons-vue@^2.0.10", "@element-plus/icons-vue@^2.0.6":
+  version "2.0.10"
+  resolved "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.0.10.tgz"
+  integrity sha512-ygEZ1mwPjcPo/OulhzLE7mtDrQBWI8vZzEWSNB2W/RNCRjoQGwbaK4N8lV4rid7Ts4qvySU3njMN7YCiSlSaTQ==
+
+"@floating-ui/core@^1.0.2":
+  version "1.0.2"
+  resolved "https://registry.npmmirror.com/@floating-ui/core/-/core-1.0.2.tgz"
+  integrity sha512-Skfy0YS3NJ5nV9us0uuPN0HDk1Q4edljaOhRBJGDWs9EBa7ZVMYBHRFlhLvvmwEoaIM9BlH6QJFn9/uZg0bACg==
+
+"@floating-ui/dom@^1.0.1":
+  version "1.0.7"
+  resolved "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.0.7.tgz"
+  integrity sha512-6RsqvCYe0AYWtsGvuWqCm7mZytnXAZCjWtsWu1Kg8dI3INvj/DbKlDsZO+mKSaQdPT12uxIW9W2dAWJkPx4Y5g==
+  dependencies:
+    "@floating-ui/core" "^1.0.2"
+
+"@popperjs/core@npm:@sxzz/popperjs-es@^2.11.7":
+  version "2.11.7"
+  resolved "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz"
+  integrity sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==
+
+"@transloadit/prettier-bytes@0.0.7":
+  version "0.0.7"
+  resolved "https://registry.npmmirror.com/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz"
+  integrity sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==
+
+"@types/event-emitter@^0.3.3":
+  version "0.3.5"
+  resolved "https://registry.npmmirror.com/@types/event-emitter/-/event-emitter-0.3.5.tgz"
+  integrity sha512-zx2/Gg0Eg7gwEiOIIh5w9TrhKKTeQh7CPCOPNc0el4pLSwzebA8SmnHwZs2dWlLONvyulykSwGSQxQHLhjGLvQ==
+
+"@types/lodash-es@*", "@types/lodash-es@^4.17.6":
+  version "4.17.6"
+  resolved "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.6.tgz"
+  integrity sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==
+  dependencies:
+    "@types/lodash" "*"
+
+"@types/lodash@*", "@types/lodash@^4.14.182":
+  version "4.14.191"
+  resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.191.tgz"
+  integrity sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==
+
+"@types/web-bluetooth@^0.0.16":
+  version "0.0.16"
+  resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz"
+  integrity sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==
+
+"@uppy/companion-client@^2.2.2":
+  version "2.2.2"
+  resolved "https://registry.npmmirror.com/@uppy/companion-client/-/companion-client-2.2.2.tgz"
+  integrity sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==
+  dependencies:
+    "@uppy/utils" "^4.1.2"
+    namespace-emitter "^2.0.1"
+
+"@uppy/core@^2.0.3", "@uppy/core@^2.1.1", "@uppy/core@^2.1.4", "@uppy/core@^2.3.3":
+  version "2.3.4"
+  resolved "https://registry.npmmirror.com/@uppy/core/-/core-2.3.4.tgz"
+  integrity sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==
+  dependencies:
+    "@transloadit/prettier-bytes" "0.0.7"
+    "@uppy/store-default" "^2.1.1"
+    "@uppy/utils" "^4.1.3"
+    lodash.throttle "^4.1.1"
+    mime-match "^1.0.2"
+    namespace-emitter "^2.0.1"
+    nanoid "^3.1.25"
+    preact "^10.5.13"
+
+"@uppy/store-default@^2.1.1":
+  version "2.1.1"
+  resolved "https://registry.npmmirror.com/@uppy/store-default/-/store-default-2.1.1.tgz"
+  integrity sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ==
+
+"@uppy/utils@^4.1.2", "@uppy/utils@^4.1.3":
+  version "4.1.3"
+  resolved "https://registry.npmmirror.com/@uppy/utils/-/utils-4.1.3.tgz"
+  integrity sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==
+  dependencies:
+    lodash.throttle "^4.1.1"
+
+"@uppy/xhr-upload@^2.0.3", "@uppy/xhr-upload@^2.0.7":
+  version "2.1.3"
+  resolved "https://registry.npmmirror.com/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz"
+  integrity sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==
+  dependencies:
+    "@uppy/companion-client" "^2.2.2"
+    "@uppy/utils" "^4.1.2"
+    nanoid "^3.1.25"
+
+"@vitejs/plugin-vue@^3.2.0":
+  version "3.2.0"
+  resolved "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-3.2.0.tgz"
+  integrity sha512-E0tnaL4fr+qkdCNxJ+Xd0yM31UwMkQje76fsDVBBUCoGOUPexu2VDUYHL8P4CwV+zMvWw6nlRw19OnRKmYAJpw==
+
+"@vue/compiler-core@3.2.45":
+  version "3.2.45"
+  resolved "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.2.45.tgz"
+  integrity sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A==
+  dependencies:
+    "@babel/parser" "^7.16.4"
+    "@vue/shared" "3.2.45"
+    estree-walker "^2.0.2"
+    source-map "^0.6.1"
+
+"@vue/compiler-dom@3.2.45":
+  version "3.2.45"
+  resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz"
+  integrity sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==
+  dependencies:
+    "@vue/compiler-core" "3.2.45"
+    "@vue/shared" "3.2.45"
+
+"@vue/compiler-sfc@3.2.45":
+  version "3.2.45"
+  resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz"
+  integrity sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q==
+  dependencies:
+    "@babel/parser" "^7.16.4"
+    "@vue/compiler-core" "3.2.45"
+    "@vue/compiler-dom" "3.2.45"
+    "@vue/compiler-ssr" "3.2.45"
+    "@vue/reactivity-transform" "3.2.45"
+    "@vue/shared" "3.2.45"
+    estree-walker "^2.0.2"
+    magic-string "^0.25.7"
+    postcss "^8.1.10"
+    source-map "^0.6.1"
+
+"@vue/compiler-ssr@3.2.45":
+  version "3.2.45"
+  resolved "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz"
+  integrity sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ==
+  dependencies:
+    "@vue/compiler-dom" "3.2.45"
+    "@vue/shared" "3.2.45"
+
+"@vue/devtools-api@^6.0.0":
+  version "6.4.5"
+  resolved "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.4.5.tgz"
+  integrity sha512-JD5fcdIuFxU4fQyXUu3w2KpAJHzTVdN+p4iOX2lMWSHMOoQdMAcpFLZzm9Z/2nmsoZ1a96QEhZ26e50xLBsgOQ==
+
+"@vue/reactivity-transform@3.2.45":
+  version "3.2.45"
+  resolved "https://registry.npmmirror.com/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz"
+  integrity sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ==
+  dependencies:
+    "@babel/parser" "^7.16.4"
+    "@vue/compiler-core" "3.2.45"
+    "@vue/shared" "3.2.45"
+    estree-walker "^2.0.2"
+    magic-string "^0.25.7"
+
+"@vue/reactivity@3.2.45":
+  version "3.2.45"
+  resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.2.45.tgz"
+  integrity sha512-PRvhCcQcyEVohW0P8iQ7HDcIOXRjZfAsOds3N99X/Dzewy8TVhTCT4uXpAHfoKjVTJRA0O0K+6QNkDIZAxNi3A==
+  dependencies:
+    "@vue/shared" "3.2.45"
+
+"@vue/runtime-core@3.2.45":
+  version "3.2.45"
+  resolved "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.2.45.tgz"
+  integrity sha512-gzJiTA3f74cgARptqzYswmoQx0fIA+gGYBfokYVhF8YSXjWTUA2SngRzZRku2HbGbjzB6LBYSbKGIaK8IW+s0A==
+  dependencies:
+    "@vue/reactivity" "3.2.45"
+    "@vue/shared" "3.2.45"
+
+"@vue/runtime-dom@3.2.45":
+  version "3.2.45"
+  resolved "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz"
+  integrity sha512-cy88YpfP5Ue2bDBbj75Cb4bIEZUMM/mAkDMfqDTpUYVgTf/kuQ2VQ8LebuZ8k6EudgH8pYhsGWHlY0lcxlvTwA==
+  dependencies:
+    "@vue/runtime-core" "3.2.45"
+    "@vue/shared" "3.2.45"
+    csstype "^2.6.8"
+
+"@vue/server-renderer@3.2.45":
+  version "3.2.45"
+  resolved "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.2.45.tgz"
+  integrity sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g==
+  dependencies:
+    "@vue/compiler-ssr" "3.2.45"
+    "@vue/shared" "3.2.45"
+
+"@vue/shared@3.2.45":
+  version "3.2.45"
+  resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.2.45.tgz"
+  integrity sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==
+
+"@vueuse/core@^9.1.0":
+  version "9.6.0"
+  resolved "https://registry.npmmirror.com/@vueuse/core/-/core-9.6.0.tgz"
+  integrity sha512-qGUcjKQXHgN+jqXEgpeZGoxdCbIDCdVPz3QiF1uyecVGbMuM63o96I1GjYx5zskKgRI0FKSNsVWM7rwrRMTf6A==
+  dependencies:
+    "@types/web-bluetooth" "^0.0.16"
+    "@vueuse/metadata" "9.6.0"
+    "@vueuse/shared" "9.6.0"
+    vue-demi "*"
+
+"@vueuse/metadata@9.6.0":
+  version "9.6.0"
+  resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.6.0.tgz"
+  integrity sha512-sIC8R+kWkIdpi5X2z2Gk8TRYzmczDwHRhEFfCu2P+XW2JdPoXrziqsGpDDsN7ykBx4ilwieS7JUIweVGhvZ93w==
+
+"@vueuse/shared@9.6.0":
+  version "9.6.0"
+  resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.6.0.tgz"
+  integrity sha512-/eDchxYYhkHnFyrb00t90UfjCx94kRHxc7J1GtBCqCG4HyPMX+krV9XJgVtWIsAMaxKVU4fC8NSUviG1JkwhUQ==
+  dependencies:
+    vue-demi "*"
+
+"@wangeditor/basic-modules@^1.1.7", "@wangeditor/basic-modules@1.x":
+  version "1.1.7"
+  resolved "https://registry.npmmirror.com/@wangeditor/basic-modules/-/basic-modules-1.1.7.tgz"
+  integrity sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==
+  dependencies:
+    is-url "^1.2.4"
+
+"@wangeditor/code-highlight@^1.0.3":
+  version "1.0.3"
+  resolved "https://registry.npmmirror.com/@wangeditor/code-highlight/-/code-highlight-1.0.3.tgz"
+  integrity sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==
+  dependencies:
+    prismjs "^1.23.0"
+
+"@wangeditor/core@^1.1.19", "@wangeditor/core@1.x":
+  version "1.1.19"
+  resolved "https://registry.npmmirror.com/@wangeditor/core/-/core-1.1.19.tgz"
+  integrity sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==
+  dependencies:
+    "@types/event-emitter" "^0.3.3"
+    event-emitter "^0.3.5"
+    html-void-elements "^2.0.0"
+    i18next "^20.4.0"
+    scroll-into-view-if-needed "^2.2.28"
+    slate-history "^0.66.0"
+
+"@wangeditor/editor-for-vue@^5.1.12":
+  version "5.1.12"
+  resolved "https://registry.npmmirror.com/@wangeditor/editor-for-vue/-/editor-for-vue-5.1.12.tgz"
+  integrity sha512-0Ds3D8I+xnpNWezAeO7HmPRgTfUxHLMd9JKcIw+QzvSmhC5xUHbpCcLU+KLmeBKTR/zffnS5GQo6qi3GhTMJWQ==
+
+"@wangeditor/editor@>=5.1.0":
+  version "5.1.23"
+  resolved "https://registry.npmmirror.com/@wangeditor/editor/-/editor-5.1.23.tgz"
+  integrity sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==
+  dependencies:
+    "@uppy/core" "^2.1.1"
+    "@uppy/xhr-upload" "^2.0.3"
+    "@wangeditor/basic-modules" "^1.1.7"
+    "@wangeditor/code-highlight" "^1.0.3"
+    "@wangeditor/core" "^1.1.19"
+    "@wangeditor/list-module" "^1.0.5"
+    "@wangeditor/table-module" "^1.1.4"
+    "@wangeditor/upload-image-module" "^1.0.2"
+    "@wangeditor/video-module" "^1.1.4"
+    dom7 "^3.0.0"
+    is-hotkey "^0.2.0"
+    lodash.camelcase "^4.3.0"
+    lodash.clonedeep "^4.5.0"
+    lodash.debounce "^4.0.8"
+    lodash.foreach "^4.5.0"
+    lodash.isequal "^4.5.0"
+    lodash.throttle "^4.1.1"
+    lodash.toarray "^4.4.0"
+    nanoid "^3.2.0"
+    slate "^0.72.0"
+    snabbdom "^3.1.0"
+
+"@wangeditor/list-module@^1.0.5":
+  version "1.0.5"
+  resolved "https://registry.npmmirror.com/@wangeditor/list-module/-/list-module-1.0.5.tgz"
+  integrity sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==
+
+"@wangeditor/table-module@^1.1.4":
+  version "1.1.4"
+  resolved "https://registry.npmmirror.com/@wangeditor/table-module/-/table-module-1.1.4.tgz"
+  integrity sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==
+
+"@wangeditor/upload-image-module@^1.0.2":
+  version "1.0.2"
+  resolved "https://registry.npmmirror.com/@wangeditor/upload-image-module/-/upload-image-module-1.0.2.tgz"
+  integrity sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==
+
+"@wangeditor/video-module@^1.1.4":
+  version "1.1.4"
+  resolved "https://registry.npmmirror.com/@wangeditor/video-module/-/video-module-1.1.4.tgz"
+  integrity sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==
+
+async-validator@^4.2.5:
+  version "4.2.5"
+  resolved "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz"
+  integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz"
+  integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
+
+axios@^1.2.0:
+  version "1.6.0"
+  resolved "https://registry.npmmirror.com/axios/-/axios-1.6.0.tgz"
+  integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==
+  dependencies:
+    follow-redirects "^1.15.0"
+    form-data "^4.0.0"
+    proxy-from-env "^1.1.0"
+
+call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.6, call-bind@^1.0.7:
+  version "1.0.7"
+  resolved "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.7.tgz"
+  integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
+  dependencies:
+    es-define-property "^1.0.0"
+    es-errors "^1.3.0"
+    function-bind "^1.1.2"
+    get-intrinsic "^1.2.4"
+    set-function-length "^1.2.1"
+
+clone@^2.1.1:
+  version "2.1.2"
+  resolved "https://registry.npmmirror.com/clone/-/clone-2.1.2.tgz"
+  integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==
+
+combined-stream@^1.0.8:
+  version "1.0.8"
+  resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz"
+  integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+  dependencies:
+    delayed-stream "~1.0.0"
+
+compute-scroll-into-view@^1.0.20:
+  version "1.0.20"
+  resolved "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz"
+  integrity sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==
+
+csstype@^2.6.8:
+  version "2.6.21"
+  resolved "https://registry.npmmirror.com/csstype/-/csstype-2.6.21.tgz"
+  integrity sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==
+
+d@^1.0.1, d@^1.0.2, d@1:
+  version "1.0.2"
+  resolved "https://registry.npmmirror.com/d/-/d-1.0.2.tgz"
+  integrity sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==
+  dependencies:
+    es5-ext "^0.10.64"
+    type "^2.7.2"
+
+dayjs@^1.11.3:
+  version "1.11.6"
+  resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.6.tgz"
+  integrity sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==
+
+deep-equal@^1.0.1:
+  version "1.1.2"
+  resolved "https://registry.npmmirror.com/deep-equal/-/deep-equal-1.1.2.tgz"
+  integrity sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==
+  dependencies:
+    is-arguments "^1.1.1"
+    is-date-object "^1.0.5"
+    is-regex "^1.1.4"
+    object-is "^1.1.5"
+    object-keys "^1.1.1"
+    regexp.prototype.flags "^1.5.1"
+
+define-data-property@^1.0.1, define-data-property@^1.1.4:
+  version "1.1.4"
+  resolved "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz"
+  integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
+  dependencies:
+    es-define-property "^1.0.0"
+    es-errors "^1.3.0"
+    gopd "^1.0.1"
+
+define-properties@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.npmmirror.com/define-properties/-/define-properties-1.2.1.tgz"
+  integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==
+  dependencies:
+    define-data-property "^1.0.1"
+    has-property-descriptors "^1.0.0"
+    object-keys "^1.1.1"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz"
+  integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
+
+dom7@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.npmmirror.com/dom7/-/dom7-3.0.0.tgz"
+  integrity sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==
+  dependencies:
+    ssr-window "^3.0.0-alpha.1"
+
+element-plus@^2.2.25:
+  version "2.2.25"
+  resolved "https://registry.npmmirror.com/element-plus/-/element-plus-2.2.25.tgz"
+  integrity sha512-HC8CWY31e6pPyBpgqI0QnWkBgs0vRzdYnEw3mpdM/NlKfp0PtNFX7NESQLomqoIulH5ftL09hjQmJNvZBQpthQ==
+  dependencies:
+    "@ctrl/tinycolor" "^3.4.1"
+    "@element-plus/icons-vue" "^2.0.6"
+    "@floating-ui/dom" "^1.0.1"
+    "@popperjs/core" "npm:@sxzz/popperjs-es@^2.11.7"
+    "@types/lodash" "^4.14.182"
+    "@types/lodash-es" "^4.17.6"
+    "@vueuse/core" "^9.1.0"
+    async-validator "^4.2.5"
+    dayjs "^1.11.3"
+    escape-html "^1.0.3"
+    lodash "^4.17.21"
+    lodash-es "^4.17.21"
+    lodash-unified "^1.0.2"
+    memoize-one "^6.0.0"
+    normalize-wheel-es "^1.2.0"
+
+es-define-property@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.0.tgz"
+  integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
+  dependencies:
+    get-intrinsic "^1.2.4"
+
+es-errors@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz"
+  integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
+
+es5-ext@^0.10.35, es5-ext@^0.10.62, es5-ext@^0.10.64, es5-ext@~0.10.14:
+  version "0.10.64"
+  resolved "https://registry.npmmirror.com/es5-ext/-/es5-ext-0.10.64.tgz"
+  integrity sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==
+  dependencies:
+    es6-iterator "^2.0.3"
+    es6-symbol "^3.1.3"
+    esniff "^2.0.1"
+    next-tick "^1.1.0"
+
+es6-iterator@^2.0.3:
+  version "2.0.3"
+  resolved "https://registry.npmmirror.com/es6-iterator/-/es6-iterator-2.0.3.tgz"
+  integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==
+  dependencies:
+    d "1"
+    es5-ext "^0.10.35"
+    es6-symbol "^3.1.1"
+
+es6-symbol@^3.1.1, es6-symbol@^3.1.3:
+  version "3.1.4"
+  resolved "https://registry.npmmirror.com/es6-symbol/-/es6-symbol-3.1.4.tgz"
+  integrity sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==
+  dependencies:
+    d "^1.0.2"
+    ext "^1.7.0"
+
+esbuild-windows-64@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmmirror.com/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz"
+  integrity sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==
+
+esbuild@^0.15.9:
+  version "0.15.18"
+  resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.15.18.tgz"
+  integrity sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==
+  optionalDependencies:
+    "@esbuild/android-arm" "0.15.18"
+    "@esbuild/linux-loong64" "0.15.18"
+    esbuild-android-64 "0.15.18"
+    esbuild-android-arm64 "0.15.18"
+    esbuild-darwin-64 "0.15.18"
+    esbuild-darwin-arm64 "0.15.18"
+    esbuild-freebsd-64 "0.15.18"
+    esbuild-freebsd-arm64 "0.15.18"
+    esbuild-linux-32 "0.15.18"
+    esbuild-linux-64 "0.15.18"
+    esbuild-linux-arm "0.15.18"
+    esbuild-linux-arm64 "0.15.18"
+    esbuild-linux-mips64le "0.15.18"
+    esbuild-linux-ppc64le "0.15.18"
+    esbuild-linux-riscv64 "0.15.18"
+    esbuild-linux-s390x "0.15.18"
+    esbuild-netbsd-64 "0.15.18"
+    esbuild-openbsd-64 "0.15.18"
+    esbuild-sunos-64 "0.15.18"
+    esbuild-windows-32 "0.15.18"
+    esbuild-windows-64 "0.15.18"
+    esbuild-windows-arm64 "0.15.18"
+
+escape-html@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz"
+  integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
+
+esniff@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.npmmirror.com/esniff/-/esniff-2.0.1.tgz"
+  integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==
+  dependencies:
+    d "^1.0.1"
+    es5-ext "^0.10.62"
+    event-emitter "^0.3.5"
+    type "^2.7.2"
+
+estree-walker@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz"
+  integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
+
+event-emitter@^0.3.5:
+  version "0.3.5"
+  resolved "https://registry.npmmirror.com/event-emitter/-/event-emitter-0.3.5.tgz"
+  integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==
+  dependencies:
+    d "1"
+    es5-ext "~0.10.14"
+
+eventemitter3@^2.0.3:
+  version "2.0.3"
+  resolved "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-2.0.3.tgz"
+  integrity sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==
+
+ext@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.npmmirror.com/ext/-/ext-1.7.0.tgz"
+  integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==
+  dependencies:
+    type "^2.7.2"
+
+extend@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz"
+  integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+
+fast-diff@1.1.2:
+  version "1.1.2"
+  resolved "https://registry.npmmirror.com/fast-diff/-/fast-diff-1.1.2.tgz"
+  integrity sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==
+
+follow-redirects@^1.15.0:
+  version "1.15.2"
+  resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz"
+  integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
+
+form-data@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz"
+  integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.8"
+    mime-types "^2.1.12"
+
+function-bind@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz"
+  integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+
+functions-have-names@^1.2.3:
+  version "1.2.3"
+  resolved "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz"
+  integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
+
+get-intrinsic@^1.0.2, get-intrinsic@^1.1.3, get-intrinsic@^1.2.4:
+  version "1.2.4"
+  resolved "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz"
+  integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
+  dependencies:
+    es-errors "^1.3.0"
+    function-bind "^1.1.2"
+    has-proto "^1.0.1"
+    has-symbols "^1.0.3"
+    hasown "^2.0.0"
+
+gopd@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.npmmirror.com/gopd/-/gopd-1.0.1.tgz"
+  integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
+  dependencies:
+    get-intrinsic "^1.1.3"
+
+has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz"
+  integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
+  dependencies:
+    es-define-property "^1.0.0"
+
+has-proto@^1.0.1:
+  version "1.0.3"
+  resolved "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.3.tgz"
+  integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
+
+has-symbols@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz"
+  integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
+
+has-tostringtag@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz"
+  integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==
+  dependencies:
+    has-symbols "^1.0.3"
+
+hasown@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz"
+  integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
+  dependencies:
+    function-bind "^1.1.2"
+
+html-void-elements@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.npmmirror.com/html-void-elements/-/html-void-elements-2.0.1.tgz"
+  integrity sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==
+
+i18next@^20.4.0:
+  version "20.6.1"
+  resolved "https://registry.npmmirror.com/i18next/-/i18next-20.6.1.tgz"
+  integrity sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==
+  dependencies:
+    "@babel/runtime" "^7.12.0"
+
+immer@^9.0.6:
+  version "9.0.21"
+  resolved "https://registry.npmmirror.com/immer/-/immer-9.0.21.tgz"
+  integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==
+
+is-arguments@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.npmmirror.com/is-arguments/-/is-arguments-1.1.1.tgz"
+  integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==
+  dependencies:
+    call-bind "^1.0.2"
+    has-tostringtag "^1.0.0"
+
+is-core-module@^2.13.0:
+  version "2.13.1"
+  resolved "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.13.1.tgz"
+  integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==
+  dependencies:
+    hasown "^2.0.0"
+
+is-date-object@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.npmmirror.com/is-date-object/-/is-date-object-1.0.5.tgz"
+  integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
+  dependencies:
+    has-tostringtag "^1.0.0"
+
+is-hotkey@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.npmmirror.com/is-hotkey/-/is-hotkey-0.2.0.tgz"
+  integrity sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==
+
+is-plain-object@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-5.0.0.tgz"
+  integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
+
+is-regex@^1.1.4:
+  version "1.1.4"
+  resolved "https://registry.npmmirror.com/is-regex/-/is-regex-1.1.4.tgz"
+  integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
+  dependencies:
+    call-bind "^1.0.2"
+    has-tostringtag "^1.0.0"
+
+is-url@^1.2.4:
+  version "1.2.4"
+  resolved "https://registry.npmmirror.com/is-url/-/is-url-1.2.4.tgz"
+  integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==
+
+lodash-es@*, lodash-es@^4.17.21:
+  version "4.17.21"
+  resolved "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz"
+  integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
+
+lodash-unified@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz"
+  integrity sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==
+
+lodash.camelcase@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.npmmirror.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz"
+  integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
+
+lodash.clonedeep@^4.5.0:
+  version "4.5.0"
+  resolved "https://registry.npmmirror.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz"
+  integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==
+
+lodash.debounce@^4.0.8:
+  version "4.0.8"
+  resolved "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz"
+  integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
+
+lodash.foreach@^4.5.0:
+  version "4.5.0"
+  resolved "https://registry.npmmirror.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz"
+  integrity sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==
+
+lodash.isequal@^4.5.0:
+  version "4.5.0"
+  resolved "https://registry.npmmirror.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz"
+  integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==
+
+lodash.throttle@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.npmmirror.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz"
+  integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==
+
+lodash.toarray@^4.4.0:
+  version "4.4.0"
+  resolved "https://registry.npmmirror.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz"
+  integrity sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==
+
+lodash@*, lodash@^4.17.21:
+  version "4.17.21"
+  resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz"
+  integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
+magic-string@^0.25.7:
+  version "0.25.9"
+  resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.25.9.tgz"
+  integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==
+  dependencies:
+    sourcemap-codec "^1.4.8"
+
+memoize-one@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz"
+  integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==
+
+mime-db@1.52.0:
+  version "1.52.0"
+  resolved "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz"
+  integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
+mime-match@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.npmmirror.com/mime-match/-/mime-match-1.0.2.tgz"
+  integrity sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==
+  dependencies:
+    wildcard "^1.1.0"
+
+mime-types@^2.1.12:
+  version "2.1.35"
+  resolved "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz"
+  integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+  dependencies:
+    mime-db "1.52.0"
+
+namespace-emitter@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.npmmirror.com/namespace-emitter/-/namespace-emitter-2.0.1.tgz"
+  integrity sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==
+
+nanoid@^3.1.25, nanoid@^3.2.0, nanoid@^3.3.7:
+  version "3.3.7"
+  resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.7.tgz"
+  integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
+
+next-tick@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.npmmirror.com/next-tick/-/next-tick-1.1.0.tgz"
+  integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==
+
+normalize-wheel-es@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz"
+  integrity sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==
+
+object-assign@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz"
+  integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
+
+object-inspect@^1.9.0:
+  version "1.12.2"
+  resolved "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.2.tgz"
+  integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==
+
+object-is@^1.1.5:
+  version "1.1.6"
+  resolved "https://registry.npmmirror.com/object-is/-/object-is-1.1.6.tgz"
+  integrity sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==
+  dependencies:
+    call-bind "^1.0.7"
+    define-properties "^1.2.1"
+
+object-keys@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz"
+  integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
+
+parchment@^1.1.4:
+  version "1.1.4"
+  resolved "https://registry.npmmirror.com/parchment/-/parchment-1.1.4.tgz"
+  integrity sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==
+
+path-parse@^1.0.7:
+  version "1.0.7"
+  resolved "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz"
+  integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+picocolors@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz"
+  integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+
+postcss@^8.1.10, postcss@^8.4.18:
+  version "8.4.38"
+  resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.38.tgz"
+  integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==
+  dependencies:
+    nanoid "^3.3.7"
+    picocolors "^1.0.0"
+    source-map-js "^1.2.0"
+
+preact@^10.5.13:
+  version "10.22.0"
+  resolved "https://registry.npmmirror.com/preact/-/preact-10.22.0.tgz"
+  integrity sha512-RRurnSjJPj4rp5K6XoP45Ui33ncb7e4H7WiOHVpjbkvqvA3U+N8Z6Qbo0AE6leGYBV66n8EhEaFixvIu3SkxFw==
+
+prismjs@^1.23.0:
+  version "1.29.0"
+  resolved "https://registry.npmmirror.com/prismjs/-/prismjs-1.29.0.tgz"
+  integrity sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==
+
+proxy-from-env@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz"
+  integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
+
+qs@^6.11.0:
+  version "6.11.0"
+  resolved "https://registry.npmmirror.com/qs/-/qs-6.11.0.tgz"
+  integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
+  dependencies:
+    side-channel "^1.0.4"
+
+quill-delta@^3.6.2:
+  version "3.6.3"
+  resolved "https://registry.npmmirror.com/quill-delta/-/quill-delta-3.6.3.tgz"
+  integrity sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==
+  dependencies:
+    deep-equal "^1.0.1"
+    extend "^3.0.2"
+    fast-diff "1.1.2"
+
+quill@^1.3.4:
+  version "1.3.7"
+  resolved "https://registry.npmmirror.com/quill/-/quill-1.3.7.tgz"
+  integrity sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==
+  dependencies:
+    clone "^2.1.1"
+    deep-equal "^1.0.1"
+    eventemitter3 "^2.0.3"
+    extend "^3.0.2"
+    parchment "^1.1.4"
+    quill-delta "^3.6.2"
+
+regenerator-runtime@^0.14.0:
+  version "0.14.1"
+  resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz"
+  integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
+
+regexp.prototype.flags@^1.5.1:
+  version "1.5.2"
+  resolved "https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz"
+  integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==
+  dependencies:
+    call-bind "^1.0.6"
+    define-properties "^1.2.1"
+    es-errors "^1.3.0"
+    set-function-name "^2.0.1"
+
+resolve@^1.22.1:
+  version "1.22.8"
+  resolved "https://registry.npmmirror.com/resolve/-/resolve-1.22.8.tgz"
+  integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
+  dependencies:
+    is-core-module "^2.13.0"
+    path-parse "^1.0.7"
+    supports-preserve-symlinks-flag "^1.0.0"
+
+rollup@^2.79.1:
+  version "2.79.1"
+  resolved "https://registry.npmmirror.com/rollup/-/rollup-2.79.1.tgz"
+  integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==
+  optionalDependencies:
+    fsevents "~2.3.2"
+
+scroll-into-view-if-needed@^2.2.28:
+  version "2.2.31"
+  resolved "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz"
+  integrity sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==
+  dependencies:
+    compute-scroll-into-view "^1.0.20"
+
+set-function-length@^1.2.1:
+  version "1.2.2"
+  resolved "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz"
+  integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
+  dependencies:
+    define-data-property "^1.1.4"
+    es-errors "^1.3.0"
+    function-bind "^1.1.2"
+    get-intrinsic "^1.2.4"
+    gopd "^1.0.1"
+    has-property-descriptors "^1.0.2"
+
+set-function-name@^2.0.1:
+  version "2.0.2"
+  resolved "https://registry.npmmirror.com/set-function-name/-/set-function-name-2.0.2.tgz"
+  integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==
+  dependencies:
+    define-data-property "^1.1.4"
+    es-errors "^1.3.0"
+    functions-have-names "^1.2.3"
+    has-property-descriptors "^1.0.2"
+
+side-channel@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz"
+  integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
+  dependencies:
+    call-bind "^1.0.0"
+    get-intrinsic "^1.0.2"
+    object-inspect "^1.9.0"
+
+slate-history@^0.66.0:
+  version "0.66.0"
+  resolved "https://registry.npmmirror.com/slate-history/-/slate-history-0.66.0.tgz"
+  integrity sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==
+  dependencies:
+    is-plain-object "^5.0.0"
+
+slate@^0.72.0, slate@>=0.65.3:
+  version "0.72.8"
+  resolved "https://registry.npmmirror.com/slate/-/slate-0.72.8.tgz"
+  integrity sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==
+  dependencies:
+    immer "^9.0.6"
+    is-plain-object "^5.0.0"
+    tiny-warning "^1.0.3"
+
+snabbdom@^3.1.0:
+  version "3.6.2"
+  resolved "https://registry.npmmirror.com/snabbdom/-/snabbdom-3.6.2.tgz"
+  integrity sha512-ig5qOnCDbugFntKi6c7Xlib8bA6xiJVk8O+WdFrV3wxbMqeHO0hXFQC4nAhPVWfZfi8255lcZkNhtIBINCc4+Q==
+
+source-map-js@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.0.tgz"
+  integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==
+
+source-map@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz"
+  integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+sourcemap-codec@^1.4.8:
+  version "1.4.8"
+  resolved "https://registry.npmmirror.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz"
+  integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
+
+ssr-window@^3.0.0-alpha.1:
+  version "3.0.0"
+  resolved "https://registry.npmmirror.com/ssr-window/-/ssr-window-3.0.0.tgz"
+  integrity sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==
+
+supports-preserve-symlinks-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
+  integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+
+tiny-warning@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.npmmirror.com/tiny-warning/-/tiny-warning-1.0.3.tgz"
+  integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
+
+type@^2.7.2:
+  version "2.7.2"
+  resolved "https://registry.npmmirror.com/type/-/type-2.7.2.tgz"
+  integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==
+
+vite@^3.0.0, vite@^3.2.3:
+  version "3.2.10"
+  resolved "https://registry.npmmirror.com/vite/-/vite-3.2.10.tgz"
+  integrity sha512-Dx3olBo/ODNiMVk/cA5Yft9Ws+snLOXrhLtrI3F4XLt4syz2Yg8fayZMWScPKoz12v5BUv7VEmQHnsfpY80fYw==
+  dependencies:
+    esbuild "^0.15.9"
+    postcss "^8.4.18"
+    resolve "^1.22.1"
+    rollup "^2.79.1"
+  optionalDependencies:
+    fsevents "~2.3.2"
+
+vue-demi@*:
+  version "0.13.11"
+  resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz"
+  integrity sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==
+
+vue-quill-editor@^3.0.6:
+  version "3.0.6"
+  resolved "https://registry.npmmirror.com/vue-quill-editor/-/vue-quill-editor-3.0.6.tgz"
+  integrity sha512-g20oSZNWg8Hbu41Kinjd55e235qVWPLfg4NvsLW6d+DhgBTFbEuMpcWlUdrD6qT3+Noim6DRu18VLM9lVShXOQ==
+  dependencies:
+    object-assign "^4.1.1"
+    quill "^1.3.4"
+
+vue-router@^4.0.13:
+  version "4.0.13"
+  resolved "https://registry.npmmirror.com/vue-router/-/vue-router-4.0.13.tgz"
+  integrity sha512-LmXrC+BkDRLak+d5xTMgUYraT3Nj0H/vCbP+7usGvIl9Viqd1UP6AsP0i69pSbn9O0dXK/xCdp4yPw21HqV9Jw==
+  dependencies:
+    "@vue/devtools-api" "^6.0.0"
+
+"vue@^3.0.0-0 || ^2.6.0", vue@^3.0.5, vue@^3.2.0, vue@^3.2.25, vue@^3.2.41, vue@3.2.45:
+  version "3.2.45"
+  resolved "https://registry.npmmirror.com/vue/-/vue-3.2.45.tgz"
+  integrity sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA==
+  dependencies:
+    "@vue/compiler-dom" "3.2.45"
+    "@vue/compiler-sfc" "3.2.45"
+    "@vue/runtime-dom" "3.2.45"
+    "@vue/server-renderer" "3.2.45"
+    "@vue/shared" "3.2.45"
+
+wildcard@^1.1.0:
+  version "1.1.2"
+  resolved "https://registry.npmmirror.com/wildcard/-/wildcard-1.1.2.tgz"
+  integrity sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==