yangg 2 月之前
父节点
当前提交
b57184504f
共有 10 个文件被更改,包括 2612 次插入79 次删除
  1. 30 0
      components.d.ts
  2. 440 45
      package-lock.json
  3. 6 2
      package.json
  4. 2 1
      src/main.js
  5. 1 1
      src/router/menu.js
  6. 863 0
      src/views/index.vue
  7. 989 0
      src/views/xvue.vue
  8. 6 0
      tsconfig.json
  9. 6 2
      vite.config.js
  10. 269 28
      yarn.lock

+ 30 - 0
components.d.ts

@@ -0,0 +1,30 @@
+/* eslint-disable */
+// @ts-nocheck
+// Generated by unplugin-vue-components
+// Read more: https://github.com/vuejs/core/pull/3399
+// biome-ignore lint: disable
+export {}
+
+/* prettier-ignore */
+declare module 'vue' {
+  export interface GlobalComponents {
+    BatchInput: typeof import('./src/components/batchInput/index.vue')['default']
+    ChatInput: typeof import('./src/components/ChatInput/index.vue')['default']
+    CMenu: typeof import('./src/components/c-menu/index.vue')['default']
+    CModal: typeof import('./src/components/c-modal/index.vue')['default']
+    CTable: typeof import('./src/components/c-table/index.vue')['default']
+    EditModel: typeof import('./src/components/editModel/index.vue')['default']
+    ExportButton: typeof import('./src/components/ExportButton/index.vue')['default']
+    HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
+    KnowledgeConfig: typeof import('./src/components/KnowledgeConfig/index.vue')['default']
+    LargeSelect: typeof import('./src/components/largeSelect/index.vue')['default']
+    LargeTable: typeof import('./src/components/largeTable/index.vue')['default']
+    ModelConfig: typeof import('./src/components/ModelConfig/index.vue')['default']
+    RouterLink: typeof import('vue-router')['RouterLink']
+    RouterView: typeof import('vue-router')['RouterView']
+    SearchModel: typeof import('./src/components/searchModel/index.vue')['default']
+    SearchResults: typeof import('./src/components/SearchResults/index.vue')['default']
+    VoiceConfig: typeof import('./src/components/VoiceConfig/index.vue')['default']
+    WelcomeSection: typeof import('./src/components/WelcomeSection/index.vue')['default']
+  }
+}

+ 440 - 45
package-lock.json

@@ -9,7 +9,8 @@
       "version": "0.0.0",
       "dependencies": {
         "@ant-design/icons-vue": "^7.0.1",
-        "ant-design-vue": "^4.0.0-rc.6",
+        "ant-design-vue": "^4.2.6",
+        "ant-design-x-vue": "^1.0.7",
         "axios": "^1.7.9",
         "dayjs": "^1.11.13",
         "docx": "^9.1.0",
@@ -28,8 +29,11 @@
         "@vitejs/plugin-vue-jsx": "^4.1.1",
         "babel-plugin-import": "^1.13.8",
         "style-resources-loader": "^1.5.0",
+        "typescript": "~5.5.4",
+        "unplugin-vue-components": "^28.4.1",
         "vite": "^6.0.5",
-        "vue-cli-plugin-style-resources-loader": "^0.1.5"
+        "vue-cli-plugin-style-resources-loader": "^0.1.5",
+        "vue-tsc": "^2.1.6"
       }
     },
     "node_modules/@ampproject/remapping": {
@@ -53,6 +57,17 @@
         "@ctrl/tinycolor": "^3.4.0"
       }
     },
+    "node_modules/@ant-design/fast-color": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmmirror.com/@ant-design/fast-color/-/fast-color-2.0.6.tgz",
+      "integrity": "sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==",
+      "dependencies": {
+        "@babel/runtime": "^7.24.7"
+      },
+      "engines": {
+        "node": ">=8.x"
+      }
+    },
     "node_modules/@ant-design/icons-svg": {
       "version": "4.4.2",
       "resolved": "https://registry.npmmirror.com/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz",
@@ -1267,6 +1282,38 @@
         "vue": "^3.0.0"
       }
     },
+    "node_modules/@volar/language-core": {
+      "version": "2.4.12",
+      "resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.12.tgz",
+      "integrity": "sha512-RLrFdXEaQBWfSnYGVxvR2WrO6Bub0unkdHYIdC31HzIEqATIuuhRRzYu76iGPZ6OtA4Au1SnW0ZwIqPP217YhA==",
+      "dev": true,
+      "dependencies": {
+        "@volar/source-map": "2.4.12"
+      }
+    },
+    "node_modules/@volar/source-map": {
+      "version": "2.4.12",
+      "resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.12.tgz",
+      "integrity": "sha512-bUFIKvn2U0AWojOaqf63ER0N/iHIBYZPpNGogfLPQ68F5Eet6FnLlyho7BS0y2HJ1jFhSif7AcuTx1TqsCzRzw==",
+      "dev": true
+    },
+    "node_modules/@volar/typescript": {
+      "version": "2.4.12",
+      "resolved": "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.12.tgz",
+      "integrity": "sha512-HJB73OTJDgPc80K30wxi3if4fSsZZAOScbj2fcicMuOPoOkcf9NNAINb33o+DzhBdF9xTKC1gnPmIRDous5S0g==",
+      "dev": true,
+      "dependencies": {
+        "@volar/language-core": "2.4.12",
+        "path-browserify": "^1.0.1",
+        "vscode-uri": "^3.0.8"
+      }
+    },
+    "node_modules/@volar/typescript/node_modules/path-browserify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz",
+      "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
+      "dev": true
+    },
     "node_modules/@vue/babel-helper-vue-transform-on": {
       "version": "1.2.5",
       "resolved": "https://registry.npmmirror.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.2.5.tgz",
@@ -1361,11 +1408,75 @@
         "@vue/shared": "3.5.13"
       }
     },
+    "node_modules/@vue/compiler-vue2": {
+      "version": "2.7.16",
+      "resolved": "https://registry.npmmirror.com/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz",
+      "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==",
+      "dev": true,
+      "dependencies": {
+        "de-indent": "^1.0.2",
+        "he": "^1.2.0"
+      }
+    },
     "node_modules/@vue/devtools-api": {
       "version": "6.6.4",
       "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
       "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="
     },
+    "node_modules/@vue/language-core": {
+      "version": "2.2.8",
+      "resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-2.2.8.tgz",
+      "integrity": "sha512-rrzB0wPGBvcwaSNRriVWdNAbHQWSf0NlGqgKHK5mEkXpefjUlVRP62u03KvwZpvKVjRnBIQ/Lwre+Mx9N6juUQ==",
+      "dev": true,
+      "dependencies": {
+        "@volar/language-core": "~2.4.11",
+        "@vue/compiler-dom": "^3.5.0",
+        "@vue/compiler-vue2": "^2.7.16",
+        "@vue/shared": "^3.5.0",
+        "alien-signals": "^1.0.3",
+        "minimatch": "^9.0.3",
+        "muggle-string": "^0.4.1",
+        "path-browserify": "^1.0.1"
+      },
+      "peerDependencies": {
+        "typescript": "*"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@vue/language-core/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/@vue/language-core/node_modules/minimatch": {
+      "version": "9.0.5",
+      "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz",
+      "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@vue/language-core/node_modules/path-browserify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz",
+      "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
+      "dev": true
+    },
     "node_modules/@vue/reactivity": {
       "version": "3.5.13",
       "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.13.tgz",
@@ -1682,10 +1793,9 @@
       "peer": true
     },
     "node_modules/acorn": {
-      "version": "8.14.0",
-      "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.14.0.tgz",
-      "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
-      "peer": true,
+      "version": "8.14.1",
+      "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.14.1.tgz",
+      "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
       "bin": {
         "acorn": "bin/acorn"
       },
@@ -1764,13 +1874,19 @@
         "ajv": "^6.9.1"
       }
     },
+    "node_modules/alien-signals": {
+      "version": "1.0.13",
+      "resolved": "https://registry.npmmirror.com/alien-signals/-/alien-signals-1.0.13.tgz",
+      "integrity": "sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==",
+      "dev": true
+    },
     "node_modules/ant-design-vue": {
-      "version": "4.0.0-rc.6",
-      "resolved": "https://registry.npmmirror.com/ant-design-vue/-/ant-design-vue-4.0.0-rc.6.tgz",
-      "integrity": "sha512-j+GAhgC1p1+nmQVbaEeY2miZ1h+8jBLlxTESX93MwcshVaYTkZNhiyddtl92VvEDJTedzuX+1oT3TP5wG/+tHg==",
+      "version": "4.2.6",
+      "resolved": "https://registry.npmmirror.com/ant-design-vue/-/ant-design-vue-4.2.6.tgz",
+      "integrity": "sha512-t7eX13Yj3i9+i5g9lqFyYneoIb3OzTvQjq9Tts1i+eiOd3Eva/6GagxBSXM1fOCjqemIu0FYVE1ByZ/38epR3Q==",
       "dependencies": {
         "@ant-design/colors": "^6.0.0",
-        "@ant-design/icons-vue": "^6.1.0",
+        "@ant-design/icons-vue": "^7.0.0",
         "@babel/runtime": "^7.10.5",
         "@ctrl/tinycolor": "^3.5.0",
         "@emotion/hash": "^0.9.0",
@@ -1803,24 +1919,33 @@
         "vue": ">=3.2.0"
       }
     },
-    "node_modules/ant-design-vue/node_modules/@ant-design/icons-vue": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmmirror.com/@ant-design/icons-vue/-/icons-vue-6.1.0.tgz",
-      "integrity": "sha512-EX6bYm56V+ZrKN7+3MT/ubDkvJ5rK/O2t380WFRflDcVFgsvl3NLH7Wxeau6R8DbrO5jWR6DSTC3B6gYFp77AA==",
+    "node_modules/ant-design-x-vue": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmmirror.com/ant-design-x-vue/-/ant-design-x-vue-1.0.7.tgz",
+      "integrity": "sha512-odxMDJ2L+da+yWig/hTQbOD/ciGmsz6oN+WfnaH90FJs1fNEnpUIlvjIxwyUQDZuMX1VCcv8HkMEeRqJpnVADA==",
       "dependencies": {
-        "@ant-design/colors": "^6.0.0",
-        "@ant-design/icons-svg": "^4.2.1"
+        "@ant-design/fast-color": "^2.0.6",
+        "@emotion/hash": "^0.9.2",
+        "@emotion/unitless": "^0.10.0",
+        "classnames": "^2.5.1",
+        "csstype": "^3.1.3",
+        "stylis": "^4.3.4"
       },
       "peerDependencies": {
-        "vue": ">=3.0.3"
+        "ant-design-vue": ">=4.0.0",
+        "vue": ">=3.3.0"
       }
     },
+    "node_modules/ant-design-x-vue/node_modules/@emotion/unitless": {
+      "version": "0.10.0",
+      "resolved": "https://registry.npmmirror.com/@emotion/unitless/-/unitless-0.10.0.tgz",
+      "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg=="
+    },
     "node_modules/anymatch": {
       "version": "3.1.3",
       "resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz",
       "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
-      "optional": true,
-      "peer": true,
+      "devOptional": true,
       "dependencies": {
         "normalize-path": "^3.0.0",
         "picomatch": "^2.0.4"
@@ -2065,8 +2190,7 @@
       "version": "2.3.0",
       "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz",
       "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
-      "optional": true,
-      "peer": true,
+      "devOptional": true,
       "engines": {
         "node": ">=8"
       },
@@ -2443,8 +2567,7 @@
       "version": "3.6.0",
       "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz",
       "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
-      "optional": true,
-      "peer": true,
+      "devOptional": true,
       "dependencies": {
         "anymatch": "~3.1.2",
         "braces": "~3.0.2",
@@ -2468,8 +2591,7 @@
       "version": "3.0.3",
       "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz",
       "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
-      "optional": true,
-      "peer": true,
+      "devOptional": true,
       "dependencies": {
         "fill-range": "^7.1.1"
       },
@@ -2481,8 +2603,7 @@
       "version": "7.1.1",
       "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz",
       "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
-      "optional": true,
-      "peer": true,
+      "devOptional": true,
       "dependencies": {
         "to-regex-range": "^5.0.1"
       },
@@ -2494,8 +2615,7 @@
       "version": "7.0.0",
       "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz",
       "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-      "optional": true,
-      "peer": true,
+      "devOptional": true,
       "engines": {
         "node": ">=0.12.0"
       }
@@ -2504,8 +2624,7 @@
       "version": "5.0.1",
       "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz",
       "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-      "optional": true,
-      "peer": true,
+      "devOptional": true,
       "dependencies": {
         "is-number": "^7.0.0"
       },
@@ -2581,6 +2700,11 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/classnames": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmmirror.com/classnames/-/classnames-2.5.1.tgz",
+      "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="
+    },
     "node_modules/collection-visit": {
       "version": "1.0.0",
       "resolved": "https://registry.npmmirror.com/collection-visit/-/collection-visit-1.0.0.tgz",
@@ -2651,6 +2775,12 @@
         "typedarray": "^0.0.6"
       }
     },
+    "node_modules/confbox": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.2.1.tgz",
+      "integrity": "sha512-hkT3yDPFbs95mNCy1+7qNKC6Pro+/ibzYxtM2iqEigpf0sVw+bg4Zh9/snjsBcf990vfIsg5+1U7VyiyBb3etg==",
+      "dev": true
+    },
     "node_modules/console-browserify": {
       "version": "1.2.0",
       "resolved": "https://registry.npmmirror.com/console-browserify/-/console-browserify-1.2.0.tgz",
@@ -2812,6 +2942,12 @@
       "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz",
       "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="
     },
+    "node_modules/de-indent": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/de-indent/-/de-indent-1.0.2.tgz",
+      "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
+      "dev": true
+    },
     "node_modules/debug": {
       "version": "4.4.0",
       "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.0.tgz",
@@ -3318,6 +3454,12 @@
       "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
       "peer": true
     },
+    "node_modules/exsolve": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmmirror.com/exsolve/-/exsolve-1.0.4.tgz",
+      "integrity": "sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==",
+      "dev": true
+    },
     "node_modules/extend-shallow": {
       "version": "3.0.2",
       "resolved": "https://registry.npmmirror.com/extend-shallow/-/extend-shallow-3.0.2.tgz",
@@ -3580,6 +3722,7 @@
       "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": [
@@ -3677,8 +3820,7 @@
       "version": "5.1.2",
       "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz",
       "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-      "optional": true,
-      "peer": true,
+      "devOptional": true,
       "dependencies": {
         "is-glob": "^4.0.1"
       },
@@ -3824,6 +3966,15 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/he": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmmirror.com/he/-/he-1.2.0.tgz",
+      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+      "dev": true,
+      "bin": {
+        "he": "bin/he"
+      }
+    },
     "node_modules/hmac-drbg": {
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
@@ -3976,8 +4127,7 @@
       "version": "2.1.0",
       "resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz",
       "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
-      "optional": true,
-      "peer": true,
+      "devOptional": true,
       "dependencies": {
         "binary-extensions": "^2.0.0"
       },
@@ -4044,8 +4194,7 @@
       "version": "2.1.1",
       "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz",
       "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
-      "optional": true,
-      "peer": true,
+      "devOptional": true,
       "engines": {
         "node": ">=0.10.0"
       }
@@ -4054,8 +4203,7 @@
       "version": "4.0.3",
       "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz",
       "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
-      "optional": true,
-      "peer": true,
+      "devOptional": true,
       "dependencies": {
         "is-extglob": "^2.1.1"
       },
@@ -4316,6 +4464,23 @@
         "node": ">=8.9.0"
       }
     },
+    "node_modules/local-pkg": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-1.1.1.tgz",
+      "integrity": "sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==",
+      "dev": true,
+      "dependencies": {
+        "mlly": "^1.7.4",
+        "pkg-types": "^2.0.1",
+        "quansync": "^0.2.8"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
     "node_modules/locate-path": {
       "version": "3.0.0",
       "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-3.0.0.tgz",
@@ -4606,6 +4771,35 @@
         "mkdirp": "bin/cmd.js"
       }
     },
+    "node_modules/mlly": {
+      "version": "1.7.4",
+      "resolved": "https://registry.npmmirror.com/mlly/-/mlly-1.7.4.tgz",
+      "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==",
+      "dev": true,
+      "dependencies": {
+        "acorn": "^8.14.0",
+        "pathe": "^2.0.1",
+        "pkg-types": "^1.3.0",
+        "ufo": "^1.5.4"
+      }
+    },
+    "node_modules/mlly/node_modules/confbox": {
+      "version": "0.1.8",
+      "resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.1.8.tgz",
+      "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==",
+      "dev": true
+    },
+    "node_modules/mlly/node_modules/pkg-types": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmmirror.com/pkg-types/-/pkg-types-1.3.1.tgz",
+      "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==",
+      "dev": true,
+      "dependencies": {
+        "confbox": "^0.1.8",
+        "mlly": "^1.7.4",
+        "pathe": "^2.0.1"
+      }
+    },
     "node_modules/move-concurrently": {
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/move-concurrently/-/move-concurrently-1.0.1.tgz",
@@ -4627,6 +4821,12 @@
       "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
       "dev": true
     },
+    "node_modules/muggle-string": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.4.1.tgz",
+      "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==",
+      "dev": true
+    },
     "node_modules/nan": {
       "version": "2.22.0",
       "resolved": "https://registry.npmmirror.com/nan/-/nan-2.22.0.tgz",
@@ -4746,8 +4946,7 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz",
       "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-      "optional": true,
-      "peer": true,
+      "devOptional": true,
       "engines": {
         "node": ">=0.10.0"
       }
@@ -4998,6 +5197,12 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/pathe": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz",
+      "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+      "dev": true
+    },
     "node_modules/pbkdf2": {
       "version": "3.1.2",
       "resolved": "https://registry.npmmirror.com/pbkdf2/-/pbkdf2-3.1.2.tgz",
@@ -5034,8 +5239,7 @@
       "version": "2.3.1",
       "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz",
       "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
-      "optional": true,
-      "peer": true,
+      "devOptional": true,
       "engines": {
         "node": ">=8.6"
       },
@@ -5063,6 +5267,17 @@
         "node": ">=6"
       }
     },
+    "node_modules/pkg-types": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmmirror.com/pkg-types/-/pkg-types-2.1.0.tgz",
+      "integrity": "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==",
+      "dev": true,
+      "dependencies": {
+        "confbox": "^0.2.1",
+        "exsolve": "^1.0.1",
+        "pathe": "^2.0.3"
+      }
+    },
     "node_modules/posix-character-classes": {
       "version": "0.1.1",
       "resolved": "https://registry.npmmirror.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
@@ -5211,6 +5426,22 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/quansync": {
+      "version": "0.2.10",
+      "resolved": "https://registry.npmmirror.com/quansync/-/quansync-0.2.10.tgz",
+      "integrity": "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/antfu"
+        },
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/sxzz"
+        }
+      ]
+    },
     "node_modules/querystring-es3": {
       "version": "0.2.1",
       "resolved": "https://registry.npmmirror.com/querystring-es3/-/querystring-es3-0.2.1.tgz",
@@ -5307,8 +5538,7 @@
       "version": "3.6.0",
       "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz",
       "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
-      "optional": true,
-      "peer": true,
+      "devOptional": true,
       "dependencies": {
         "picomatch": "^2.2.1"
       },
@@ -6228,6 +6458,48 @@
         "node": ">=0.6.0"
       }
     },
+    "node_modules/tinyglobby": {
+      "version": "0.2.12",
+      "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.12.tgz",
+      "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==",
+      "dev": true,
+      "dependencies": {
+        "fdir": "^6.4.3",
+        "picomatch": "^4.0.2"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/SuperchupuDev"
+      }
+    },
+    "node_modules/tinyglobby/node_modules/fdir": {
+      "version": "6.4.3",
+      "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.4.3.tgz",
+      "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==",
+      "dev": true,
+      "peerDependencies": {
+        "picomatch": "^3 || ^4"
+      },
+      "peerDependenciesMeta": {
+        "picomatch": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/tinyglobby/node_modules/picomatch": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz",
+      "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
     "node_modules/to-arraybuffer": {
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
@@ -6303,11 +6575,30 @@
       "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
       "peer": true
     },
+    "node_modules/typescript": {
+      "version": "5.5.4",
+      "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.5.4.tgz",
+      "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
+      "devOptional": true,
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
     "node_modules/uc.micro": {
       "version": "2.1.0",
       "resolved": "https://registry.npmmirror.com/uc.micro/-/uc.micro-2.1.0.tgz",
       "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="
     },
+    "node_modules/ufo": {
+      "version": "1.5.4",
+      "resolved": "https://registry.npmmirror.com/ufo/-/ufo-1.5.4.tgz",
+      "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==",
+      "dev": true
+    },
     "node_modules/undici-types": {
       "version": "6.20.0",
       "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.20.0.tgz",
@@ -6355,6 +6646,82 @@
         "imurmurhash": "^0.1.4"
       }
     },
+    "node_modules/unplugin": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmmirror.com/unplugin/-/unplugin-2.2.2.tgz",
+      "integrity": "sha512-Qp+iiD+qCRnUek+nDoYvtWX7tfnYyXsrOnJ452FRTgOyKmTM7TUJ3l+PLPJOOWPTUyKISKp4isC5JJPSXUjGgw==",
+      "dev": true,
+      "dependencies": {
+        "acorn": "^8.14.1",
+        "webpack-virtual-modules": "^0.6.2"
+      },
+      "engines": {
+        "node": ">=18.12.0"
+      }
+    },
+    "node_modules/unplugin-utils": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmmirror.com/unplugin-utils/-/unplugin-utils-0.2.4.tgz",
+      "integrity": "sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==",
+      "dev": true,
+      "dependencies": {
+        "pathe": "^2.0.2",
+        "picomatch": "^4.0.2"
+      },
+      "engines": {
+        "node": ">=18.12.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sxzz"
+      }
+    },
+    "node_modules/unplugin-utils/node_modules/picomatch": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz",
+      "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/unplugin-vue-components": {
+      "version": "28.4.1",
+      "resolved": "https://registry.npmmirror.com/unplugin-vue-components/-/unplugin-vue-components-28.4.1.tgz",
+      "integrity": "sha512-niGSc0vJD9ueAnsqcfAldmtpkppZ09B6p2G1dL7X5S8KPdgbk1P+txPwaaDCe7N+eZh2VG1aAypLXkuJs3OSUg==",
+      "dev": true,
+      "dependencies": {
+        "chokidar": "^3.6.0",
+        "debug": "^4.4.0",
+        "local-pkg": "^1.0.0",
+        "magic-string": "^0.30.17",
+        "mlly": "^1.7.4",
+        "tinyglobby": "^0.2.12",
+        "unplugin": "^2.2.0",
+        "unplugin-utils": "^0.2.4"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "@babel/parser": "^7.15.8",
+        "@nuxt/kit": "^3.2.2",
+        "vue": "2 || 3"
+      },
+      "peerDependenciesMeta": {
+        "@babel/parser": {
+          "optional": true
+        },
+        "@nuxt/kit": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/unset-value": {
       "version": "1.0.0",
       "resolved": "https://registry.npmmirror.com/unset-value/-/unset-value-1.0.0.tgz",
@@ -6591,6 +6958,12 @@
       "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
       "peer": true
     },
+    "node_modules/vscode-uri": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz",
+      "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==",
+      "dev": true
+    },
     "node_modules/vue": {
       "version": "3.5.13",
       "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.13.tgz",
@@ -7037,6 +7410,22 @@
         "vue": "^3.2.0"
       }
     },
+    "node_modules/vue-tsc": {
+      "version": "2.2.8",
+      "resolved": "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-2.2.8.tgz",
+      "integrity": "sha512-jBYKBNFADTN+L+MdesNX/TB3XuDSyaWynKMDgR+yCSln0GQ9Tfb7JS2lr46s2LiFUT1WsmfWsSvIElyxzOPqcQ==",
+      "dev": true,
+      "dependencies": {
+        "@volar/typescript": "~2.4.11",
+        "@vue/language-core": "2.2.8"
+      },
+      "bin": {
+        "vue-tsc": "bin/vue-tsc.js"
+      },
+      "peerDependencies": {
+        "typescript": ">=5.0.0"
+      }
+    },
     "node_modules/vue-types": {
       "version": "3.0.2",
       "resolved": "https://registry.npmmirror.com/vue-types/-/vue-types-3.0.2.tgz",
@@ -7276,6 +7665,12 @@
         "node": ">=10.13.0"
       }
     },
+    "node_modules/webpack-virtual-modules": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
+      "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
+      "dev": true
+    },
     "node_modules/webpack/node_modules/schema-utils": {
       "version": "3.3.0",
       "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-3.3.0.tgz",

+ 6 - 2
package.json

@@ -10,7 +10,8 @@
   },
   "dependencies": {
     "@ant-design/icons-vue": "^7.0.1",
-    "ant-design-vue": "^4.0.0-rc.6",
+    "ant-design-vue": "^4.2.6",
+    "ant-design-x-vue": "^1.0.7",
     "axios": "^1.7.9",
     "dayjs": "^1.11.13",
     "docx": "^9.1.0",
@@ -29,7 +30,10 @@
     "@vitejs/plugin-vue-jsx": "^4.1.1",
     "babel-plugin-import": "^1.13.8",
     "style-resources-loader": "^1.5.0",
+    "typescript": "~5.5.4",
+    "unplugin-vue-components": "^28.4.1",
     "vite": "^6.0.5",
-    "vue-cli-plugin-style-resources-loader": "^0.1.5"
+    "vue-cli-plugin-style-resources-loader": "^0.1.5",
+    "vue-tsc": "^2.1.6"
   }
 }

+ 2 - 1
src/main.js

@@ -7,7 +7,8 @@ import store from './store'
 import antdUse from './antdUse'
 import 'dayjs/locale/zh-cn';
 import './app.less'
-
+/* import 'ant-design-vue/dist/antd.css'
+import 'ant-design-x-vue/dist/style.css' */
 // 创建应用上下文
 const app = createApp(App)
 app.config.productionTip

+ 1 - 1
src/router/menu.js

@@ -10,7 +10,7 @@ export const ROUTE = [
         path: '/report',
         name: 'report',
         title: '报表中心',
-        component: () => import('@views/report.vue')
+        component: () => import('@views/xvue.vue')
       },
     ]
   },

+ 863 - 0
src/views/index.vue

@@ -0,0 +1,863 @@
+<script setup lang="tsx">
+import {
+  Attachments,
+  type AttachmentsProps,
+  Bubble,
+  type BubbleListProps,
+  Conversations,
+  type ConversationsProps,
+  Prompts,
+  type PromptsProps,
+  Sender,
+  Welcome,
+  useXAgent,
+  useXChat,
+} from 'ant-design-x-vue';
+import {
+  CloudUploadOutlined,
+  CommentOutlined,
+  EllipsisOutlined,
+  FireOutlined,
+  HeartOutlined,
+  PaperClipOutlined,
+  PlusOutlined,
+  ReadOutlined,
+  ShareAltOutlined,
+  SmileOutlined,
+} from '@ant-design/icons-vue';
+import { Badge, Button, Space, theme } from 'ant-design-vue';
+import { computed, ref, watch, type VNode, h, onMounted } from 'vue';
+import MarkdownIt from 'markdown-it';
+
+defineOptions({ name: 'PlaygroundIndependent' });
+
+const sleep = () => new Promise((resolve) => setTimeout(resolve, 500));
+
+const renderTitle = (icon: VNode, title: string) => (
+  <Space align="start">
+    {icon}
+    <span>{title}</span>
+  </Space>
+);
+
+const defaultConversationsItems = [
+  {
+    key: '0',
+    label: 'What is Ant Design X?',
+  },
+];
+
+const placeholderPromptsItems: PromptsProps['items'] = [
+  {
+    key: '1',
+    label: renderTitle(<FireOutlined style={{ color: '#FF4D4F' }} />, 'Hot Topics'),
+    description: 'What are you interested in?',
+    children: [
+      {
+        key: '1-1',
+        description: `What's new in X?`,
+      },
+      {
+        key: '1-2',
+        description: `What's AGI?`,
+      },
+      {
+        key: '1-3',
+        description: `Where is the doc?`,
+      },
+    ],
+  },
+  {
+    key: '2',
+    label: renderTitle(<ReadOutlined style={{ color: '#1890FF' }} />, 'Design Guide'),
+    description: 'How to design a good product?',
+    children: [
+      {
+        key: '2-1',
+        icon: <HeartOutlined />,
+        description: `Know the well`,
+      },
+      {
+        key: '2-2',
+        icon: <SmileOutlined />,
+        description: `Set the AI role`,
+      },
+      {
+        key: '2-3',
+        icon: <CommentOutlined />,
+        description: `Express the feeling`,
+      },
+    ],
+  },
+];
+
+const senderPromptsItems: PromptsProps['items'] = [
+  {
+    key: '1',
+    description: 'Hot Topics',
+    icon: <FireOutlined style={{ color: '#FF4D4F' }} />,
+  },
+  {
+    key: '2',
+    description: 'Design Guide',
+    icon: <ReadOutlined style={{ color: '#1890FF' }} />,
+  },
+];
+
+const roles: BubbleListProps['roles'] = {
+  ai: {
+    placement: 'start',
+    typing: { step: 5, interval: 20 },
+    styles: {
+      content: {
+        borderRadius: '16px',
+      },
+    },
+  },
+  local: {
+    placement: 'end',
+    variant: 'shadow',
+  },
+};
+
+// ==================== Style ====================
+const { token } = theme.useToken();
+const styles = computed(() => {
+  return {
+    layout: {
+      width: '100%',
+      'min-width': '1000px',
+      height: '722px',
+      'border-radius': `${token.value.borderRadius}px`,
+      display: 'flex',
+      background: `${token.value.colorBgContainer}`,
+      'font-family': `AlibabaPuHuiTi, ${token.value.fontFamily}, sans-serif`,
+    },
+    menu: {
+      background: `${token.value.colorBgLayout}80`,
+      width: '280px',
+      height: '100%',
+      display: 'flex',
+      'flex-direction': 'column',
+    },
+    conversations: {
+      padding: '0 12px',
+      flex: 1,
+      'overflow-y': 'auto',
+    },
+    chat: {
+      height: '100%',
+      width: '100%',
+      'max-width': '700px',
+      margin: '0 auto',
+      'box-sizing': 'border-box',
+      display: 'flex',
+      'flex-direction': 'column',
+      padding: `${token.value.paddingLG}px`,
+      gap: '16px',
+    },
+    messages: {
+      flex: 1,
+    },
+    placeholder: {
+      'padding-top': '32px',
+    },
+    sender: {
+      'box-shadow': token.value.boxShadow,
+    },
+    logo: {
+      display: 'flex',
+      height: '72px',
+      'align-items': 'center',
+      'justify-content': 'start',
+      padding: '0 24px',
+      'box-sizing': 'border-box',
+    },
+    'logo-img': {
+      width: '24px',
+      height: '24px',
+      display: 'inline-block',
+    },
+    'logo-span': {
+      display: 'inline-block',
+      margin: '0 8px',
+      'font-weight': 'bold',
+      color: token.value.colorText,
+      'font-size': '16px',
+    },
+    addBtn: {
+      background: '#1677ff0f',
+      border: '1px solid #1677ff34',
+      width: 'calc(100% - 24px)',
+      margin: '0 12px 24px 12px',
+    }
+  } as const
+});
+
+// ==================== State ====================
+const headerOpen = ref(false);
+const content = ref('');
+const conversationsItems = ref(defaultConversationsItems);
+const activeKey = ref(defaultConversationsItems[0].key);
+const attachedFiles = ref<AttachmentsProps['items']>([]);
+const agentRequestLoading = ref(false);
+const pagination = ref({
+  total: 0,
+  page: 1,
+  pageSize: 20,
+  totalPages: 0
+});
+const loadingHistory = ref(false);
+
+// 添加文件类型分类存储
+const imageUrls = ref<string[]>([]);
+const documentUrls = ref<string[]>([]);
+
+// ==================== Runtime ====================
+const [ agent ] = useXAgent({
+  request: async ({ message, attachments }, { onSuccess, onError }) => {
+    agentRequestLoading.value = true;
+    
+    try {
+      // 调用多模态聊天接口
+      const apiUrl = `http://192.168.66.187:8082/chatbot/multimodal`;
+      const response = await fetch(apiUrl, {
+        method: 'POST',
+        headers: {
+          'Content-Type': 'application/json',
+        },
+        body: JSON.stringify({
+          message: message,
+          chat_config_id: "17",
+          user_id: 4,
+          session_id: "",
+          source: "pc",
+          image_urls: imageUrls.value,
+          documents: documentUrls.value,
+          merchant_id: "3",
+          model_type: "REMOTE_CLAUDE",
+	        model_name: "claude-3-sonnet-20240229"
+        }),
+      });
+      
+      if (!response.ok) {
+        throw new Error(`API request failed with status ${response.status}`);
+      }
+      
+      const responseData = await response.json();
+      
+      // 检查响应状态码
+      if (responseData.code !== 2000) {
+        throw new Error(`API returned error code: ${responseData.code}, message: ${responseData.message}`);
+      }
+      
+      // 从响应中提取内容
+      if (responseData.choices && responseData.choices[0].message.content) {
+        // 将AI回复内容传递给onSuccess
+        onSuccess(responseData.choices[0].message.content);
+        
+        // 可选:记录模型信息和token使用情况
+        console.log(`Model used: ${responseData.data.model}`);
+        if (responseData.usage) {
+          console.log(`Token usage: ${JSON.stringify(responseData.usage)}`);
+        }
+      } else {
+        throw new Error('Response data is missing content');
+      }
+    } catch (error) {
+      console.error('Error calling multimodal API:', error);
+      onError(error instanceof Error ? error : new Error('Unknown error occurred'));
+    } finally {
+      agentRequestLoading.value = false;
+      // 清空URL数组
+      imageUrls.value = [];
+      documentUrls.value = [];
+    }
+  },
+});
+
+const { onRequest, messages, setMessages } = useXChat({
+  agent: agent.value,
+  onRequest: (message, attachments) => {
+    return agent.value.request({
+      message,
+      attachments,
+    });
+  }
+});
+
+watch(activeKey, () => {
+  if (activeKey.value !== undefined) {
+    setMessages([]);
+  }
+}, { immediate: true });
+
+// ==================== Event ====================
+const onSubmit = (nextContent: string) => {
+  if (!nextContent) return;
+  
+  // 检查是否有正在上传的文件
+  const hasUploadingFiles = attachedFiles.value.some(file => file.status === 'uploading');
+  if (hasUploadingFiles) {
+    // 可以显示一个提示,告诉用户等待文件上传完成
+    console.warn('Please wait for file uploads to complete');
+    return;
+  }
+  
+  // 将附件文件传递给请求,同时传递分类后的URLs
+  onRequest(nextContent, attachedFiles.value);
+  
+  // 发送后清空输入和附件
+  content.value = '';
+  attachedFiles.value = [];
+  // 清空URL数组
+  imageUrls.value = [];
+  documentUrls.value = [];
+  headerOpen.value = false;
+};
+
+const onPromptsItemClick: PromptsProps['onItemClick'] = (info) => {
+  onRequest(info.data.description as string);
+};
+
+const onAddConversation = () => {
+  // 添加一个特殊的"新会话"选项
+  const newConversationKey = 'new';
+  
+  // 检查是否已经有新会话选项
+  if (!conversationsItems.value.some(item => item.key === newConversationKey)) {
+    conversationsItems.value = [
+      {
+        key: newConversationKey,
+        label: '新会话',
+      },
+      ...conversationsItems.value,
+    ];
+  }
+  
+  // 选中新会话
+  activeKey.value = newConversationKey;
+  // 清空消息
+  setMessages([]);
+};
+
+const onConversationClick: ConversationsProps['onActiveChange'] = async (key) => {
+  activeKey.value = key;
+  
+  // 如果是新会话,清空消息
+  if (key === 'new') {
+    setMessages([]);
+    return;
+  }
+  
+  // 查找选中的会话
+  const selectedSession = conversationsItems.value.find(item => item.key === key);
+  if (!selectedSession) return;
+  
+  // 这里可以添加加载特定会话消息的逻辑
+  // 例如:
+  try {
+    const response = await fetch(`http://192.168.66.187:8082/api/chat/messages?session_id=${key}`, {
+      method: 'GET',
+      headers: {
+        'Content-Type': 'application/json',
+      }
+    });
+    
+    if (!response.ok) {
+      throw new Error(`Failed to fetch messages: ${response.status}`);
+    }
+    
+    const result = await response.json();
+    if (result.code !== 2000) {
+      throw new Error(`API returned error: ${result.message}`);
+    }
+    
+    // 假设API返回的消息格式与您的消息格式兼容
+    if (result.data && result.data.messages) {
+      // 转换消息格式
+      const formattedMessages = result.data.messages.map((msg: any) => ({
+        id: msg.id || Math.random().toString(36).substring(2, 9),
+        message: msg.content,
+        status: msg.role === 'assistant' ? 'ai' : 'local'
+      }));
+      
+      setMessages(formattedMessages);
+    }
+  } catch (error) {
+    console.error('Error fetching messages:', error);
+    // 如果获取失败,清空消息
+    setMessages([]);
+  }
+};
+
+const handleFileChange: AttachmentsProps['onChange'] = (info) => {
+  console.log('File change event:', info);
+  
+  // 获取新添加的文件
+  const newFile = info.file;
+  
+  // 保存文件列表,包括原始文件对象
+  attachedFiles.value = info.fileList.map(file => ({
+    ...file,
+    // 确保保留原始文件对象以便上传
+    originFileObj: file.originFileObj
+  }));
+  
+  // 检查是否有新文件添加
+  if (newFile && newFile.status === 'uploading' && newFile.originFileObj) {
+    console.log('Starting upload for file:', newFile.name);
+    
+    // 立即上传文件
+    uploadFile(newFile.originFileObj)
+      .then(fileUrl => {
+        console.log('File uploaded successfully:', fileUrl);
+        // 更新文件状态为已上传成功
+        attachedFiles.value = attachedFiles.value.map(file => {
+          if (file.uid === newFile.uid) {
+            return {
+              ...file,
+              status: 'done',
+              url: fileUrl,
+              response: { url: fileUrl }
+            };
+          }
+          return file;
+        });
+      })
+      .catch(error => {
+        console.error('File upload failed:', error);
+        // 更新文件状态为上传失败
+        attachedFiles.value = attachedFiles.value.map(file => {
+          if (file.uid === newFile.uid) {
+            return {
+              ...file,
+              status: 'error',
+              error
+            };
+          }
+          return file;
+        });
+      });
+  }
+};
+
+// 添加文件上传函数
+const uploadFile = async (file: File): Promise<string> => {
+  const formData = new FormData();
+  formData.append('file', file);
+  
+  try {
+    const uploadResponse = await fetch('http://192.168.66.187:8082/upload/file', {
+      method: 'POST',
+      body: formData,
+    });
+    
+    if (!uploadResponse.ok) {
+      throw new Error(`File upload failed with status ${uploadResponse.status}`);
+    }
+    
+    const uploadResult = await uploadResponse.json();
+    
+    // 检查上传响应状态码
+    if (uploadResult.status !== 2000) {
+      throw new Error(`Upload API returned error: ${uploadResult.message}`);
+    }
+    
+    // 从响应中获取文件URL
+    const fileUrl = uploadResult.data?.fileUrl;
+    
+    if (!fileUrl) {
+      throw new Error('Upload response missing file URL');
+    }
+    
+    // 根据文件URL后缀或文件类型判断是否为图片
+    const isImage = (url: string, fileType: string): boolean => {
+      // 检查URL后缀
+      const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg'];
+      const hasImageExtension = imageExtensions.some(ext => url.toLowerCase().endsWith(ext));
+      
+      // 检查MIME类型
+      const isImageMimeType = fileType.startsWith('image/');
+      
+      return hasImageExtension || isImageMimeType;
+    };
+    
+    // 根据判断结果分类存储URL
+    if (isImage(fileUrl, file.type)) {
+      imageUrls.value.push(fileUrl);
+      console.log('Added image URL:', fileUrl);
+      console.log('Current image URLs:', imageUrls.value);
+    } else {
+      documentUrls.value.push(fileUrl);
+      console.log('Added document URL:', fileUrl);
+      console.log('Current document URLs:', documentUrls.value);
+    }
+    
+    return fileUrl;
+  } catch (error) {
+    console.error('Error uploading file:', error);
+    throw error;
+  }
+};
+
+// ==================== Nodes ====================
+const placeholderNode = computed(() => (
+  <Space direction="vertical" size={16} style={styles.value.placeholder}>
+    <Welcome
+      variant="borderless"
+      icon="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*s5sNRo5LjfQAAAAAAAAAAAAADgCCAQ/fmt.webp"
+      title="Hello, I'm Ant Design X"
+      description="Base on Ant Design, AGI product interface solution, create a better intelligent vision~"
+      extra={
+        <Space>
+          <Button icon={<ShareAltOutlined />} />
+          <Button icon={<EllipsisOutlined />} />
+        </Space>
+      }
+    />
+    <Prompts
+      title="Do you want?"
+      items={placeholderPromptsItems}
+      styles={{
+        list: {
+          width: '100%',
+        },
+        item: {
+          flex: 1,
+        },
+      }}
+      onItemClick={onPromptsItemClick}
+    />
+  </Space>
+));
+
+// 创建 markdown-it 实例
+const md = new MarkdownIt({
+  html: true,
+  linkify: true,
+  typographer: true
+});
+
+const items = computed<BubbleListProps['items']>(() => messages.value.map(({ id, message, status }) => {
+  // 检查消息是否是 markdown 格式
+  const isMarkdown = status === 'ai' && 
+    (message.includes('#') || message.includes('**') || message.includes('\n'));
+  
+  let content;
+  
+  if (isMarkdown && status === 'ai') {
+    // 渲染 markdown 内容
+    const htmlContent = md.render(message);
+    content = h('div', {
+      class: 'markdown-content',
+      innerHTML: htmlContent
+    });
+  } else {
+    // 普通文本内容
+    content = message;
+  }
+  
+  return {
+    key: id,
+    loading: status === 'loading',
+    role: status === 'local' ? 'local' : 'ai',
+    content: content,
+  };
+}));
+
+const attachmentsNode = computed(() => (
+  <Badge dot={attachedFiles.value.length > 0 && !headerOpen.value}>
+    <Button type="text" icon={<PaperClipOutlined />} onClick={() => headerOpen.value = !headerOpen.value} />
+  </Badge>
+));
+
+const senderHeader = computed(() => (
+  <Sender.Header
+    title="Attachments"
+    open={headerOpen.value}
+    onOpenChange={(open) => headerOpen.value = open}
+    styles={{
+      content: {
+        padding: 0,
+      },
+    }}
+  >
+    <Attachments
+      action="http://192.168.66.187:8082/upload/file" // 添加上传地址
+      name="file" // 指定上传字段名
+      items={attachedFiles.value}
+      onChange={handleFileChange}
+      customRequest={({ file, onSuccess, onError, onProgress }) => {
+        // 手动处理文件上传
+        if (file && file.originFileObj) {
+          console.log('Custom request triggered for file:', file.name);
+          uploadFile(file.originFileObj)
+            .then(fileUrl => {
+              console.log('Custom upload successful:', fileUrl);
+              onSuccess({ url: fileUrl }, new XMLHttpRequest());
+            })
+            .catch(err => {
+              console.error('Custom upload failed:', err);
+              onError(err);
+            });
+        }
+      }}
+      placeholder={(type) =>
+        type === 'drop'
+          ? { title: 'Drop file here' }
+          : {
+            icon: <CloudUploadOutlined />,
+            title: 'Upload files',
+            description: 'Click or drag files to this area to upload',
+          }
+      }
+    />
+  </Sender.Header>
+));
+
+const logoNode = computed(() => (
+  <div style={styles.value.logo}>
+    <img
+      src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*eco6RrQhxbMAAAAAAAAAAAAADgCCAQ/original"
+      draggable={false}
+      alt="logo"
+      style={styles.value['logo-img']}
+    />
+    <span style={styles.value['logo-span']}>Ant Design X Vue</span>
+  </div>
+));
+
+// 添加 markdown 样式
+const markdownStyles = `
+.markdown-content h3 {
+  font-size: 1.3em;
+  margin-top: 1em;
+  margin-bottom: 0.5em;
+  font-weight: 600;
+}
+
+.markdown-content h4 {
+  font-size: 1.1em;
+  margin-top: 1em;
+  margin-bottom: 0.5em;
+  font-weight: 600;
+}
+
+.markdown-content p {
+  margin-bottom: 0.8em;
+}
+
+.markdown-content ul, .markdown-content ol {
+  padding-left: 1.5em;
+  margin-bottom: 0.8em;
+}
+
+.markdown-content li {
+  margin-bottom: 0.3em;
+}
+
+.markdown-content strong {
+  font-weight: 600;
+}
+`;
+
+// 修改 fetchChatHistory 函数,处理 last_message 和 user_message
+const fetchChatHistory = async () => {
+  loadingHistory.value = true;
+  try {
+    const response = await fetch('http://192.168.66.187:8082/api/chat/history', {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json',
+      },
+      body: JSON.stringify({
+        merchant_id: "3",
+        user_id: 4,
+        page: pagination.value.page,
+        page_size: pagination.value.pageSize
+      }),
+    });
+
+    if (!response.ok) {
+      throw new Error(`获取聊天历史失败: ${response.status}`);
+    }
+
+    const result = await response.json();
+    
+    if (result.code !== 2000) {
+      throw new Error(`API返回错误: ${result.message}`);
+    }
+
+    // 更新会话列表
+    if (result.data && result.data.sessions) {
+      conversationsItems.value = result.data.sessions.map((session: any) => {
+        // 优先使用用户消息作为会话标签,如果没有则使用AI回复
+        const displayContent = session.user_message?.content || session.last_message?.content || '新会话';
+        
+        return {
+          key: session.session_id,
+          // 截取前20个字符作为标签,如果超过则添加省略号
+          label: displayContent.substring(0, 20) + (displayContent.length > 20 ? '...' : ''),
+          // 保存时间戳
+          timestamp: new Date(session.last_message?.created_at || Date.now()),
+          // 保存用户消息和AI回复,以便在UI中显示
+          userMessage: session.user_message,
+          aiMessage: session.last_message,
+          // 保存完整会话数据以备后用
+          sessionData: session
+        };
+      });
+      
+      // 如果有会话,默认选中第一个
+      if (conversationsItems.value.length > 0) {
+        activeKey.value = conversationsItems.value[0].key;
+        
+        // 加载第一个会话的消息
+        await loadSessionMessages(conversationsItems.value[0].key);
+      }
+      
+      // 更新分页信息
+      if (result.data.pagination) {
+        pagination.value = {
+          total: result.data.pagination.total,
+          page: result.data.pagination.page,
+          pageSize: result.data.pagination.page_size,
+          totalPages: result.data.pagination.total_pages
+        };
+      }
+    }
+  } catch (error) {
+    console.error('获取聊天历史出错:', error);
+    // 如果获取失败,使用默认会话列表
+    conversationsItems.value = defaultConversationsItems;
+  } finally {
+    loadingHistory.value = false;
+  }
+};
+
+// 修改加载会话消息的函数,处理用户消息和AI回复
+const loadSessionMessages = async (sessionId: string) => {
+  try {
+    // 显示加载状态
+    setMessages([{ id: 'loading', message: '加载消息中...', status: 'loading' }]);
+    
+    const response = await fetch(`http://192.168.66.187:8082/api/chat/messages?session_id=${sessionId}`, {
+      method: 'GET',
+      headers: {
+        'Content-Type': 'application/json',
+      }
+    });
+    
+    if (!response.ok) {
+      throw new Error(`获取消息失败: ${response.status}`);
+    }
+    
+    const result = await response.json();
+    if (result.code !== 2000) {
+      throw new Error(`API返回错误: ${result.message}`);
+    }
+    
+    // 处理消息数据
+    if (result.data && result.data.messages) {
+      // 转换消息格式并按时间排序
+      const formattedMessages = [];
+      
+      // 遍历消息,每组包含用户消息和AI回复
+      for (const msg of result.data.messages) {
+        // 如果有用户消息,添加到列表
+        if (msg.user_message && msg.user_message.content) {
+          formattedMessages.push({
+            id: `user_${msg.id || Math.random().toString(36).substring(2, 9)}`,
+            message: msg.user_message.content,
+            status: 'local',
+            timestamp: new Date(msg.user_message.created_at || Date.now())
+          });
+        }
+        
+        // 如果有AI回复,添加到列表
+        if (msg.last_message && msg.last_message.content) {
+          formattedMessages.push({
+            id: `ai_${msg.id || Math.random().toString(36).substring(2, 9)}`,
+            message: msg.last_message.content,
+            status: 'ai',
+            timestamp: new Date(msg.last_message.created_at || Date.now())
+          });
+        }
+      }
+      
+      // 按时间排序
+      formattedMessages.sort((a, b) => a.timestamp - b.timestamp);
+      
+      // 更新消息列表
+      setMessages(formattedMessages);
+    } else {
+      // 如果没有消息,显示空列表
+      setMessages([]);
+    }
+  } catch (error) {
+    console.error('加载会话消息出错:', error);
+    // 显示错误消息
+    setMessages([{
+      id: 'error',
+      message: '加载消息失败,请重试',
+      status: 'ai'
+    }]);
+  }
+};
+
+// 在组件挂载时获取聊天历史
+onMounted(() => {
+  /* fetchChatHistory(); */
+});
+
+defineRender(() => {
+  return (
+    <div style={styles.value.layout}>
+      {/* 添加 markdown 样式 */}
+      <style>{markdownStyles}</style>
+      
+      <div style={styles.value.menu}>
+        {/* 🌟 Logo */}
+        {logoNode.value}
+        {/* 🌟 添加会话 */}
+        <Button
+          onClick={onAddConversation}
+          type="link"
+          style={styles.value.addBtn}
+          icon={<PlusOutlined />}
+        >
+          New Conversation
+        </Button>
+        {/* 🌟 会话管理 */}
+        <Conversations
+          items={conversationsItems.value}
+          style={styles.value.conversations}
+          activeKey={activeKey.value}
+          onActiveChange={onConversationClick}
+        />
+      </div>
+      <div style={styles.value.chat}>
+        {/* 🌟 消息列表 */}
+        <Bubble.List
+          items={items.value.length > 0 ? items.value : [{ content: placeholderNode.value, variant: 'borderless' }]}
+          roles={roles}
+          style={styles.value.messages}
+        />
+        {/* 🌟 提示词 */}
+        <Prompts style={{ color: token.value.colorText }} items={senderPromptsItems} onItemClick={onPromptsItemClick} />
+        {/* 🌟 输入框 */}
+        <Sender
+          value={content.value}
+          header={senderHeader.value}
+          onSubmit={onSubmit}
+          onChange={(value) => content.value = value}
+          prefix={attachmentsNode.value}
+          loading={agentRequestLoading.value}
+          style={styles.value.sender}
+        />
+      </div>
+    </div>
+  )
+});
+</script>

+ 989 - 0
src/views/xvue.vue

@@ -0,0 +1,989 @@
+<template>
+  <div class="chat-container">
+    <!-- 左侧对话列表 -->
+    <div class="sidebar">
+      <div class="logo">
+        <img src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*eco6RrQhxbMAAAAAAAAAAAAADgCCAQ/original"
+          alt="logo" class="logo-img" />
+        <span class="logo-text">Ant Design X Vue</span>
+      </div>
+
+      <Button @click="onAddConversation" type="link" class="new-chat-btn">
+        <PlusOutlined />
+        New Conversation
+      </Button>
+
+      <Conversations :items="conversationItems" :defaultActiveKey="activeConversation" :style="sidebarStyle"
+        :menu="menuConfig" @activeChange="handleConversationChange" />
+    </div>
+
+    <!-- 右侧聊天区域 -->
+    <div class="chat-content">
+      <div v-if="messages.length > 0" class="messages-container" ref="messageContainer">
+        <Bubble.List 
+          :items="bubbleItems" 
+          :roles="roles" 
+          class="messages-list"
+          key="message-list"
+        >
+          <template #footer v-if="false">
+            <Space :size="token.paddingXXS">
+              <Button type="text" size="small" :icon="h(SyncOutlined)"></Button>
+              <Button type="text" size="small" :icon="h(CopyOutlined)" />
+            </Space>
+          </template>
+        </Bubble.List>
+      </div>
+
+      <div v-else>
+        <Welcome key="welcome" variant="borderless"
+          icon="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*s5sNRo5LjfQAAAAAAAAAAAAADgCCAQ/fmt.webp"
+          :title="welcomeTitle.content" :description="welcomeDescription">
+          <template #extra>
+            <Space>
+              <Button>
+                <template #icon>
+                  <ShareAltOutlined />
+                </template>
+              </Button>
+              <Button>
+                <template #icon>
+                  <EllipsisOutlined />
+                </template>
+              </Button>
+            </Space>
+          </template>
+        </Welcome>
+
+        <Prompts v-if="placeholderPromptsItems.length" title="Do you want?" :items="placeholderPromptsItems"
+          :styles="promptsStyles" @itemClick="onPromptsItemClick" />
+      </div>
+      <!-- 底部输入区域 -->
+      <div class="input-section">
+        <Flex align="center" justify="space-between" style="margin-bottom: 8px;">
+          <Prompts :items="senderPromptsItems" @itemClick="onPromptsItemClick" />
+          <a-select
+            ref="selectRef"
+            v-model:value="selectedModel"
+            style="width: 180px;"
+            :loading="modelLoading"
+            placeholder="选择模型"
+            @change="handleModelChange"
+            @focus="handleFocus"
+          >
+            <a-select-option 
+              v-for="option in modelOptions" 
+              :key="option.id"
+              :value="option.id"
+            >
+              {{ option.name }}
+            </a-select-option>
+          </a-select>
+        </Flex>
+        <Flex style="max-height: 250px;margin-top: 10px;" align="flex-end">
+          <Sender ref="senderRef" :header="senderHeader" :prefix="badgeNode" :value="inputContent" :loading="loading"
+            @change="handleInputChange" @submit="handleSubmit" />
+        </Flex>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, computed, markRaw, h, onMounted, nextTick, watch, CSSProperties } from 'vue'
+import {
+  Attachments,
+  Bubble,
+  Conversations,
+  Prompts,
+  Sender,
+  Welcome,
+  useXAgent,
+  useXChat,
+  ConversationsProps
+} from 'ant-design-x-vue'
+import {
+  CloudUploadOutlined,
+  CommentOutlined,
+  EllipsisOutlined,
+  FireOutlined,
+  HeartOutlined,
+  PaperClipOutlined,
+  PlusOutlined,
+  ReadOutlined,
+  ShareAltOutlined,
+  SmileOutlined,
+  LinkOutlined,
+  EditOutlined,
+  StopOutlined,
+  DeleteOutlined
+} from '@ant-design/icons-vue'
+import { UserOutlined } from '@ant-design/icons-vue';
+import { Badge, Button, Space, theme, Flex, Typography, message as messageAnt, Avatar, Select } from 'ant-design-vue'
+import MarkdownIt from 'markdown-it'
+import type { SelectProps } from 'ant-design-vue'
+
+const { token } = theme.useToken()
+const openValue = ref(true);
+// 状态管理
+const loading = ref(false)
+const headerOpen = ref(false)
+const inputContent = ref('')
+const attachedFiles = ref([])
+const activeConversation = ref('')
+const API_BASE_URL = 'http://192.168.66.187:8082'
+// 对话列表数据
+const conversationItems = ref([
+  {
+    key: 'chat1',
+    label: 'What is Ant Design X?',
+  }
+])
+/* 对话列表菜单 */
+const menuConfig: ConversationsProps['menu'] = (conversation) => ({
+  items: [
+    {
+      label: 'Operation 1',
+      key: 'operation1',
+      icon: h(EditOutlined),
+    },
+    {
+      label: 'Operation 2',
+      key: 'operation2',
+      icon: h(StopOutlined),
+      disabled: true,
+    },
+    {
+      label: 'Operation 3',
+      key: 'operation3',
+      icon: h(DeleteOutlined),
+      danger: true,
+    },
+  ],
+})
+
+// 聊天相关配置
+const roles = {
+  ai: {
+    placement: 'start',
+    typing: { step: 5, interval: 20 },
+    styles: {
+      content: {
+        borderRadius: '16px',
+      },
+    },
+  },
+  local: {
+    placement: 'end',
+    variant: 'shadow',
+  },
+}
+
+// 修改提示词配置,使用 defineComponent 包装
+const placeholderPromptsItems = ref([
+  {
+    key: '1',
+    label: 'Hot Topics',
+    icon: '',//markRaw(FireOutlined),
+    description: 'What are you interested in?',
+    children: [
+      { key: '1-1', description: `What's new in X?` },
+      { key: '1-2', description: `What's AGI?` },
+      { key: '1-3', description: `Where is the doc?` },
+    ],
+  },
+  {
+    key: '2',
+    label: 'Design Guide',
+    icon: '',//markRaw(ReadOutlined),
+    description: 'How to design a good product?',
+    children: [
+      { key: '2-1', icon: '', description: 'Know the well' },//markRaw(HeartOutlined)
+      { key: '2-2', icon: '', description: 'Set the AI role' },//markRaw(SmileOutlined)
+      { key: '2-3', icon: '', description: 'Express the feeling' },//markRaw(CommentOutlined)
+    ],
+  },
+])
+
+const senderPromptsItems = ref([
+  {
+    key: '1',
+    description: 'Hot Topics',
+    icon: ''//markRaw(FireOutlined),
+  },
+  {
+    key: '2',
+    description: 'Design Guide',
+    icon: '',//markRaw(ReadOutlined),
+  },
+])
+
+// 添加文件类型分类存储
+const imageUrls = ref<string[]>([]);
+const documentUrls = ref<string[]>([]);
+
+const fooAvatar: CSSProperties = {
+  color: '#f56a00',
+  backgroundColor: '#fde3cf',
+};
+
+const barAvatar: CSSProperties = {
+  color: '#fff',
+  backgroundColor: '#87d068',
+};
+
+const hideAvatar: CSSProperties = {
+  visibility: 'hidden',
+};
+
+// 消息处理
+const { messages, onRequest, setMessages } = useXChat({
+  agent: useXAgent({
+    request: async ({ message, attachments }, { onSuccess, onError }) => {
+      try {
+        loading.value = true
+        console.log('messages', messages.value)
+        // 保存当前消息状态
+        const currentMessages = [...messages.value]
+        
+        // 构建请求数据
+        const formData = new FormData()
+        formData.append('message', message)
+
+        // 添加附件
+        if (attachments?.length) {
+          attachments.forEach(file => {
+            formData.append('files', file)
+          })
+        }
+
+        // 发送请求到后端API
+        const response = await fetch('/api/chat', {
+          method: 'POST',
+          body: formData
+        })
+
+        if (!response.ok) {
+          throw new Error('请求失败')
+        }
+
+        const data = await response.json()
+        // 确保在成功回调前不会清空消息
+        setMessages(currentMessages)
+        onSuccess(data.message)
+
+      } catch (error) {
+        onError(error)
+        messageAnt.error('发送失败,请重试!')
+      } finally {
+        loading.value = false
+      }
+    }
+  })[0],
+  initialMessages: [], // 添加初始空数组
+  // 添加配置以防止自动清空消息
+  preserveMessages: true
+})
+
+// 添加消息状态监听
+watch(messages, (newMessages) => {
+  if (newMessages.length === 0 && activeConversation.value) {
+    // 如果消息被清空且存在活动会话,恢复上一次的消息
+    const lastMessages = [...messages.value]
+    if (lastMessages.length > 0) {
+      nextTick(() => {
+        setMessages(lastMessages)
+      })
+    }
+  }
+}, { deep: true })
+
+// 监听会话切换
+watch(activeConversation, () => {
+  if (activeConversation.value !== undefined) {
+    // 切换会话时清空消息
+    setMessages([])
+  }
+}, { immediate: true })
+
+// 新增会话处理
+const onAddConversation = () => {
+  const newKey = `chat${conversationItems.value.length + 1}`
+  conversationItems.value = [
+    ...conversationItems.value,
+    {
+      key: newKey,
+      label: `新会话 ${conversationItems.value.length + 1}`,
+    }
+  ]
+  activeConversation.value = newKey
+  // 清空当前会话消息
+  setMessages([])
+}
+
+// 创建 markdown-it 实例
+const md = new MarkdownIt({
+  html: true,
+  linkify: true,
+  typographer: true,
+  breaks: true
+})
+
+// 修改消息渲染相关的代码
+const bubbleItems = computed(() => {
+  if (!messages.value?.length) return []
+  
+  return messages.value.map((msg, index) => {
+    const baseItem = {
+      key: msg.id || `msg-${index}`,
+      role: msg.role || 'local',
+      status: msg.status || 'success',
+    }
+
+    if (msg.message) {
+      return {
+        ...baseItem,
+        content: h('div', {
+          class: 'markdown-content',
+          innerHTML: md.render(msg.message)
+        })
+      }
+    }
+
+    return baseItem
+  })
+})
+
+// 修改模型选择相关的响应式数据
+const selectedModel = ref('')
+const selectedModelInfo = ref({ name: '', type: '' }) // 新增:存储选中模型的完整信息
+const modelOptions = ref([])
+const modelLoading = ref(false)
+
+// 添加获取用户模型偏好的函数
+const fetchUserModelPreference = async () => {
+  try {
+    const response = await fetch(`${API_BASE_URL}/api/user/model_preference`, {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json'
+      },
+      body: JSON.stringify({
+        user_id: "4",
+        merchant_id: "3",
+        action: "get"
+      })
+    })
+
+    if (!response.ok) {
+      throw new Error('Failed to fetch user model preference')
+    }
+
+    const data = await response.json()
+    if (data.code === 2000 && data.data?.id) {
+      // 设置用户已配置的模型
+      
+      console.log('selectedModel', selectedModel.value)
+      // 从 modelOptions 中找到对应的模型信息并设置
+      const selectedOption = modelOptions.value.find(opt => opt.name === data.data.model_name)
+      console.log('selectedOption', selectedOption)
+      if (selectedOption) {
+        selectedModel.value = selectedOption.id
+        selectedModelInfo.value = {
+          name: selectedOption.name,
+          type: selectedOption.type
+        }
+      } else {
+        // 如果找不到对应的模型,使用第一个可用的模型
+        if (modelOptions.value.length > 0) {
+          const defaultModel = modelOptions.value[0]
+          selectedModel.value = defaultModel.id
+          selectedModelInfo.value = {
+            name: defaultModel.name,
+            type: defaultModel.type
+          }
+        }
+      }
+    } else {
+      // 如果没有用户偏好设置,使用第一个模型作为默认值
+      if (modelOptions.value.length > 0) {
+        const defaultModel = modelOptions.value[0]
+        selectedModel.value = defaultModel.id
+        selectedModelInfo.value = {
+          name: defaultModel.name,
+          type: defaultModel.type
+        }
+      }
+    }
+  } catch (error) {
+    console.error('Error fetching user model preference:', error)
+    // 如果获取偏好失败,使用第一个可用的模型
+    if (modelOptions.value.length > 0) {
+      const defaultModel = modelOptions.value[0]
+      selectedModel.value = defaultModel.id
+      selectedModelInfo.value = {
+        name: defaultModel.name,
+        type: defaultModel.type
+      }
+    }
+  }
+}
+
+// 修改获取模型列表的函数,在获取完列表后获取用户偏好
+const fetchModelOptions = async () => {
+  try {
+    modelLoading.value = true
+    const response = await fetch(`${API_BASE_URL}/api/models`)
+    
+    if (!response.ok) {
+      throw new Error('Failed to fetch models')
+    }
+    
+    const data = await response.json()
+    if (data.code === 2000) {
+      modelOptions.value = data.data.models
+      // .map(model => ({
+      //   value: model.model_name,
+      //   label: model.display_name || model.model_name
+      // }))
+      
+      // 获取模型列表后,获取用户偏好设置
+      await fetchUserModelPreference()
+      
+      // 如果没有用户偏好设置,使用第一个模型作为默认值
+      if (!selectedModel.value && modelOptions.value.length > 0) {
+        selectedModel.value = modelOptions.value[0].value
+      }
+    } else {
+      throw new Error(data.message || 'Failed to fetch models')
+    }
+  } catch (error) {
+    console.error('Error fetching models:', error)
+    messageAnt.error('获取模型列表失败')
+  } finally {
+    modelLoading.value = false
+  }
+}
+
+// 在组件挂载时获取模型列表
+onMounted(async () => {
+  console.log('Component mounted') // 添加日志
+  await fetchModelOptions()
+})
+
+// 修改模型切换处理函数
+const handleModelChange = async (value: string) => {
+  try {
+    console.log('Model changed to:', value)
+    
+    // 从选项中获取完整的模型信息
+    const selectedOption = modelOptions.value.find(opt => opt.id === value)
+    if (selectedOption) {
+      selectedModel.value = value
+      selectedModelInfo.value = {
+        name: selectedOption.name,
+        type: selectedOption.type
+      }
+    }
+    
+    const response = await fetch(`${API_BASE_URL}/api/user/model_preference`, {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json'
+      },
+      body: JSON.stringify({
+        user_id: "4",
+        merchant_id: "3",
+        model_type: selectedModelInfo.value.type,
+        model_name: selectedModelInfo.value.name,
+        action: "set"
+      })
+    })
+
+    if (!response.ok) {
+      throw new Error('Failed to update model preference')
+    }
+
+    const data = await response.json()
+    if (data.code === 2000) {
+      messageAnt.success('模型偏好设置已更新')
+    } else {
+      throw new Error(data.message || 'Failed to update model preference')
+    }
+  } catch (error) {
+    console.error('Error updating model preference:', error)
+    messageAnt.error('更新模型偏好设置失败')
+  }
+}
+
+// 处理焦点事件
+const handleFocus = () => {
+  console.log('Select focused')
+}
+
+// 修改消息处理部分
+const handleSubmit = async () => {
+  const content = inputContent.value.trim()
+  if (!content && !items.value.length) return
+
+  try {
+    loading.value = true
+    const userMessageId = `user-${Date.now()}`
+    
+    // 保存当前消息状态
+    const currentMessages = [...messages.value]
+    
+    // 添加用户消息
+    const newMessages = [...currentMessages, {
+      id: userMessageId,
+      role: 'local',
+      message: content,
+      status: 'success'
+    }]
+    
+    // 更新消息数组
+    setMessages(newMessages)
+
+    // 清理输入
+    await nextTick(() => {
+      inputContent.value = ''
+      items.value = []
+      imageUrls.value = []
+      documentUrls.value = []
+    })
+
+    // API 请求
+    const response = await fetch(`${API_BASE_URL}/api/chat/online/multimodal`, {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json'
+      },
+      body: JSON.stringify({
+        message: content,
+        chat_config_id: "17",
+        user_id: 4,
+        session_id: activeConversation.value,
+        source: "pc",
+        image_urls: imageUrls.value,
+        documents: documentUrls.value,
+        merchant_id: "3",
+        model_type: selectedModelInfo.value.type,
+        model_name: selectedModelInfo.value.name
+      })
+    })
+
+    if (!response.ok) {
+      throw new Error(`API request failed: ${response.status}`)
+    }
+
+    const result = await response.json()
+    if (result.code !== 2000) {
+      throw new Error(`API returned error code: ${result.code}`)
+    }
+    
+    activeConversation.value = result.session_id
+    if (result.choices?.[0]?.message?.content) {
+      const aiMessageId = `ai-${Date.now()}`
+      const fullMessage = result.choices[0].message.content
+
+      // 使用最新的消息数组
+      const latestMessages = [...messages.value]
+      const updatedMessages = [...latestMessages, {
+        id: aiMessageId,
+        role: 'ai',
+        message: '',
+        status: 'loading'
+      }]
+      setMessages(updatedMessages)
+
+      // 逐字显示
+      let currentText = ''
+      const chars = fullMessage.split('')
+
+      for (let i = 0; i < chars.length; i++) {
+        await new Promise(resolve => setTimeout(resolve, 50))
+        currentText += chars[i]
+        
+        const progressMessages = messages.value.map(msg =>
+          msg.id === aiMessageId
+            ? { ...msg, message: currentText }
+            : msg
+        )
+        setMessages(progressMessages)
+      }
+
+      // 确保最终状态使用最新的消息数组
+      const finalMessages = messages.value.map(msg =>
+        msg.id === aiMessageId
+          ? { ...msg, message: fullMessage, status: 'success' }
+          : msg
+      )
+      setMessages(finalMessages)
+    }
+
+  } catch (error) {
+    console.error('Error sending message:', error)
+    messageAnt.error('发送失败,请重试!')
+  } finally {
+    loading.value = false
+  }
+}
+
+// 添加文件上传函数
+const uploadFile = async (file: File) => {
+  const formData = new FormData()
+  formData.append('file', file)
+
+  try {
+    const response = await fetch('http://your-api/upload/file', {
+      method: 'POST',
+      body: formData
+    })
+
+    if (!response.ok) {
+      throw new Error('Upload failed')
+    }
+
+    const result = await response.json()
+
+    // 根据文件类型分类存储URL
+    const fileUrl = result.data.fileUrl
+    if (file.type.startsWith('image/')) {
+      imageUrls.value.push(fileUrl)
+    } else {
+      documentUrls.value.push(fileUrl)
+    }
+
+    return fileUrl
+  } catch (error) {
+    console.error('Upload error:', error)
+    throw error
+  }
+}
+
+// 修改会话切换处理函数
+const handleConversationChange = (key: string) => {
+  if (key) {
+    activeConversation.value = key
+    // 只在必要时清空消息
+    if (!messages.value.length) {
+      setMessages([])
+    }
+  }
+}
+
+// 方法定义
+const onPromptsItemClick = async (info: any) => {
+  if (info?.data?.description) {
+    // 设置输入内容为选中的提示词
+    inputContent.value = info.data.description
+    // 调用 handleSubmit 发送请求
+    await handleSubmit()
+  }
+}
+
+// 添加文件处理函数
+const handleFileChange = (info: any) => {
+  const { fileList } = info
+  attachedFiles.value = fileList.map((file: any) => ({
+    ...file,
+    status: file.status,
+    url: file.response?.url || file.url
+  }))
+
+  // 根据文件类型分类存储URL
+  fileList.forEach((file: any) => {
+    const fileUrl = file.response?.url || file.url
+    if (fileUrl) {
+      if (file.type?.startsWith('image/')) {
+        if (!imageUrls.value.includes(fileUrl)) {
+          imageUrls.value.push(fileUrl)
+        }
+      } else {
+        if (!documentUrls.value.includes(fileUrl)) {
+          documentUrls.value.push(fileUrl)
+        }
+      }
+    }
+  })
+}
+
+// 计算属性
+const sidebarStyle = computed(() => ({
+  width: '255px',
+  background: token.value.colorBgContainer,
+  borderRadius: token.value.borderRadius,
+}))
+
+// 修改 attachmentsNode 计算属性
+const attachmentsNode = computed(() =>
+  h(Badge,
+    { dot: attachedFiles.value.length > 0 && !headerOpen.value },
+    {
+      default: () => h(Button, {
+        type: 'text',
+        icon: '',//markRaw(PaperClipOutlined),
+        onClick: () => headerOpen.value = !headerOpen.value
+      })
+    }
+  )
+)
+
+
+// 添加欢迎页面的计算属性
+const welcomeTitle = computed(() => ({
+  content: 'Hello, I\'m Ant Design X',
+  style: {
+    fontSize: '24px',
+    fontWeight: 'bold',
+    marginBottom: '8px'
+  }
+}))
+
+const welcomeDescription = ref('Base on Ant Design, AGI product interface solution, create a better intelligent vision~')
+
+const [message, contextHolder] = messageAnt.useMessage();
+
+// 在组件挂载后再进行相关操作
+onMounted(() => {
+  // 如果需要在挂载后执行一些初始化逻辑
+  nextTick(() => {
+    // 可以在这里进行一些初始化
+  })
+})
+
+// 处理函数
+const openChange = (value: boolean) => {
+  nextTick(() => {  // 使用 nextTick 确保状态更新后再触发渲染
+    openValue.value = value
+  })
+}
+
+const triggerOpen = () => {
+  nextTick(() => {  // 使用 nextTick 确保状态更新后再触发渲染
+    openValue.value = false
+  })
+  console.log(openValue.value)
+}
+
+const senderSubmit = () => {
+  message.success('Send message successfully!');
+}
+
+const selectFileClick = () => {
+  message.info('Mock select file');
+}
+
+// 确保所有响应式数据都有初始值
+const promptsStyles = ref({})
+const open = ref(false);
+const items = ref([]);
+const text = ref('');
+
+const senderRef = ref<InstanceType<typeof Sender>>(null);
+
+const selectRef = ref()
+
+const senderHeader = computed(() =>
+  h(Sender.Header, {
+    title: "Attachments",
+    styles: {
+      content: {
+        padding: 0,
+      },
+    },
+    open: open.value,
+    onOpenChange: (v: boolean) => open.value = v,
+    forceRender: true
+  }, {
+    default: () => h(Attachments, {
+      action: `${API_BASE_URL}/chatbot/upload/file`,
+      name: 'file',
+      items: attachedFiles.value,
+      onChange: handleFileChange,
+      customRequest: ({ file, onSuccess, onError }) => {
+        // 确保文件对象存在
+        const fileObj = file.originFileObj || file
+        if (fileObj) {
+          uploadFile(fileObj)
+            .then(fileUrl => {
+              console.log('Upload successful:', fileUrl)
+              onSuccess({ url: fileUrl }, new XMLHttpRequest())
+            })
+            .catch(err => {
+              console.error('Upload failed:', err)
+              onError(err)
+              messageAnt.error('文件上传失败,请重试!')
+            })
+        }
+      },
+      placeholder: (type: string) => type === 'drop'
+        ? { title: 'Drop file here' }
+        : {
+          icon: h(CloudUploadOutlined),
+          title: 'Upload files',
+          description: 'Click or drag files to this area to upload',
+        },
+      getDropContainer: () => senderRef.value?.nativeElement
+    })
+  })
+)
+
+const badgeNode = computed(() =>
+  h(Badge, { dot: items.value.length > 0 && !open.value }, {
+    default: () => h(Button, {
+      onClick: () => open.value = !open.value,
+      icon: h(LinkOutlined)
+    })
+  })
+);
+
+// 处理输入变化
+const handleInputChange = (value: string) => {
+  inputContent.value = value
+}
+
+// 添加清理文件的函数
+const clearFiles = () => {
+  attachedFiles.value = []
+  imageUrls.value = []
+  documentUrls.value = []
+}
+
+// 在 script setup 中添加滚动逻辑
+const scrollToBottom = () => {
+  nextTick(() => {
+    const container = document.querySelector('.messages-container')
+    if (container) {
+      container.scrollTop = container.scrollHeight
+    }
+  })
+}
+
+// 监听消息变化,自动滚动到底部
+watch(messages, () => {
+  scrollToBottom()
+}, { deep: true })
+
+</script>
+
+<style scoped>
+.chat-container {
+  display: flex;
+  height: calc(100vh - 200px);
+  min-width: 1000px;
+  background: var(--ant-color-bg-container);
+  font-family: AlibabaPuHuiTi, -apple-system, sans-serif;
+}
+
+.sidebar {
+  width: 280px;
+  background: var(--ant-color-bg-layout-80);
+  display: flex;
+  flex-direction: column;
+  border-right: 1px solid rgba(0, 0, 0, 0.06);
+}
+
+.logo {
+  display: flex;
+  height: 72px;
+  align-items: center;
+  padding: 0 24px;
+}
+
+.logo-img {
+  width: 24px;
+  height: 24px;
+}
+
+.logo-text {
+  margin-left: 8px;
+  font-weight: bold;
+  font-size: 16px;
+}
+
+.new-chat-btn {
+  margin: 0 12px 24px;
+  background: #1677ff0f;
+  border: 1px solid #1677ff34;
+}
+
+.chat-content {
+  flex: 1;
+  max-width: 700px;
+  margin: 0 auto;
+  padding: 24px;
+  display: flex;
+  flex-direction: column;
+  height:calc(100vh - 50px);
+  overflow: hidden; /* 防止出现双滚动条 */
+}
+
+.messages-container {
+  flex: 1;
+  overflow-y: auto;
+  padding: 24px 0;
+  display: flex;
+  flex-direction: column;
+  height: calc(100vh - 200px); /* 调整高度,减去其他元素的高度 */
+  scroll-behavior: smooth; /* 添加平滑滚动效果 */
+}
+
+.messages-list {
+  flex: 1;
+  overflow-y: auto;
+  margin-bottom: auto; /* 确保内容从顶部开始 */
+}
+
+.input-section {
+  position: sticky;
+  bottom: 0;
+  background: var(--ant-color-bg-container);
+  padding: 16px 0;
+  margin-top: auto;
+  z-index: 1;
+}
+
+.welcome-container {
+  padding-top: 32px;
+  display: flex;
+  flex-direction: column;
+  gap: 16px;
+}
+
+/* 添加 Markdown 样式 */
+.markdown-content {
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+}
+
+.markdown-content h1,
+.markdown-content h2,
+.markdown-content h3,
+.markdown-content h4 {
+  margin-top: 1em;
+  margin-bottom: 0.5em;
+  font-weight: 600;
+}
+
+.markdown-content code {
+  background-color: rgba(0, 0, 0, 0.05);
+  padding: 0.2em 0.4em;
+  border-radius: 3px;
+}
+
+.markdown-content pre {
+  background-color: rgba(0, 0, 0, 0.05);
+  padding: 1em;
+  border-radius: 4px;
+  overflow-x: auto;
+}
+
+::v-deep .markdown-content p {
+  margin: 0;
+}
+
+/* 添加模型选择器样式 */
+.model-selector {
+  margin-bottom: 8px;
+}
+</style>

+ 6 - 0
tsconfig.json

@@ -0,0 +1,6 @@
+{
+  "compilerOptions": {
+    "jsx": "preserve",
+    "jsxImportSource": "vue"
+  }
+} 

+ 6 - 2
vite.config.js

@@ -3,11 +3,12 @@ import vue from '@vitejs/plugin-vue'
 import vueJsx from '@vitejs/plugin-vue-jsx'
 import path from 'path'
 import { fileURLToPath } from 'url'
-
+import components from 'unplugin-vue-components/vite';
+import { AntDesignXVueResolver } from 'ant-design-x-vue/resolver';
 const __dirname = path.dirname(fileURLToPath(import.meta.url))
 
 function resolve(dir) {
-    return path.join(__dirname, dir)
+    return path.join(__dirname, dir)  
 }
 
 export default defineConfig(({ command, mode }) => {
@@ -16,6 +17,9 @@ export default defineConfig(({ command, mode }) => {
   
   return {
     plugins: [
+      components({
+        resolvers: [AntDesignXVueResolver()],
+      }),
       vue(),
       vueJsx()
     ],

+ 269 - 28
yarn.lock

@@ -17,20 +17,19 @@
   dependencies:
     "@ctrl/tinycolor" "^3.4.0"
 
+"@ant-design/fast-color@^2.0.6":
+  version "2.0.6"
+  resolved "https://registry.npmmirror.com/@ant-design/fast-color/-/fast-color-2.0.6.tgz"
+  integrity sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==
+  dependencies:
+    "@babel/runtime" "^7.24.7"
+
 "@ant-design/icons-svg@^4.2.1":
   version "4.4.2"
   resolved "https://registry.npmmirror.com/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz"
   integrity sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==
 
-"@ant-design/icons-vue@^6.1.0":
-  version "6.1.0"
-  resolved "https://registry.npmmirror.com/@ant-design/icons-vue/-/icons-vue-6.1.0.tgz"
-  integrity sha512-EX6bYm56V+ZrKN7+3MT/ubDkvJ5rK/O2t380WFRflDcVFgsvl3NLH7Wxeau6R8DbrO5jWR6DSTC3B6gYFp77AA==
-  dependencies:
-    "@ant-design/colors" "^6.0.0"
-    "@ant-design/icons-svg" "^4.2.1"
-
-"@ant-design/icons-vue@^7.0.1":
+"@ant-design/icons-vue@^7.0.0", "@ant-design/icons-vue@^7.0.1":
   version "7.0.1"
   resolved "https://registry.npmmirror.com/@ant-design/icons-vue/-/icons-vue-7.0.1.tgz"
   integrity sha512-eCqY2unfZK6Fe02AwFlDHLfoyEFreP6rBwAZMIJ1LugmfMiVgwWDYlp1YsRugaPtICYOabV1iWxXdP12u9U43Q==
@@ -192,7 +191,7 @@
     "@babel/template" "^7.25.9"
     "@babel/types" "^7.26.0"
 
-"@babel/parser@^7.25.3", "@babel/parser@^7.25.6", "@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.3":
+"@babel/parser@^7.15.8", "@babel/parser@^7.25.3", "@babel/parser@^7.25.6", "@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.3":
   version "7.26.3"
   resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.26.3.tgz"
   integrity sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==
@@ -224,7 +223,7 @@
     "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9"
     "@babel/plugin-syntax-typescript" "^7.25.9"
 
-"@babel/runtime@^7.10.5", "@babel/runtime@^7.12.5", "@babel/runtime@^7.23.2":
+"@babel/runtime@^7.10.5", "@babel/runtime@^7.12.5", "@babel/runtime@^7.23.2", "@babel/runtime@^7.24.7":
   version "7.26.0"
   resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.26.0.tgz"
   integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==
@@ -266,11 +265,16 @@
   resolved "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz"
   integrity sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==
 
-"@emotion/hash@^0.9.0":
+"@emotion/hash@^0.9.0", "@emotion/hash@^0.9.2":
   version "0.9.2"
   resolved "https://registry.npmmirror.com/@emotion/hash/-/hash-0.9.2.tgz"
   integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==
 
+"@emotion/unitless@^0.10.0":
+  version "0.10.0"
+  resolved "https://registry.npmmirror.com/@emotion/unitless/-/unitless-0.10.0.tgz"
+  integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==
+
 "@emotion/unitless@^0.8.0":
   version "0.8.1"
   resolved "https://registry.npmmirror.com/@emotion/unitless/-/unitless-0.8.1.tgz"
@@ -386,6 +390,27 @@
   resolved "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-5.2.1.tgz"
   integrity sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==
 
+"@volar/language-core@~2.4.11", "@volar/language-core@2.4.12":
+  version "2.4.12"
+  resolved "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.12.tgz"
+  integrity sha512-RLrFdXEaQBWfSnYGVxvR2WrO6Bub0unkdHYIdC31HzIEqATIuuhRRzYu76iGPZ6OtA4Au1SnW0ZwIqPP217YhA==
+  dependencies:
+    "@volar/source-map" "2.4.12"
+
+"@volar/source-map@2.4.12":
+  version "2.4.12"
+  resolved "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.12.tgz"
+  integrity sha512-bUFIKvn2U0AWojOaqf63ER0N/iHIBYZPpNGogfLPQ68F5Eet6FnLlyho7BS0y2HJ1jFhSif7AcuTx1TqsCzRzw==
+
+"@volar/typescript@~2.4.11":
+  version "2.4.12"
+  resolved "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.12.tgz"
+  integrity sha512-HJB73OTJDgPc80K30wxi3if4fSsZZAOScbj2fcicMuOPoOkcf9NNAINb33o+DzhBdF9xTKC1gnPmIRDous5S0g==
+  dependencies:
+    "@volar/language-core" "2.4.12"
+    path-browserify "^1.0.1"
+    vscode-uri "^3.0.8"
+
 "@vue/babel-helper-vue-transform-on@1.2.5":
   version "1.2.5"
   resolved "https://registry.npmmirror.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.2.5.tgz"
@@ -429,7 +454,7 @@
     estree-walker "^2.0.2"
     source-map-js "^1.2.0"
 
-"@vue/compiler-dom@3.5.13":
+"@vue/compiler-dom@^3.5.0", "@vue/compiler-dom@3.5.13":
   version "3.5.13"
   resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz"
   integrity sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==
@@ -460,11 +485,33 @@
     "@vue/compiler-dom" "3.5.13"
     "@vue/shared" "3.5.13"
 
+"@vue/compiler-vue2@^2.7.16":
+  version "2.7.16"
+  resolved "https://registry.npmmirror.com/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz"
+  integrity sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==
+  dependencies:
+    de-indent "^1.0.2"
+    he "^1.2.0"
+
 "@vue/devtools-api@^6.0.0-beta.11", "@vue/devtools-api@^6.6.4":
   version "6.6.4"
   resolved "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz"
   integrity sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==
 
+"@vue/language-core@2.2.8":
+  version "2.2.8"
+  resolved "https://registry.npmmirror.com/@vue/language-core/-/language-core-2.2.8.tgz"
+  integrity sha512-rrzB0wPGBvcwaSNRriVWdNAbHQWSf0NlGqgKHK5mEkXpefjUlVRP62u03KvwZpvKVjRnBIQ/Lwre+Mx9N6juUQ==
+  dependencies:
+    "@volar/language-core" "~2.4.11"
+    "@vue/compiler-dom" "^3.5.0"
+    "@vue/compiler-vue2" "^2.7.16"
+    "@vue/shared" "^3.5.0"
+    alien-signals "^1.0.3"
+    minimatch "^9.0.3"
+    muggle-string "^0.4.1"
+    path-browserify "^1.0.1"
+
 "@vue/reactivity@3.5.13":
   version "3.5.13"
   resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.13.tgz"
@@ -498,7 +545,7 @@
     "@vue/compiler-ssr" "3.5.13"
     "@vue/shared" "3.5.13"
 
-"@vue/shared@3.5.13":
+"@vue/shared@^3.5.0", "@vue/shared@3.5.13":
   version "3.5.13"
   resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.13.tgz"
   integrity sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==
@@ -784,10 +831,10 @@ acorn@^6.4.1:
   resolved "https://registry.npmmirror.com/acorn/-/acorn-6.4.2.tgz"
   integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==
 
-acorn@^8.14.0, acorn@^8.8.2:
-  version "8.14.0"
-  resolved "https://registry.npmmirror.com/acorn/-/acorn-8.14.0.tgz"
-  integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==
+acorn@^8.14.0, acorn@^8.14.1, acorn@^8.8.2:
+  version "8.14.1"
+  resolved "https://registry.npmmirror.com/acorn/-/acorn-8.14.1.tgz"
+  integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==
 
 ajv-errors@^1.0.0:
   version "1.0.1"
@@ -843,13 +890,18 @@ ajv@^8.8.2, ajv@^8.9.0:
     json-schema-traverse "^1.0.0"
     require-from-string "^2.0.2"
 
-ant-design-vue@^4.0.0-rc.6:
-  version "4.0.0-rc.6"
-  resolved "https://registry.npmmirror.com/ant-design-vue/-/ant-design-vue-4.0.0-rc.6.tgz"
-  integrity sha512-j+GAhgC1p1+nmQVbaEeY2miZ1h+8jBLlxTESX93MwcshVaYTkZNhiyddtl92VvEDJTedzuX+1oT3TP5wG/+tHg==
+alien-signals@^1.0.3:
+  version "1.0.13"
+  resolved "https://registry.npmmirror.com/alien-signals/-/alien-signals-1.0.13.tgz"
+  integrity sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==
+
+ant-design-vue@^4.2.6, ant-design-vue@>=4.0.0:
+  version "4.2.6"
+  resolved "https://registry.npmmirror.com/ant-design-vue/-/ant-design-vue-4.2.6.tgz"
+  integrity sha512-t7eX13Yj3i9+i5g9lqFyYneoIb3OzTvQjq9Tts1i+eiOd3Eva/6GagxBSXM1fOCjqemIu0FYVE1ByZ/38epR3Q==
   dependencies:
     "@ant-design/colors" "^6.0.0"
-    "@ant-design/icons-vue" "^6.1.0"
+    "@ant-design/icons-vue" "^7.0.0"
     "@babel/runtime" "^7.10.5"
     "@ctrl/tinycolor" "^3.5.0"
     "@emotion/hash" "^0.9.0"
@@ -871,6 +923,18 @@ ant-design-vue@^4.0.0-rc.6:
     vue-types "^3.0.0"
     warning "^4.0.0"
 
+ant-design-x-vue@^1.0.7:
+  version "1.0.7"
+  resolved "https://registry.npmmirror.com/ant-design-x-vue/-/ant-design-x-vue-1.0.7.tgz"
+  integrity sha512-odxMDJ2L+da+yWig/hTQbOD/ciGmsz6oN+WfnaH90FJs1fNEnpUIlvjIxwyUQDZuMX1VCcv8HkMEeRqJpnVADA==
+  dependencies:
+    "@ant-design/fast-color" "^2.0.6"
+    "@emotion/hash" "^0.9.2"
+    "@emotion/unitless" "^0.10.0"
+    classnames "^2.5.1"
+    csstype "^3.1.3"
+    stylis "^4.3.4"
+
 anymatch@^2.0.0:
   version "2.0.0"
   resolved "https://registry.npmmirror.com/anymatch/-/anymatch-2.0.0.tgz"
@@ -1061,6 +1125,13 @@ brace-expansion@^1.1.7:
     balanced-match "^1.0.0"
     concat-map "0.0.1"
 
+brace-expansion@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz"
+  integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
+  dependencies:
+    balanced-match "^1.0.0"
+
 braces@^2.3.1, braces@^2.3.2:
   version "2.3.2"
   resolved "https://registry.npmmirror.com/braces/-/braces-2.3.2.tgz"
@@ -1291,7 +1362,7 @@ chokidar@^2.1.8:
   optionalDependencies:
     fsevents "^1.2.7"
 
-chokidar@^3.4.1:
+chokidar@^3.4.1, chokidar@^3.6.0:
   version "3.6.0"
   resolved "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz"
   integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
@@ -1334,6 +1405,11 @@ class-utils@^0.3.5:
     isobject "^3.0.0"
     static-extend "^0.1.1"
 
+classnames@^2.5.1:
+  version "2.5.1"
+  resolved "https://registry.npmmirror.com/classnames/-/classnames-2.5.1.tgz"
+  integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==
+
 collection-visit@^1.0.0:
   version "1.0.0"
   resolved "https://registry.npmmirror.com/collection-visit/-/collection-visit-1.0.0.tgz"
@@ -1384,6 +1460,16 @@ concat-stream@^1.5.0:
     readable-stream "^2.2.2"
     typedarray "^0.0.6"
 
+confbox@^0.1.8:
+  version "0.1.8"
+  resolved "https://registry.npmmirror.com/confbox/-/confbox-0.1.8.tgz"
+  integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==
+
+confbox@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.npmmirror.com/confbox/-/confbox-0.2.1.tgz"
+  integrity sha512-hkT3yDPFbs95mNCy1+7qNKC6Pro+/ibzYxtM2iqEigpf0sVw+bg4Zh9/snjsBcf990vfIsg5+1U7VyiyBb3etg==
+
 console-browserify@^1.1.0:
   version "1.2.0"
   resolved "https://registry.npmmirror.com/console-browserify/-/console-browserify-1.2.0.tgz"
@@ -1504,6 +1590,11 @@ dayjs@^1.10.5, dayjs@^1.11.13:
   resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz"
   integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==
 
+de-indent@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.npmmirror.com/de-indent/-/de-indent-1.0.2.tgz"
+  integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==
+
 debug@^2.2.0:
   version "2.6.9"
   resolved "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz"
@@ -1518,7 +1609,7 @@ debug@^2.3.3:
   dependencies:
     ms "2.0.0"
 
-debug@^4.1.0, debug@^4.3.1:
+debug@^4.1.0, debug@^4.3.1, debug@^4.4.0:
   version "4.4.0"
   resolved "https://registry.npmmirror.com/debug/-/debug-4.4.0.tgz"
   integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
@@ -1829,6 +1920,11 @@ expand-brackets@^2.1.4:
     snapdragon "^0.8.1"
     to-regex "^3.0.1"
 
+exsolve@^1.0.1:
+  version "1.0.4"
+  resolved "https://registry.npmmirror.com/exsolve/-/exsolve-1.0.4.tgz"
+  integrity sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==
+
 extend-shallow@^2.0.1:
   version "2.0.1"
   resolved "https://registry.npmmirror.com/extend-shallow/-/extend-shallow-2.0.1.tgz"
@@ -1873,6 +1969,11 @@ fast-uri@^3.0.1:
   resolved "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.0.3.tgz"
   integrity sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==
 
+fdir@^6.4.3:
+  version "6.4.3"
+  resolved "https://registry.npmmirror.com/fdir/-/fdir-6.4.3.tgz"
+  integrity sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==
+
 fflate@^0.8.1:
   version "0.8.2"
   resolved "https://registry.npmmirror.com/fflate/-/fflate-0.8.2.tgz"
@@ -2135,6 +2236,11 @@ hasown@^2.0.0, hasown@^2.0.2:
   dependencies:
     function-bind "^1.1.2"
 
+he@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.npmmirror.com/he/-/he-1.2.0.tgz"
+  integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+
 hmac-drbg@^1.0.1:
   version "1.0.1"
   resolved "https://registry.npmmirror.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz"
@@ -2547,6 +2653,15 @@ loader-utils@^2.0.0:
     emojis-list "^3.0.0"
     json5 "^2.1.2"
 
+local-pkg@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.npmmirror.com/local-pkg/-/local-pkg-1.1.1.tgz"
+  integrity sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==
+  dependencies:
+    mlly "^1.7.4"
+    pkg-types "^2.0.1"
+    quansync "^0.2.8"
+
 locate-path@^3.0.0:
   version "3.0.0"
   resolved "https://registry.npmmirror.com/locate-path/-/locate-path-3.0.0.tgz"
@@ -2579,7 +2694,7 @@ lru-cache@^5.1.1:
   dependencies:
     yallist "^3.0.2"
 
-magic-string@^0.30.11:
+magic-string@^0.30.11, magic-string@^0.30.17:
   version "0.30.17"
   resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.17.tgz"
   integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==
@@ -2719,6 +2834,13 @@ minimatch@^3.1.1:
   dependencies:
     brace-expansion "^1.1.7"
 
+minimatch@^9.0.3:
+  version "9.0.5"
+  resolved "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz"
+  integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==
+  dependencies:
+    brace-expansion "^2.0.1"
+
 minimist@^1.2.0, minimist@^1.2.6:
   version "1.2.8"
   resolved "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz"
@@ -2755,6 +2877,16 @@ mkdirp@^0.5.1, mkdirp@^0.5.3:
   dependencies:
     minimist "^1.2.6"
 
+mlly@^1.7.4:
+  version "1.7.4"
+  resolved "https://registry.npmmirror.com/mlly/-/mlly-1.7.4.tgz"
+  integrity sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==
+  dependencies:
+    acorn "^8.14.0"
+    pathe "^2.0.1"
+    pkg-types "^1.3.0"
+    ufo "^1.5.4"
+
 move-concurrently@^1.0.1:
   version "1.0.1"
   resolved "https://registry.npmmirror.com/move-concurrently/-/move-concurrently-1.0.1.tgz"
@@ -2777,6 +2909,11 @@ ms@2.0.0:
   resolved "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz"
   integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
 
+muggle-string@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.4.1.tgz"
+  integrity sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==
+
 nanoid@^3.3.7:
   version "3.3.8"
   resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.8.tgz"
@@ -2980,6 +3117,11 @@ pascalcase@^0.1.1:
   resolved "https://registry.npmmirror.com/pascalcase/-/pascalcase-0.1.1.tgz"
   integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==
 
+path-browserify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz"
+  integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==
+
 path-browserify@0.0.1:
   version "0.0.1"
   resolved "https://registry.npmmirror.com/path-browserify/-/path-browserify-0.0.1.tgz"
@@ -3000,6 +3142,11 @@ path-is-absolute@^1.0.0:
   resolved "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
   integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
 
+pathe@^2.0.1, pathe@^2.0.2, pathe@^2.0.3:
+  version "2.0.3"
+  resolved "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz"
+  integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==
+
 pbkdf2@^3.1.2:
   version "3.1.2"
   resolved "https://registry.npmmirror.com/pbkdf2/-/pbkdf2-3.1.2.tgz"
@@ -3031,6 +3178,11 @@ picomatch@^2.0.4, picomatch@^2.2.1:
   resolved "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz"
   integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
 
+"picomatch@^3 || ^4", picomatch@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz"
+  integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==
+
 pify@^4.0.1:
   version "4.0.1"
   resolved "https://registry.npmmirror.com/pify/-/pify-4.0.1.tgz"
@@ -3043,6 +3195,24 @@ pkg-dir@^3.0.0:
   dependencies:
     find-up "^3.0.0"
 
+pkg-types@^1.3.0:
+  version "1.3.1"
+  resolved "https://registry.npmmirror.com/pkg-types/-/pkg-types-1.3.1.tgz"
+  integrity sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==
+  dependencies:
+    confbox "^0.1.8"
+    mlly "^1.7.4"
+    pathe "^2.0.1"
+
+pkg-types@^2.0.1:
+  version "2.1.0"
+  resolved "https://registry.npmmirror.com/pkg-types/-/pkg-types-2.1.0.tgz"
+  integrity sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==
+  dependencies:
+    confbox "^0.2.1"
+    exsolve "^1.0.1"
+    pathe "^2.0.3"
+
 posix-character-classes@^0.1.0:
   version "0.1.1"
   resolved "https://registry.npmmirror.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz"
@@ -3146,6 +3316,11 @@ qs@^6.12.3:
   dependencies:
     side-channel "^1.0.6"
 
+quansync@^0.2.8:
+  version "0.2.10"
+  resolved "https://registry.npmmirror.com/quansync/-/quansync-0.2.10.tgz"
+  integrity sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==
+
 querystring-es3@^0.2.0:
   version "0.2.1"
   resolved "https://registry.npmmirror.com/querystring-es3/-/querystring-es3-0.2.1.tgz"
@@ -3665,7 +3840,7 @@ style-resources-loader@^1.5.0:
     schema-utils "^2.7.0"
     tslib "^2.3.1"
 
-stylis@^4.1.3:
+stylis@^4.1.3, stylis@^4.3.4:
   version "4.3.4"
   resolved "https://registry.npmmirror.com/stylis/-/stylis-4.3.4.tgz"
   integrity sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==
@@ -3769,6 +3944,14 @@ timers-browserify@^2.0.4:
   dependencies:
     setimmediate "^1.0.4"
 
+tinyglobby@^0.2.12:
+  version "0.2.12"
+  resolved "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.12.tgz"
+  integrity sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==
+  dependencies:
+    fdir "^6.4.3"
+    picomatch "^4.0.2"
+
 to-arraybuffer@^1.0.0:
   version "1.0.1"
   resolved "https://registry.npmmirror.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz"
@@ -3821,11 +4004,21 @@ typedarray@^0.0.6:
   resolved "https://registry.npmmirror.com/typedarray/-/typedarray-0.0.6.tgz"
   integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
 
+typescript@*, typescript@>=5.0.0, typescript@~5.5.4:
+  version "5.5.4"
+  resolved "https://registry.npmmirror.com/typescript/-/typescript-5.5.4.tgz"
+  integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==
+
 uc.micro@^2.0.0, uc.micro@^2.1.0:
   version "2.1.0"
   resolved "https://registry.npmmirror.com/uc.micro/-/uc.micro-2.1.0.tgz"
   integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==
 
+ufo@^1.5.4:
+  version "1.5.4"
+  resolved "https://registry.npmmirror.com/ufo/-/ufo-1.5.4.tgz"
+  integrity sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==
+
 undici-types@~6.20.0:
   version "6.20.0"
   resolved "https://registry.npmmirror.com/undici-types/-/undici-types-6.20.0.tgz"
@@ -3855,6 +4048,36 @@ unique-slug@^2.0.0:
   dependencies:
     imurmurhash "^0.1.4"
 
+unplugin-utils@^0.2.4:
+  version "0.2.4"
+  resolved "https://registry.npmmirror.com/unplugin-utils/-/unplugin-utils-0.2.4.tgz"
+  integrity sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==
+  dependencies:
+    pathe "^2.0.2"
+    picomatch "^4.0.2"
+
+unplugin-vue-components@^28.4.1:
+  version "28.4.1"
+  resolved "https://registry.npmmirror.com/unplugin-vue-components/-/unplugin-vue-components-28.4.1.tgz"
+  integrity sha512-niGSc0vJD9ueAnsqcfAldmtpkppZ09B6p2G1dL7X5S8KPdgbk1P+txPwaaDCe7N+eZh2VG1aAypLXkuJs3OSUg==
+  dependencies:
+    chokidar "^3.6.0"
+    debug "^4.4.0"
+    local-pkg "^1.0.0"
+    magic-string "^0.30.17"
+    mlly "^1.7.4"
+    tinyglobby "^0.2.12"
+    unplugin "^2.2.0"
+    unplugin-utils "^0.2.4"
+
+unplugin@^2.2.0:
+  version "2.2.2"
+  resolved "https://registry.npmmirror.com/unplugin/-/unplugin-2.2.2.tgz"
+  integrity sha512-Qp+iiD+qCRnUek+nDoYvtWX7tfnYyXsrOnJ452FRTgOyKmTM7TUJ3l+PLPJOOWPTUyKISKp4isC5JJPSXUjGgw==
+  dependencies:
+    acorn "^8.14.1"
+    webpack-virtual-modules "^0.6.2"
+
 unset-value@^1.0.0:
   version "1.0.0"
   resolved "https://registry.npmmirror.com/unset-value/-/unset-value-1.0.0.tgz"
@@ -3943,6 +4166,11 @@ vm-browserify@^1.0.1:
   resolved "https://registry.npmmirror.com/vm-browserify/-/vm-browserify-1.1.2.tgz"
   integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
 
+vscode-uri@^3.0.8:
+  version "3.1.0"
+  resolved "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz"
+  integrity sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==
+
 vue-cli-plugin-style-resources-loader@^0.1.5:
   version "0.1.5"
   resolved "https://registry.npmmirror.com/vue-cli-plugin-style-resources-loader/-/vue-cli-plugin-style-resources-loader-0.1.5.tgz"
@@ -3972,6 +4200,14 @@ vue-router@^4.5.0:
   dependencies:
     "@vue/devtools-api" "^6.6.4"
 
+vue-tsc@^2.1.6:
+  version "2.2.8"
+  resolved "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-2.2.8.tgz"
+  integrity sha512-jBYKBNFADTN+L+MdesNX/TB3XuDSyaWynKMDgR+yCSln0GQ9Tfb7JS2lr46s2LiFUT1WsmfWsSvIElyxzOPqcQ==
+  dependencies:
+    "@volar/typescript" "~2.4.11"
+    "@vue/language-core" "2.2.8"
+
 vue-types@^3.0.0:
   version "3.0.2"
   resolved "https://registry.npmmirror.com/vue-types/-/vue-types-3.0.2.tgz"
@@ -3979,7 +4215,7 @@ vue-types@^3.0.0:
   dependencies:
     is-plain-object "3.0.1"
 
-vue@^3.0.0, vue@^3.0.2, vue@^3.2.0, vue@^3.2.25, vue@^3.5.13, vue@>=3.0.3, vue@>=3.2.0, vue@3.5.13:
+vue@^3.0.0, vue@^3.0.2, vue@^3.2.0, vue@^3.2.25, vue@^3.5.13, vue@>=3.0.3, vue@>=3.2.0, vue@>=3.3.0, "vue@2 || 3", vue@3.5.13:
   version "3.5.13"
   resolved "https://registry.npmmirror.com/vue/-/vue-3.5.13.tgz"
   integrity sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==
@@ -4043,6 +4279,11 @@ webpack-sources@^3.2.3:
   resolved "https://registry.npmmirror.com/webpack-sources/-/webpack-sources-3.2.3.tgz"
   integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
 
+webpack-virtual-modules@^0.6.2:
+  version "0.6.2"
+  resolved "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz"
+  integrity sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==
+
 "webpack@^3.0.0 || ^4.0.0 || ^5.0.0", "webpack@^4.0.0 || ^5.0.0", webpack@^5.0.0, webpack@^5.1.0:
   version "5.97.1"
   resolved "https://registry.npmmirror.com/webpack/-/webpack-5.97.1.tgz"