Explorar o código

修改样式功能

yangg hai 5 meses
pai
achega
e92ec21396
Modificáronse 5 ficheiros con 843 adicións e 1062 borrados
  1. 342 9
      package-lock.json
  2. 2 2
      src/api/report.js
  3. 28 114
      src/components/SearchResults/index.vue
  4. 397 100
      src/views/report.vue
  5. 74 837
      yarn.lock

+ 342 - 9
package-lock.json

@@ -12,6 +12,9 @@
         "ant-design-vue": "^4.0.0-rc.6",
         "axios": "^1.7.9",
         "dayjs": "^1.11.13",
+        "docx": "^9.1.0",
+        "file-saver": "^2.0.5",
+        "html2pdf.js": "^0.10.2",
         "less": "^4.2.1",
         "less-loader": "^12.2.0",
         "markdown-it": "^14.1.0",
@@ -1231,12 +1234,16 @@
       "version": "22.10.2",
       "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.10.2.tgz",
       "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==",
-      "devOptional": true,
-      "peer": true,
       "dependencies": {
         "undici-types": "~6.20.0"
       }
     },
+    "node_modules/@types/raf": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmmirror.com/@types/raf/-/raf-3.4.3.tgz",
+      "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
+      "optional": true
+    },
     "node_modules/@vitejs/plugin-vue": {
       "version": "5.2.1",
       "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-5.2.1.tgz",
@@ -1738,6 +1745,17 @@
       "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
       "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
     },
+    "node_modules/atob": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmmirror.com/atob/-/atob-2.1.2.tgz",
+      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+      "bin": {
+        "atob": "bin/atob.js"
+      },
+      "engines": {
+        "node": ">= 4.5.0"
+      }
+    },
     "node_modules/axios": {
       "version": "1.7.9",
       "resolved": "https://registry.npmmirror.com/axios/-/axios-1.7.9.tgz",
@@ -1763,6 +1781,14 @@
       "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
       "dev": true
     },
+    "node_modules/base64-arraybuffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
+      "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
+      "engines": {
+        "node": ">= 0.6.0"
+      }
+    },
     "node_modules/big.js": {
       "version": "5.2.2",
       "resolved": "https://registry.npmmirror.com/big.js/-/big.js-5.2.2.tgz",
@@ -1814,6 +1840,17 @@
         "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
       }
     },
+    "node_modules/btoa": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmmirror.com/btoa/-/btoa-1.2.1.tgz",
+      "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
+      "bin": {
+        "btoa": "bin/btoa.js"
+      },
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
     "node_modules/buffer-from": {
       "version": "1.1.2",
       "resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz",
@@ -1841,6 +1878,31 @@
         }
       ]
     },
+    "node_modules/canvg": {
+      "version": "3.0.10",
+      "resolved": "https://registry.npmmirror.com/canvg/-/canvg-3.0.10.tgz",
+      "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==",
+      "optional": true,
+      "dependencies": {
+        "@babel/runtime": "^7.12.5",
+        "@types/raf": "^3.4.0",
+        "core-js": "^3.8.3",
+        "raf": "^3.4.1",
+        "regenerator-runtime": "^0.13.7",
+        "rgbcolor": "^1.0.1",
+        "stackblur-canvas": "^2.0.0",
+        "svg-pathdata": "^6.0.3"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/canvg/node_modules/regenerator-runtime": {
+      "version": "0.13.11",
+      "resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+      "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
+      "optional": true
+    },
     "node_modules/chrome-trace-event": {
       "version": "1.0.4",
       "resolved": "https://registry.npmmirror.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
@@ -1907,6 +1969,19 @@
         "url": "https://opencollective.com/core-js"
       }
     },
+    "node_modules/core-util-is": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz",
+      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
+    },
+    "node_modules/css-line-break": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmmirror.com/css-line-break/-/css-line-break-2.1.0.tgz",
+      "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
+      "dependencies": {
+        "utrie": "^1.0.2"
+      }
+    },
     "node_modules/csstype": {
       "version": "3.1.3",
       "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz",
@@ -1942,6 +2017,39 @@
         "node": ">=0.4.0"
       }
     },
+    "node_modules/docx": {
+      "version": "9.1.0",
+      "resolved": "https://registry.npmmirror.com/docx/-/docx-9.1.0.tgz",
+      "integrity": "sha512-XOtseSTRrkKN/sV5jNBqyLazyhNpWfaUhpuKc22cs+5DavNjRQvchnohb0g0S+x/96/D06U/i0/U/Gc4E5kwuQ==",
+      "dependencies": {
+        "@types/node": "^22.7.5",
+        "hash.js": "^1.1.7",
+        "jszip": "^3.10.1",
+        "nanoid": "^5.0.4",
+        "xml": "^1.0.1",
+        "xml-js": "^1.6.8"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/docx/node_modules/nanoid": {
+      "version": "5.0.9",
+      "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-5.0.9.tgz",
+      "integrity": "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "bin": {
+        "nanoid": "bin/nanoid.js"
+      },
+      "engines": {
+        "node": "^18 || >=20"
+      }
+    },
     "node_modules/dom-align": {
       "version": "1.12.4",
       "resolved": "https://registry.npmmirror.com/dom-align/-/dom-align-1.12.4.tgz",
@@ -1952,6 +2060,12 @@
       "resolved": "https://registry.npmmirror.com/dom-scroll-into-view/-/dom-scroll-into-view-2.0.1.tgz",
       "integrity": "sha512-bvVTQe1lfaUr1oFzZX80ce9KLDlZ3iU+XGNE/bz9HnGdklTieqsbmsLHe+rT2XWqopvL0PckkYqN7ksmm5pe3w=="
     },
+    "node_modules/dompurify": {
+      "version": "2.5.8",
+      "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-2.5.8.tgz",
+      "integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==",
+      "optional": true
+    },
     "node_modules/electron-to-chromium": {
       "version": "1.5.76",
       "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.76.tgz",
@@ -2011,6 +2125,11 @@
       "devOptional": true,
       "peer": true
     },
+    "node_modules/es6-promise": {
+      "version": "4.2.8",
+      "resolved": "https://registry.npmmirror.com/es6-promise/-/es6-promise-4.2.8.tgz",
+      "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
+    },
     "node_modules/esbuild": {
       "version": "0.24.2",
       "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.24.2.tgz",
@@ -2141,6 +2260,16 @@
       "devOptional": true,
       "peer": true
     },
+    "node_modules/fflate": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.8.2.tgz",
+      "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="
+    },
+    "node_modules/file-saver": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmmirror.com/file-saver/-/file-saver-2.0.5.tgz",
+      "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
+    },
     "node_modules/follow-redirects": {
       "version": "1.15.9",
       "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz",
@@ -2255,6 +2384,15 @@
         "node": ">=8"
       }
     },
+    "node_modules/hash.js": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmmirror.com/hash.js/-/hash.js-1.1.7.tgz",
+      "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "minimalistic-assert": "^1.0.1"
+      }
+    },
     "node_modules/html-tags": {
       "version": "3.3.1",
       "resolved": "https://registry.npmmirror.com/html-tags/-/html-tags-3.3.1.tgz",
@@ -2267,6 +2405,28 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/html2canvas": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz",
+      "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
+      "dependencies": {
+        "css-line-break": "^2.1.0",
+        "text-segmentation": "^1.0.3"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/html2pdf.js": {
+      "version": "0.10.2",
+      "resolved": "https://registry.npmmirror.com/html2pdf.js/-/html2pdf.js-0.10.2.tgz",
+      "integrity": "sha512-WyHVeMb18Bp7vYTmBv1GVsThH//K7SRfHdSdhHPkl4JvyQarNQXnailkYn0QUbRRmnN5rdbbmSIGEsPZtzPy2Q==",
+      "dependencies": {
+        "es6-promise": "^4.2.5",
+        "html2canvas": "^1.0.0",
+        "jspdf": "^2.3.1"
+      }
+    },
     "node_modules/iconv-lite": {
       "version": "0.6.3",
       "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz",
@@ -2291,6 +2451,11 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/immediate": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmmirror.com/immediate/-/immediate-3.0.6.tgz",
+      "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
+    },
     "node_modules/inflight": {
       "version": "1.0.6",
       "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz",
@@ -2305,8 +2470,7 @@
     "node_modules/inherits": {
       "version": "2.0.4",
       "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
-      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-      "dev": true
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
     },
     "node_modules/is-plain-object": {
       "version": "3.0.1",
@@ -2321,6 +2485,11 @@
       "resolved": "https://registry.npmmirror.com/is-what/-/is-what-3.14.1.tgz",
       "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA=="
     },
+    "node_modules/isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
+    },
     "node_modules/jest-worker": {
       "version": "27.5.1",
       "resolved": "https://registry.npmmirror.com/jest-worker/-/jest-worker-27.5.1.tgz",
@@ -2378,6 +2547,34 @@
         "node": ">=6"
       }
     },
+    "node_modules/jspdf": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmmirror.com/jspdf/-/jspdf-2.5.2.tgz",
+      "integrity": "sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==",
+      "dependencies": {
+        "@babel/runtime": "^7.23.2",
+        "atob": "^2.1.2",
+        "btoa": "^1.2.1",
+        "fflate": "^0.8.1"
+      },
+      "optionalDependencies": {
+        "canvg": "^3.0.6",
+        "core-js": "^3.6.0",
+        "dompurify": "^2.5.4",
+        "html2canvas": "^1.0.0-rc.5"
+      }
+    },
+    "node_modules/jszip": {
+      "version": "3.10.1",
+      "resolved": "https://registry.npmmirror.com/jszip/-/jszip-3.10.1.tgz",
+      "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
+      "dependencies": {
+        "lie": "~3.3.0",
+        "pako": "~1.0.2",
+        "readable-stream": "~2.3.6",
+        "setimmediate": "^1.0.5"
+      }
+    },
     "node_modules/less": {
       "version": "4.2.1",
       "resolved": "https://registry.npmmirror.com/less/-/less-4.2.1.tgz",
@@ -2428,6 +2625,14 @@
         }
       }
     },
+    "node_modules/lie": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmmirror.com/lie/-/lie-3.3.0.tgz",
+      "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+      "dependencies": {
+        "immediate": "~3.0.5"
+      }
+    },
     "node_modules/linkify-it": {
       "version": "5.0.0",
       "resolved": "https://registry.npmmirror.com/linkify-it/-/linkify-it-5.0.0.tgz",
@@ -2570,6 +2775,11 @@
         "node": ">= 0.6"
       }
     },
+    "node_modules/minimalistic-assert": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+      "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
+    },
     "node_modules/minimatch": {
       "version": "3.1.2",
       "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz",
@@ -2648,6 +2858,11 @@
         "wrappy": "1"
       }
     },
+    "node_modules/pako": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz",
+      "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
+    },
     "node_modules/parse-node-version": {
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/parse-node-version/-/parse-node-version-1.0.1.tgz",
@@ -2665,6 +2880,12 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/performance-now": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz",
+      "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
+      "optional": true
+    },
     "node_modules/picocolors": {
       "version": "1.1.1",
       "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
@@ -2706,6 +2927,11 @@
         "node": "^10 || ^12 || >=14"
       }
     },
+    "node_modules/process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+    },
     "node_modules/proxy-from-env": {
       "version": "1.1.0",
       "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@@ -2734,6 +2960,15 @@
         "node": ">=6"
       }
     },
+    "node_modules/raf": {
+      "version": "3.4.1",
+      "resolved": "https://registry.npmmirror.com/raf/-/raf-3.4.1.tgz",
+      "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
+      "optional": true,
+      "dependencies": {
+        "performance-now": "^2.1.0"
+      }
+    },
     "node_modules/randombytes": {
       "version": "2.1.0",
       "resolved": "https://registry.npmmirror.com/randombytes/-/randombytes-2.1.0.tgz",
@@ -2744,6 +2979,25 @@
         "safe-buffer": "^5.1.0"
       }
     },
+    "node_modules/readable-stream": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz",
+      "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+      "dependencies": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      }
+    },
+    "node_modules/readable-stream/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+    },
     "node_modules/regenerator-runtime": {
       "version": "0.14.1",
       "resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
@@ -2764,6 +3018,15 @@
       "resolved": "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
       "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
     },
+    "node_modules/rgbcolor": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/rgbcolor/-/rgbcolor-1.0.1.tgz",
+      "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
+      "optional": true,
+      "engines": {
+        "node": ">= 0.8.15"
+      }
+    },
     "node_modules/rollup": {
       "version": "4.29.1",
       "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.29.1.tgz",
@@ -2832,8 +3095,7 @@
     "node_modules/sax": {
       "version": "1.4.1",
       "resolved": "https://registry.npmmirror.com/sax/-/sax-1.4.1.tgz",
-      "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
-      "optional": true
+      "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="
     },
     "node_modules/schema-utils": {
       "version": "2.7.1",
@@ -2880,6 +3142,11 @@
         "randombytes": "^2.1.0"
       }
     },
+    "node_modules/setimmediate": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.5.tgz",
+      "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
+    },
     "node_modules/shallow-equal": {
       "version": "1.2.1",
       "resolved": "https://registry.npmmirror.com/shallow-equal/-/shallow-equal-1.2.1.tgz",
@@ -2913,6 +3180,28 @@
         "source-map": "^0.6.0"
       }
     },
+    "node_modules/stackblur-canvas": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmmirror.com/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
+      "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
+      "optional": true,
+      "engines": {
+        "node": ">=0.1.14"
+      }
+    },
+    "node_modules/string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dependencies": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "node_modules/string_decoder/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+    },
     "node_modules/style-resources-loader": {
       "version": "1.5.0",
       "resolved": "https://registry.npmmirror.com/style-resources-loader/-/style-resources-loader-1.5.0.tgz",
@@ -2952,6 +3241,15 @@
         "url": "https://github.com/chalk/supports-color?sponsor=1"
       }
     },
+    "node_modules/svg-pathdata": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmmirror.com/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
+      "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
+      "optional": true,
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
     "node_modules/svg-tags": {
       "version": "1.0.0",
       "resolved": "https://registry.npmmirror.com/svg-tags/-/svg-tags-1.0.0.tgz",
@@ -3079,6 +3377,14 @@
         "url": "https://opencollective.com/webpack"
       }
     },
+    "node_modules/text-segmentation": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz",
+      "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
+      "dependencies": {
+        "utrie": "^1.0.2"
+      }
+    },
     "node_modules/throttle-debounce": {
       "version": "5.0.2",
       "resolved": "https://registry.npmmirror.com/throttle-debounce/-/throttle-debounce-5.0.2.tgz",
@@ -3100,9 +3406,7 @@
     "node_modules/undici-types": {
       "version": "6.20.0",
       "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.20.0.tgz",
-      "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
-      "devOptional": true,
-      "peer": true
+      "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="
     },
     "node_modules/update-browserslist-db": {
       "version": "1.1.1",
@@ -3143,6 +3447,19 @@
         "punycode": "^2.1.0"
       }
     },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+    },
+    "node_modules/utrie": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/utrie/-/utrie-1.0.2.tgz",
+      "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
+      "dependencies": {
+        "base64-arraybuffer": "^1.0.2"
+      }
+    },
     "node_modules/vite": {
       "version": "6.0.6",
       "resolved": "https://registry.npmmirror.com/vite/-/vite-6.0.6.tgz",
@@ -3383,6 +3700,22 @@
       "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
       "dev": true
     },
+    "node_modules/xml": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/xml/-/xml-1.0.1.tgz",
+      "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw=="
+    },
+    "node_modules/xml-js": {
+      "version": "1.6.11",
+      "resolved": "https://registry.npmmirror.com/xml-js/-/xml-js-1.6.11.tgz",
+      "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==",
+      "dependencies": {
+        "sax": "^1.2.4"
+      },
+      "bin": {
+        "xml-js": "bin/cli.js"
+      }
+    },
     "node_modules/yallist": {
       "version": "3.1.1",
       "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz",

+ 2 - 2
src/api/report.js

@@ -1,7 +1,7 @@
 import { axios } from '@/utils/request'
 
 export function getList (d) {
-    // return axios({
+    /* // return axios({
     //     url: `/report`,
     //     method: 'post',
     //     data: d
@@ -30,7 +30,7 @@ export function getList (d) {
             size: 20,
             total: 8
         })
-    });
+    }); */
 }
 
 

+ 28 - 114
src/components/SearchResults/index.vue

@@ -12,9 +12,9 @@
       <div v-if="displayResults.length > 0" class="results-list">
         <div v-for="(item, index) in displayResults" :key="index" class="result-item">
           <h3 class="result-title">
-            <a :href="item.url" target="_blank" rel="noopener noreferrer">{{ item.title }}</a>
+            <a :href="item.link"  target="_blank" rel="noopener noreferrer">{{ item.title }}</a>
           </h3>
-          <p class="result-url">{{ item.url }}</p>
+          <p class="result-url">{{ item.link }}</p>
           <p class="result-snippet">{{ item.snippet }}</p>
           <div class="result-meta">
             <span class="result-date">{{ formatDate(item.date) }}</span>
@@ -39,7 +39,7 @@
 </template>
 
 <script>
-import { defineComponent, ref, onMounted, onUnmounted } from 'vue';
+import { defineComponent, ref, watch } from 'vue';
 import { FileSearchOutlined } from '@ant-design/icons-vue';
 import dayjs from 'dayjs';
 
@@ -48,114 +48,29 @@ export default defineComponent({
   components: {
     FileSearchOutlined
   },
-  setup() {
-    const allResults = ref([
-      {
-        title: 'Ant Design - The world\'s second most popular React UI framework',
-        url: 'https://ant.design',
-        snippet: 'Ant Design is a comprehensive design system for enterprise-level products. Create efficient and enjoyable work experiences with high-quality components and best practices.',
-        date: '2024-03-20',
-        source: 'Official Documentation'
-      },
-      {
-        title: 'Getting Started with Ant Design Vue',
-        url: 'https://antdv.com/docs/vue/introduce',
-        snippet: 'Ant Design Vue is an enterprise-class UI components based on Ant Design and Vue 3. Provides high-quality Vue components out of the box with excellent development experience.',
-        date: '2024-03-19',
-        source: 'Ant Design Vue'
-      },
-      {
-        title: 'Ant Design System Principles and Guidelines',
-        url: 'https://ant.design/docs/spec/introduce',
-        snippet: 'Learn about the design principles behind Ant Design. Discover how to create consistent and beautiful user interfaces following our comprehensive guidelines.',
-        date: '2024-03-18',
-        source: 'Design Guidelines'
-      },
-      {
-        title: 'Understanding Component Architecture in Ant Design',
-        url: 'https://medium.com/antdesign/component-architecture',
-        snippet: 'Deep dive into how Ant Design components are structured and how they work together to create a cohesive design system. Learn best practices for component implementation.',
-        date: '2024-03-17',
-        source: 'Medium Article'
-      },
-      {
-        title: 'Customizing Ant Design Themes',
-        url: 'https://ant.design/docs/react/customize-theme',
-        snippet: 'Learn how to customize Ant Design themes to match your brand identity. Complete guide to variable customization, component styling, and creating consistent design tokens.',
-        date: '2024-03-16',
-        source: 'Technical Guide'
-      }
-    ]);
-    
+  props: {
+    searchResults: {
+      type: Array,
+      default: () => []
+    },
+    loading: {
+      type: Boolean,
+      default: false
+    },
+    total: {
+      type: Number,
+      default: 0
+    }
+  },
+  setup(props) {
     const displayResults = ref([]);
-    const loading = ref(false);
-    const currentPage = ref(1);
-    const pageSize = ref(10);
-    const total = ref(28);
-    const hasMore = ref(true);
-    const loadingTrigger = ref(null);
-    const resultsContainer = ref(null);
-
-    // 模拟获取更多结果
-    const fetchMoreResults = async () => {
-      if (loading.value || !hasMore.value) return;
-      
-      loading.value = true;
-      try {
-        // 模拟API延迟
-        await new Promise(resolve => setTimeout(resolve, 800));
-        
-        const startIndex = (currentPage.value - 1) * pageSize.value;
-        const endIndex = startIndex + pageSize.value;
-        const newResults = allResults.value.slice(startIndex, endIndex);
-        
-        // 添加新结果到显示列表
-        displayResults.value = [...displayResults.value, ...newResults];
-        
-        // 更新页码和是否还有更多
-        currentPage.value += 1;
-        hasMore.value = displayResults.value.length < total.value;
-      } catch (error) {
-        console.error('Failed to fetch more results:', error);
-      } finally {
-        loading.value = false;
-      }
-    };
+    const hasMore = ref(false);
 
-    // 使用 Intersection Observer 监听滚动
-    let observer = null;
-    
-    const setupIntersectionObserver = () => {
-      observer = new IntersectionObserver(
-        (entries) => {
-          const target = entries[0];
-          if (target.isIntersecting && !loading.value) {
-            fetchMoreResults();
-          }
-        },
-        {
-          root: resultsContainer.value,
-          threshold: 0.1
-        }
-      );
-
-      if (loadingTrigger.value) {
-        observer.observe(loadingTrigger.value);
-      }
-    };
-
-    onMounted(() => {
-      // 初始加载第一页
-      fetchMoreResults();
-      // 设置观察者
-      setupIntersectionObserver();
-    });
-
-    onUnmounted(() => {
-      if (observer) {
-        observer.disconnect();
-      }
-    });
+    // 监听 searchResults 变化
+    watch(() => props.searchResults, (newResults) => {
+      displayResults.value = newResults;
+      hasMore.value = displayResults.value.length < props.total;
+    }, { immediate: true });
 
     // 格式化日期
     const formatDate = (date) => {
@@ -164,12 +79,10 @@ export default defineComponent({
 
     return {
       displayResults,
-      loading,
-      total,
+      loading: props.loading,
+      total: props.total,
       hasMore,
-      formatDate,
-      loadingTrigger,
-      resultsContainer
+      formatDate
     };
   }
 });
@@ -218,6 +131,7 @@ export default defineComponent({
       }
 
       .result-title {
+      cursor: pointer;
         margin: 0 0 8px;
         font-size: 16px;
         

+ 397 - 100
src/views/report.vue

@@ -1,6 +1,19 @@
 <template>
   <div class="layout">
-    <div class="menu">
+    <div class="menu" :class="{ collapsed: isMenuCollapsed }">
+      <!-- 添加收缩按钮 -->
+      <div 
+        class="collapse-left-button" 
+        :class="{ 'menu-collapsed': isMenuCollapsed }"
+        @click="toggleMenu"
+      >
+        <img 
+          :src="isMenuCollapsed ? rightIcon : leftIcon" 
+          alt="toggle" 
+          class="collapse-icon"
+        />
+      </div>
+
       <!-- Logo -->
       <div class="logo">
         <img
@@ -44,14 +57,38 @@
     <div class="chat">
       <!-- 欢迎消息 -->
       <div v-if="messages.length === 0" class="welcome-section">
-
         <!-- Do you want 部分 -->
         <div class="suggestion-section">
           <h3>嗨,我是你的智能助手</h3>
 
           <div class="cards-container">
-            <!-- Hot Topics 卡片 -->
             <div class="suggestion-card">
+              <div class="card-header">
+                <img
+                  src="../assets/svg/hot-for-ux.svg"
+                  alt="hot topics"
+                  class="tab-icon"
+                />
+                <h4>推荐问题</h4>
+              </div>
+              <p class="card-subtitle">为您精选的热门问题</p>
+              <div class="suggestion-items">
+                <!-- Combine both QA pairs and guides -->
+                <div
+                  v-for="(item, index) in [
+                    ...currentQaPairs,
+                    ...currentDesignGuides,
+                  ]"
+                  :key="index"
+                  class="suggestion-item"
+                  @click="handleQaClick(item)"
+                >
+                  {{ item.question }}
+                </div>
+              </div>
+            </div>
+            <!-- Hot Topics 卡片 --><!-- Design Guide 卡片 -->
+            <!--  <div class="suggestion-card">
               <div class="card-header">
                 <img
                   src="../assets/svg/hot-for-ux.svg"
@@ -62,9 +99,9 @@
               </div>
               <p class="card-subtitle">我们可以这样向知识库提问</p>
               <div class="suggestion-items">
-                <div 
-                  v-for="(qa, index) in currentQaPairs" 
-                  :key="index" 
+                <div
+                  v-for="(qa, index) in currentQaPairs"
+                  :key="index"
                   class="suggestion-item"
                   @click="handleQaClick(qa)"
                 >
@@ -73,7 +110,7 @@
               </div>
             </div>
 
-            <!-- Design Guide 卡片 -->
+            
             <div class="suggestion-card">
               <div class="card-header">
                 <img
@@ -85,16 +122,16 @@
               </div>
               <p class="card-subtitle">搜索网上的热门回答</p>
               <div class="suggestion-items">
-                <div 
-                  v-for="(guide, index) in currentDesignGuides" 
-                  :key="index" 
+                <div
+                  v-for="(guide, index) in currentDesignGuides"
+                  :key="index"
                   class="suggestion-item"
                   @click="handleQaClick(guide)"
                 >
                   {{ guide.question }}
                 </div>
               </div>
-            </div>
+            </div> -->
           </div>
         </div>
       </div>
@@ -142,7 +179,9 @@
                     <div class="file-info-display">
                       <img :src="getFileIcon(file)" class="file-type-icon" />
                       <div class="file-details">
-                        <span class="file-name" :title="file.name">{{ file.name }}</span>
+                        <span class="file-name" :title="file.name">{{
+                          file.name
+                        }}</span>
                         <span class="file-size">{{ file.size }}</span>
                       </div>
                     </div>
@@ -176,12 +215,6 @@
                   <img v-else :src="playIcon" alt="播放" class="audio-icon" />
                 </button>
               </div>
-
-
-
-
-
-
             </div>
           </div>
         </div>
@@ -207,6 +240,26 @@
             />
             <span>Design Guide</span>
           </div>
+          <!-- 添加互联网搜索开关 -->
+          <div class="web-search-toggle">
+            <input
+              type="checkbox"
+              id="webSearchToggle"
+              v-model="enableWebSearch"
+              :disabled="attachedFiles.length > 0"
+              class="toggle-input"
+            />
+            <label
+              for="webSearchToggle"
+              class="toggle-label"
+              :class="{ disabled: attachedFiles.length > 0 }"
+            >
+              启用互联网搜索
+              <!--  <span v-if="attachedFiles.length > 0" class="disabled-hint">
+                (文件上传时不可用)
+              </span> -->
+            </label>
+          </div>
         </div>
         <!-- 添加附件面板 -->
         <div v-if="showAttachments" class="attachments-panel">
@@ -289,10 +342,14 @@
                       v-else
                       :src="getFileIcon(file)"
                       alt="file"
-                      :class="isImageFile(file) || isVideoFile(file) ? 'file-icon' : ''"
+                      :class="
+                        isImageFile(file) || isVideoFile(file)
+                          ? 'file-icon'
+                          : ''
+                      "
                     />
-                    <button 
-                      class="remove-btn" 
+                    <button
+                      class="remove-btn"
                       @click.stop="removeFile(file)"
                       v-if="!file.isUploading"
                     >
@@ -367,7 +424,11 @@
         />
       </div>
       <div class="right-menu-content">
-        <SearchResults />
+        <SearchResults
+          :searchResults="searchResults"
+          :loading="isSearchLoading"
+          :total="searchTotal"
+        />
       </div>
     </div>
   </div>
@@ -406,11 +467,11 @@ import playIcon from "../assets/svg/play.svg";
 import axios from "axios";
 import { useStore } from "vuex";
 import MarkdownIt from "markdown-it";
-import ModelConfig from '../components/ModelConfig/index.vue';
-import SearchResults from '../components/SearchResults/index.vue';
-import VoiceConfig from '../components/VoiceConfig/index.vue';
-import KnowledgeConfig from '../components/KnowledgeConfig/index.vue';
-import ExportButton from '../components/ExportButton/index.vue';
+import ModelConfig from "../components/ModelConfig/index.vue";
+import SearchResults from "../components/SearchResults/index.vue";
+import VoiceConfig from "../components/VoiceConfig/index.vue";
+import KnowledgeConfig from "../components/KnowledgeConfig/index.vue";
+import ExportButton from "../components/ExportButton/index.vue";
 
 // 初始化 markdown-it
 const md = new MarkdownIt({
@@ -463,20 +524,38 @@ const currentQaPairs = ref([]);
 const currentDesignGuides = ref([]);
 let rotationInterval = null;
 
+// 添加新的响应式状态
+const searchResults = ref([]);
+const isSearchLoading = ref(false);
+const searchTotal = ref(0);
+
+// 添加互联网搜索开关状态
+const enableWebSearch = ref(false);
+
+// 添加新的响应式变量
+const isMenuCollapsed = ref(false);
+
+// 添加切换菜单方法
+const toggleMenu = () => {
+  isMenuCollapsed.value = !isMenuCollapsed.value;
+};
+
 // 修改获取文档摘要的方法
 const fetchDocumentSummary = async () => {
   isLoadingSummary.value = true;
   try {
-    const response = await axios.get(`${import.meta.env.VITE_BASE_AI_API}/api/document/summary`);
-    console.log('API Response:', response.data);
-    
+    const response = await axios.get(
+      `${import.meta.env.VITE_BASE_AI_API}/api/document/summary`
+    );
+    console.log("API Response:", response.data);
+
     if (response.data.code === 200) {
       documentSummary.value = response.data.data.items;
-      console.log('Document Summary:', documentSummary.value);
+      console.log("Document Summary:", documentSummary.value);
       startRotation();
     }
   } catch (error) {
-    console.error('获取文档摘要失败:', error);
+    console.error("获取文档摘要失败:", error);
   } finally {
     isLoadingSummary.value = false;
   }
@@ -490,50 +569,54 @@ const startRotation = () => {
 
   const updateItems = () => {
     if (!documentSummary.value?.length) {
-      console.log('No document summary data available');
+      console.log("No document summary data available");
       return;
     }
-    
+
     // 处理第一项数据(Hot Topics)
     try {
       const hotTopicsData = documentSummary.value[0];
       console.log(hotTopicsData);
       if (hotTopicsData?.questions) {
-        const parsedQaPairs = /* JSON.parse( */hotTopicsData.questions/* .replace(/'/g, '"')); */
-        const formattedQaPairs = parsedQaPairs.map(question => ({ question }));
+        const parsedQaPairs =
+          /* JSON.parse( */ hotTopicsData.questions; /* .replace(/'/g, '"')); */
+        const formattedQaPairs = parsedQaPairs.map((question) => ({
+          question,
+        }));
         // 随机选择3个问题
         const shuffled = [...formattedQaPairs].sort(() => 0.5 - Math.random());
         currentQaPairs.value = shuffled.slice(0, 3);
       }
     } catch (error) {
-      console.error('解析 Hot Topics 失败:', error);
+      console.error("解析 Hot Topics 失败:", error);
     }
 
     // 处理第二项数据(Design Guide)
     try {
       const designGuideData = documentSummary.value[1];
       if (designGuideData?.questions) {
-        const parsedGuides = /* JSON.parse( */designGuideData.questions/* .replace(/'/g, '"')); */
-        const formattedGuides = parsedGuides.map(question => ({ question }));
+        const parsedGuides =
+          /* JSON.parse( */ designGuideData.questions; /* .replace(/'/g, '"')); */
+        const formattedGuides = parsedGuides.map((question) => ({ question }));
         // 随机选择3个指南
         const shuffled = [...formattedGuides].sort(() => 0.5 - Math.random());
         currentDesignGuides.value = shuffled.slice(0, 3);
       }
     } catch (error) {
-      console.error('解析 Design Guide 失败:', error);
+      console.error("解析 Design Guide 失败:", error);
     }
   };
 
   // 初始更新
   updateItems();
-  
+
   // 每5秒更新一次
   rotationInterval = setInterval(updateItems, 5000);
 };
 
 // 处理QA点击事件
 const handleQaClick = (qa) => {
-  console.log('QA clicked:', qa); // 添加日志
+  console.log("QA clicked:", qa); // 添加日志
   if (qa?.question) {
     inputContent.value = qa.question;
     sendMessage();
@@ -596,9 +679,9 @@ const uploadFile = async (file) => {
 const handleFileUpload = async (event) => {
   const files = Array.from(event.target.files);
   if (files.length === 0) return;
-    // 添加文件大小检查
-    const MAX_VIDEO_SIZE = 10 * 1024 * 1024; // 10MB in bytes
-    const invalidFiles = files.filter(file => {
+  // 添加文件大小检查
+  const MAX_VIDEO_SIZE = 10 * 1024 * 1024; // 10MB in bytes
+  const invalidFiles = files.filter((file) => {
     if (isVideoFile(file) && file.size > MAX_VIDEO_SIZE) {
       return true;
     }
@@ -607,8 +690,8 @@ const handleFileUpload = async (event) => {
 
   if (invalidFiles.length > 0) {
     // 如果有超出大小限制的视频文件,显示错误提示
-    alert('Video files must not exceed 10MB');
-    event.target.value = ''; // 清空input
+    alert("Video files must not exceed 10MB");
+    event.target.value = ""; // 清空input
     return;
   }
   isUploading.value = true;
@@ -621,27 +704,31 @@ const handleFileUpload = async (event) => {
         size: file.size,
         sizeFormatted: formatFileSize(file.size),
         type: file.type,
-        isUploading: true
+        isUploading: true,
       };
-      
+
       // 先添加到文件列表中
       attachedFiles.value.push(fileWithStatus);
 
       try {
         const url = await uploadFile(file);
         // 直接修改数组中的对象
-        const index = attachedFiles.value.findIndex(f => f.name === file.name);
+        const index = attachedFiles.value.findIndex(
+          (f) => f.name === file.name
+        );
         if (index !== -1) {
           // 使用数组替换方式更新,确保响应式更新
           attachedFiles.value.splice(index, 1, {
             ...fileWithStatus,
             url,
-            isUploading: false
+            isUploading: false,
           });
         }
       } catch (error) {
         // 如果上传失败,从列表中移除该文件
-        attachedFiles.value = attachedFiles.value.filter(f => f.name !== file.name);
+        attachedFiles.value = attachedFiles.value.filter(
+          (f) => f.name !== file.name
+        );
         console.error("单个文件上传失败:", error);
       }
     }
@@ -651,6 +738,10 @@ const handleFileUpload = async (event) => {
     isUploading.value = false;
     event.target.value = ""; // 清空input以允许重复上传相同文件
   }
+
+  if (files.length > 0 && enableWebSearch.value) {
+    enableWebSearch.value = false; // 如果有文件上传,自动关闭互联网搜索
+  }
 };
 
 const formatFileSize = (bytes) => {
@@ -746,6 +837,12 @@ const sendMessage = async () => {
   messages.value.push(userMessage);
   scrollToBottom();
 
+  // 异步执行搜索,但不等待结果
+
+  sendMessageS(messageContent).catch((error) => {
+    console.error("Web search failed:", error);
+  });
+
   // 保存当前输入内容并清空输入框和附件
   const currentInput = inputContent.value;
   showAttachments.value = false;
@@ -765,19 +862,21 @@ const sendMessage = async () => {
   scrollToBottom();
 
   try {
-    const response = await axios.post(
-      `${import.meta.env.VITE_BASE_AI_API}/chatbot/multimodal`,
-      {
-        message: currentInput,
-        chat_config_id: "2",
-        user_id: "13365429324",
-        session_id: session_id.value,
-        source: "pc",
-        image_urls: imageUrls,
-        video_urls: videoUrls,
-        documents: documentUrls,
-      }
-    );
+    // 根据开关状态选择不同的 API 端点
+    const apiEndpoint = enableWebSearch.value
+      ? `${import.meta.env.VITE_BASE_AI_API}/api/chat/web-search-llm/`
+      : `${import.meta.env.VITE_BASE_AI_API}/chatbot/multimodal`;
+
+    const response = await axios.post(apiEndpoint, {
+      message: currentInput,
+      chat_config_id: "2",
+      user_id: "13365429324",
+      session_id: session_id.value,
+      source: "pc",
+      image_urls: imageUrls,
+      video_urls: videoUrls,
+      documents: documentUrls,
+    });
 
     // 更新 session_id
     if (response.data.data.session_id) {
@@ -795,7 +894,7 @@ const sendMessage = async () => {
       displayContent: "",
       audioData: response.data.data.audio_info?.audio || null, // 保存音频数据
     });
-
+    enableWebSearch.value=false
     messages.value.push(aiMessage);
     // 如果有音频数据,自动播放
     if (aiMessage.audioData) {
@@ -820,6 +919,34 @@ const sendMessage = async () => {
   }
 };
 
+// 修改 sendMessageS 方法
+const sendMessageS = async (query) => {
+  isSearchLoading.value = true;
+  try {
+    const response = await axios.post(
+      `${import.meta.env.VITE_BASE_AI_API}/api/web-search-results/`,
+      {
+        query: query,
+        num_results: 20,
+        page: 1,
+        page_size: 20,
+        engine: "bing",
+      }
+    );
+
+    if (response.data && response.data.code === 200) {
+      searchResults.value = response.data.data.results || [];
+      searchTotal.value = response.data.data.total_results || 0;
+    }
+  } catch (error) {
+    console.error("Web search failed:", error);
+    searchResults.value = [];
+    searchTotal.value = 0;
+  } finally {
+    isSearchLoading.value = false;
+  }
+};
+
 // 修改打字效果方法
 const typeMessage = async (message) => {
   if (!message || !message.content) {
@@ -881,12 +1008,12 @@ const toggleRightMenu = () => {
 
 const handleFileDrop = async (event) => {
   if (isUploading.value) return;
-  
+
   const files = Array.from(event.dataTransfer.files);
   if (files.length === 0) return;
-// 添加文件大小检查
-const MAX_VIDEO_SIZE = 10 * 1024 * 1024; // 10MB in bytes
-  const invalidFiles = files.filter(file => {
+  // 添加文件大小检查
+  const MAX_VIDEO_SIZE = 10 * 1024 * 1024; // 10MB in bytes
+  const invalidFiles = files.filter((file) => {
     if (isVideoFile(file) && file.size > MAX_VIDEO_SIZE) {
       return true;
     }
@@ -902,25 +1029,29 @@ const MAX_VIDEO_SIZE = 10 * 1024 * 1024; // 10MB in bytes
         size: file.size,
         sizeFormatted: formatFileSize(file.size),
         type: file.type,
-        isUploading: true
+        isUploading: true,
       };
-      
+
       attachedFiles.value.push(fileWithStatus);
 
       try {
         const url = await uploadFile(file);
         // 直接修改数组中的对象
-        const index = attachedFiles.value.findIndex(f => f.name === file.name);
+        const index = attachedFiles.value.findIndex(
+          (f) => f.name === file.name
+        );
         if (index !== -1) {
           // 使用数组替换方式更新,确保响应式更新
           attachedFiles.value.splice(index, 1, {
             ...fileWithStatus,
             url,
-            isUploading: false
+            isUploading: false,
           });
         }
       } catch (error) {
-        attachedFiles.value = attachedFiles.value.filter(f => f.name !== file.name);
+        attachedFiles.value = attachedFiles.value.filter(
+          (f) => f.name !== file.name
+        );
         console.error("单个文件上传失败:", error);
       }
     }
@@ -929,6 +1060,10 @@ const MAX_VIDEO_SIZE = 10 * 1024 * 1024; // 10MB in bytes
   } finally {
     isUploading.value = false;
   }
+
+  if (files.length > 0 && enableWebSearch.value) {
+    enableWebSearch.value = false; // 如果有文件上传,自动关闭互联网搜索
+  }
 };
 
 // 添加音频点击处理方法
@@ -998,6 +1133,7 @@ const renderMarkdown = (content) => {
   width: 100%;
   height: 100vh;
   overflow: hidden;
+  position: relative;
 }
 
 .menu {
@@ -1007,8 +1143,16 @@ const renderMarkdown = (content) => {
   display: flex;
   flex-direction: column;
   border-right: 1px solid rgba(0, 0, 0, 0.06);
-  position: relative;
-  z-index: 1;
+  position: absolute;
+  left: 0;
+  transform: translateX(0);
+  transition: transform 0.3s ease;
+  z-index: 2;
+}
+
+.menu.collapsed {
+  transform: translateX(-260px);
+  width: 260px;
 }
 
 .conversations {
@@ -1025,6 +1169,31 @@ const renderMarkdown = (content) => {
   gap: 24px;
   overflow-y: auto;
   overflow-x: hidden;
+  margin-left: 0;
+  margin-right: 0;
+  transition: margin 0.3s ease;
+  position: absolute;
+  left: 0;
+  right: 0;
+  top: 0;
+  bottom: 0;
+}
+
+.menu:not(.collapsed) + .chat {
+  left: 260px;
+}
+
+.chat {
+  right: 0;
+  transition: left 0.3s ease, right 0.3s ease;
+}
+
+.layout:has(.right_menu:not(.collapsed)) .chat {
+  right: 600px;
+}
+
+.right_menu:not(.collapsed) ~ .chat {
+  right: 600px;
 }
 
 .messages {
@@ -1104,7 +1273,6 @@ const renderMarkdown = (content) => {
   box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
 }
 
-/* 滚动条样式 */
 .conversation-list::-webkit-scrollbar {
   width: 4px;
 }
@@ -1176,7 +1344,6 @@ const renderMarkdown = (content) => {
   gap: 8px;
 }
 
-/* 标签栏样式 */
 .tabs-wrapper {
   display: flex;
   gap: 8px;
@@ -1251,10 +1418,6 @@ const renderMarkdown = (content) => {
 }
 
 .attachments-panel {
-  /* position: absolute;
-  bottom: calc(100% + 8px);
-  left: 0;
-  right: 0; */
   background: white;
   border-radius: 12px;
   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
@@ -1292,19 +1455,12 @@ const renderMarkdown = (content) => {
 
 .upload-area {
   padding: 24px;
-  /*  border: 2px dashed #d9d9d9; */
   border-radius: 8px;
   text-align: center;
   cursor: pointer;
   transition: all 0.3s;
-  /*   background: #fafafa; */
 }
 
-/* .upload-area:hover {
-  border-color: #1677ff;
-  background: #f0f7ff;
-} */
-
 .upload-area.has-files {
   padding: 12px;
   background: #fff;
@@ -1361,10 +1517,11 @@ const renderMarkdown = (content) => {
   object-fit: cover;
   border-radius: 4px;
 }
-/* 视频预览特定样式 */
+
 .file-wrapper video.file-icon {
-  background: #000; /* 视频加载前的背景色 */
+  background: #000;
 }
+
 .remove-btn {
   position: absolute;
   top: -8px;
@@ -1395,18 +1552,18 @@ const renderMarkdown = (content) => {
 
 .file-name {
   display: block;
-  max-width: 150px; /* 设置最大宽度 */
+  max-width: 150px;
   color: rgba(0, 0, 0, 0.88);
   font-size: 14px;
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
 }
+
 .file-info .file-name {
-  max-width: 150px; /* 可以根据实际布局调整宽度 */
+  max-width: 150px;
 }
 
-/* 如果需要在hover时显示完整文件名,可以添加 title 属性和 tooltip 效果 */
 .file-name:hover {
   cursor: pointer;
 }
@@ -1698,12 +1855,47 @@ const renderMarkdown = (content) => {
   height: 100%;
   background: #f7f7f8;
   border-left: 1px solid rgba(0, 0, 0, 0.06);
-  position: relative;
-  transition: width 0.3s ease;
+  position: absolute; /* 改为绝对定位 */
+  right: 0;
+  transform: translateX(0);
+  transition: transform 0.3s ease;
+  z-index: 2;
 }
 
 .right_menu.collapsed {
-  width: 0px;
+  transform: translateX(100%); /* 使用 transform 代替 width */
+  width: 600px; /* 保持固定宽度 */
+}
+
+/* 当右侧菜单展开时,给聊天区域添加右边距 */
+.right_menu:not(.collapsed) + .chat {
+  margin-right: 600px;
+}
+
+.collapse-left-button{
+  position: absolute;
+  left: 260px;
+  top: 50%;
+  transform: translateY(-50%);
+  width: 20px;
+  height: 40px;
+  background: #fff;
+  border: 1px solid rgba(0, 0, 0, 0.06);
+  border-right: none;
+  border-radius: 4px 0 0 4px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+  z-index: 2;
+  transition: left 0.3s ease;
+}
+
+.collapse-left-button.menu-collapsed {
+  left: 260px;
+ /*  border-right: 1px solid rgba(0, 0, 0, 0.06);
+  border-left: none;
+  border-radius: 0 4px 4px 0; */
 }
 
 .collapse-button {
@@ -2048,8 +2240,12 @@ const renderMarkdown = (content) => {
 }
 
 @keyframes spin {
-  0% { transform: rotate(0deg); }
-  100% { transform: rotate(360deg); }
+  0% {
+    transform: rotate(0deg);
+  }
+  100% {
+    transform: rotate(360deg);
+  }
 }
 
 /* 上传区域在上传时的样式 */
@@ -2067,6 +2263,107 @@ const renderMarkdown = (content) => {
   margin-top: auto;
   border-top: 1px solid rgba(0, 0, 0, 0.06);
 }
+
+.web-search-toggle {
+  display: flex;
+  align-items: center;
+  margin-left: auto;
+  padding: 0 12px;
+}
+
+.toggle-input {
+  position: relative;
+  width: 36px;
+  height: 20px;
+  margin-right: 8px;
+  appearance: none;
+  background: #ccc;
+  border-radius: 10px;
+  cursor: pointer;
+  transition: background 0.3s;
+}
+
+.toggle-input:checked {
+  background: #1677ff;
+}
+
+.toggle-input::before {
+  content: "";
+  position: absolute;
+  top: 2px;
+  left: 2px;
+  width: 16px;
+  height: 16px;
+  background: white;
+  border-radius: 50%;
+  transition: transform 0.3s;
+}
+
+.toggle-input:checked::before {
+  transform: translateX(16px);
+}
+
+.toggle-label {
+  font-size: 14px;
+  color: rgba(0, 0, 0, 0.88);
+  cursor: pointer;
+}
+
+.toggle-input:disabled {
+  opacity: 0.5;
+  cursor: not-allowed;
+}
+
+.toggle-label.disabled {
+  color: rgba(0, 0, 0, 0.45);
+  cursor: not-allowed;
+}
+
+.disabled-hint {
+  font-size: 12px;
+  color: rgba(0, 0, 0, 0.45);
+  margin-left: 4px;
+}
+
+/* 添加菜单收缩相关样式 */
+.menu {
+  /* 现有样式保持不变 */
+  transition: width 0.3s ease;
+  position: relative;
+}
+
+.menu.collapsed {
+  width: 0;
+  padding: 0;
+}
+
+/* 添加收缩按钮样式 */
+.collapse-button {
+  position: absolute;
+  right: -20px;
+  top: 50%;
+  transform: translateY(-50%);
+  width: 20px;
+  height: 40px;
+  background: #fff;
+  border: 1px solid rgba(0, 0, 0, 0.06);
+  border-left: none;
+  border-radius: 0 4px 4px 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+  z-index: 1;
+}
+
+.collapse-button:hover {
+  background: #f5f5f5;
+}
+
+.collapse-icon {
+  width: 12px;
+  height: 12px;
+}
 </style>
 <style lang="less" scoped>
 ::v-deep .message-content {

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 74 - 837
yarn.lock


Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio