Procházet zdrojové kódy

Merge branch 'master' of http://39.97.59.228:8013/hrx/mky-vent-base

lxh před 1 dnem
rodič
revize
8823c3601c
55 změnil soubory, kde provedl 2245 přidání a 1718 odebrání
  1. 7 9
      src/assets/images/ventAI/chatModalBlue/1-10.svg
  2. 7 9
      src/assets/images/ventAI/chatModalBlue/1-11.svg
  3. 5 8
      src/assets/images/ventAI/chatModalBlue/1-12.svg
  4. 2 8
      src/assets/images/ventAI/chatModalBlue/1-13.svg
  5. binární
      src/assets/images/ventAI/chatModalBlue/1-14.png
  6. 0 10
      src/assets/images/ventAI/chatModalBlue/1-14.svg
  7. binární
      src/assets/images/ventAI/chatModalBlue/1-15.png
  8. 0 10
      src/assets/images/ventAI/chatModalBlue/1-15.svg
  9. binární
      src/assets/images/ventAI/chatModalBlue/1-3.png
  10. binární
      src/assets/images/ventAI/chatModalBlue/1-4.png
  11. binární
      src/assets/images/ventAI/chatModalBlue/1-7.png
  12. 4 0
      src/assets/images/ventAI/chatModalBlue/1-7.svg
  13. 4 0
      src/assets/images/ventAI/chatModalBlue/1-8.svg
  14. 3 0
      src/assets/images/ventAI/chatModalBlue/1-9.svg
  15. 3 0
      src/assets/images/ventAI/chatModalBlue/2-1.svg
  16. 0 0
      src/assets/images/ventAI/chatModalBlue/2-2.svg
  17. 11 0
      src/assets/images/ventAI/chatModalBlue/2-3.svg
  18. 3 0
      src/assets/images/ventAI/chatModalBlue/2-4.svg
  19. 1 0
      src/assets/images/ventAI/chatModalBlue/2-5.svg
  20. binární
      src/assets/images/ventAI/chatModalBlue/2-6.png
  21. 3 0
      src/assets/images/ventAI/chatModalBlue/2-6.svg
  22. binární
      src/assets/images/ventAI/chatModalBlue/3-1.png
  23. binární
      src/assets/images/ventAI/chatModalBlue/3-2.png
  24. binární
      src/assets/images/ventAI/chatModalBlue/3-5.png
  25. binární
      src/assets/images/ventAI/chatModalBlue/3-6.png
  26. 2 6
      src/assets/images/ventAI/chatModalBlue/3-7.svg
  27. 1 0
      src/assets/images/ventAI/chatModalBlue/4-5.svg
  28. 1 0
      src/assets/images/ventAI/chatModalBlue/4-6.svg
  29. binární
      src/assets/images/ventAI/chatModalBlue/5-1.png
  30. 1 0
      src/assets/images/ventAI/dataPicker/AI-icon.svg
  31. 28 23
      src/design/themify/deepblue.less
  32. 24 20
      src/design/themify/default.less
  33. 13 8
      src/store/modules/modelFile.ts
  34. 22 2
      src/views/vent/deviceManager/comment/NormalTable.vue
  35. 4 1
      src/views/vent/deviceManager/deviceTable/device.api.ts
  36. 95 35
      src/views/vent/deviceManager/substationTabel/substation.data.ts
  37. 955 769
      src/views/vent/home/configurable/components/detail/ComplexList.vue
  38. 5 1
      src/views/vent/monitorManager/fanLocalMonitor/fanLocal.threejs.ts
  39. 5 1
      src/views/vent/monitorManager/fireDoorMonitor/fireDoor.threejs.ts
  40. 4 2
      src/views/vent/monitorManager/gateMonitor/gate.threejs.ts
  41. 5 1
      src/views/vent/monitorManager/mainFanMonitor/main.threejs.ts
  42. 5 1
      src/views/vent/monitorManager/windowMonitor/window.threejs.ts
  43. 5 1
      src/views/vent/monitorManager/windrectMonitor/windrect.threejs.ts
  44. 308 0
      src/views/vent/packageUpload/index.vue
  45. 15 0
      src/views/vent/packageUpload/package.api.ts
  46. 70 32
      src/views/ventAI/dataPicker/components/DataPickerModal.vue
  47. 10 8
      src/views/ventAI/dataPicker/useDataPicker.ts
  48. 285 83
      src/views/ventAI/manageAssistent/components/AiAssistantModal.vue
  49. 4 4
      src/views/ventAI/manageAssistent/components/chatModal/ChatInputArea.vue
  50. 239 173
      src/views/ventAI/manageAssistent/components/chatModal/ChatMessages.vue
  51. 2 2
      src/views/ventAI/manageAssistent/components/chatModal/FilePreviewPanel.vue
  52. 76 87
      src/views/ventAI/manageAssistent/components/chatModal/TaskListPanel.vue
  53. 0 397
      src/views/ventAI/manageAssistent/components/chatModal/ThinkingPanel.vue
  54. 1 0
      src/views/ventAI/manageAssistent/components/chatModal/types.ts
  55. 7 7
      src/views/ventAI/manageAssistent/components/chatModal/utils.ts

+ 7 - 9
src/assets/images/ventAI/chatModalBlue/1-10.svg

@@ -1,10 +1,8 @@
-<svg id="组_16756" data-name="组 16756" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12.442" height="12.482" viewBox="0 0 12.442 12.482">
-  <defs>
-    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
-      <stop offset="0" stop-color="#659ebc"/>
-      <stop offset="1" stop-color="#207aab"/>
-    </linearGradient>
-  </defs>
-  <path id="路径_57050" data-name="路径 57050" d="M6.37,0A4.74,4.74,0,1,1,1.63,4.74,4.741,4.741,0,0,1,6.37,0Zm0,1.435a3.305,3.305,0,1,0,3.3,3.305,3.305,3.305,0,0,0-3.3-3.305ZM9.653,8.888c-.113.082-.14.11-.054.222.666.871,1.386,1.8,2.049,2.665,1.4,1.827,3.541-.293,1.73-1.71-.86-.673-1.777-1.4-2.64-2.08-.111-.087-.138-.06-.222.052a3.921,3.921,0,0,1-.862.852Z" transform="translate(-1.63)" fill="url(#linear-gradient)"/>
-  <path id="路径_57051" data-name="路径 57051" d="M195.648,194.975h4.522a.12.12,0,0,1,.12.12v1.043a.12.12,0,0,1-.12.12h-4.522a.12.12,0,0,1-.12-.12v-1.043a.12.12,0,0,1,.12-.12Z" transform="translate(-193.143 -190.863)" fill="url(#linear-gradient)"/>
+<svg xmlns="http://www.w3.org/2000/svg" width="15.753" height="13.602" viewBox="0 0 15.753 13.602">
+  <g id="组_16862" data-name="组 16862" transform="translate(-683.624 -454.698)">
+    <g id="组_16817" data-name="组 16817" transform="translate(12014.351 18447.115)">
+      <path id="路径_58150" data-name="路径 58150" d="M65.85,122.88H52.3a1.12,1.12,0,0,0,0,2.24H65.85a1.112,1.112,0,0,0,1.1-1.12A1.1,1.1,0,0,0,65.85,122.88Zm-9.494,5.512H52.3a1.112,1.112,0,0,0-1.1,1.12,1.123,1.123,0,0,0,1.1,1.12h4.054a1.112,1.112,0,0,0,1.1-1.12A1.1,1.1,0,0,0,56.356,128.392Zm0,5.512H52.3a1.112,1.112,0,0,0-1.1,1.12,1.123,1.123,0,0,0,1.1,1.12h4.089a1.063,1.063,0,0,0,.765-.32,1.086,1.086,0,0,0,.32-.8A1.127,1.127,0,0,0,56.356,133.9Z" transform="translate(-11381.927 -18115.297)" fill="#fff"/>
+      <path id="路径_58151" data-name="路径 58151" d="M4.054,6.881,8.125,0H0Z" transform="translate(-11322.851 -17978.814) rotate(-90)" fill="#fff"/>
+    </g>
+  </g>
 </svg>

+ 7 - 9
src/assets/images/ventAI/chatModalBlue/1-11.svg

@@ -1,10 +1,8 @@
-<svg id="组_16759" data-name="组 16759" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12.442" height="12.482" viewBox="0 0 12.442 12.482">
-  <defs>
-    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
-      <stop offset="0" stop-color="#bce8ff"/>
-      <stop offset="1" stop-color="#28a6ea"/>
-    </linearGradient>
-  </defs>
-  <path id="路径_57050" data-name="路径 57050" d="M6.37,0A4.74,4.74,0,1,1,1.63,4.74,4.741,4.741,0,0,1,6.37,0Zm0,1.435a3.305,3.305,0,1,0,3.3,3.305,3.305,3.305,0,0,0-3.3-3.305ZM9.653,8.888c-.113.082-.14.11-.054.222.666.871,1.386,1.8,2.049,2.665,1.4,1.827,3.541-.293,1.73-1.71-.86-.673-1.777-1.4-2.64-2.08-.111-.087-.138-.06-.222.052a3.921,3.921,0,0,1-.862.852Z" transform="translate(-1.63)" fill="url(#linear-gradient)"/>
-  <path id="路径_57051" data-name="路径 57051" d="M195.648,194.975h4.522a.12.12,0,0,1,.12.12v1.043a.12.12,0,0,1-.12.12h-4.522a.12.12,0,0,1-.12-.12v-1.043a.12.12,0,0,1,.12-.12Z" transform="translate(-193.143 -190.863)" fill="url(#linear-gradient)"/>
+<svg xmlns="http://www.w3.org/2000/svg" width="15.753" height="13.602" viewBox="0 0 15.753 13.602">
+  <g id="组_16858" data-name="组 16858" transform="translate(-683.624 -454.698)">
+    <g id="组_16817" data-name="组 16817" transform="translate(12014.351 18447.115)">
+      <path id="路径_58150" data-name="路径 58150" d="M65.85,122.88H52.3a1.12,1.12,0,0,0,0,2.24H65.85a1.112,1.112,0,0,0,1.1-1.12A1.1,1.1,0,0,0,65.85,122.88Zm-9.494,5.512H52.3a1.112,1.112,0,0,0-1.1,1.12,1.123,1.123,0,0,0,1.1,1.12h4.054a1.112,1.112,0,0,0,1.1-1.12A1.1,1.1,0,0,0,56.356,128.392Zm0,5.512H52.3a1.112,1.112,0,0,0-1.1,1.12,1.123,1.123,0,0,0,1.1,1.12h4.089a1.063,1.063,0,0,0,.765-.32,1.086,1.086,0,0,0,.32-.8A1.127,1.127,0,0,0,56.356,133.9Z" transform="translate(-11381.927 -18115.297)" fill="#fff"/>
+      <path id="路径_58151" data-name="路径 58151" d="M63.13,128.978l4.071,6.881H59.076Z" transform="translate(-11451.829 -17919.738) rotate(-90)" fill="#fff"/>
+    </g>
+  </g>
 </svg>

+ 5 - 8
src/assets/images/ventAI/chatModalBlue/1-12.svg

@@ -1,9 +1,6 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12.442" height="12.414" viewBox="0 0 12.442 12.414">
-  <defs>
-    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
-      <stop offset="0" stop-color="#659ebc"/>
-      <stop offset="1" stop-color="#207aab"/>
-    </linearGradient>
-  </defs>
-  <path id="路径_58051" data-name="路径 58051" d="M114.815,184.972a5.445,5.445,0,0,0-.124,1,4.328,4.328,0,0,0,4.355,4.355,3.757,3.757,0,0,0,1.866-.436v2.364a1.673,1.673,0,0,1-1.68,1.68h-2.551l-.933,1.12a.532.532,0,0,1-.809.062.061.061,0,0,1-.062-.062l-.933-1.12h-2.551a1.673,1.673,0,0,1-1.68-1.68v-5.6a1.673,1.673,0,0,1,1.68-1.68Zm4.23,4.106a3.111,3.111,0,1,1,3.111-3.111A3.08,3.08,0,0,1,119.045,189.078Zm.373-3.484v-1.306a.378.378,0,1,0-.747,0v1.618a.229.229,0,0,0,.062.187.342.342,0,0,0,.311.187h1.12a.378.378,0,1,0,0-.747h-.747Z" transform="translate(-109.713 -182.857)" fill="url(#linear-gradient)"/>
+<svg xmlns="http://www.w3.org/2000/svg" width="12.804" height="10.613" viewBox="0 0 12.804 10.613">
+  <g id="组_16862" data-name="组 16862" transform="translate(-463.598 -140.692)">
+    <path id="路径_58188" data-name="路径 58188" d="M60.746,133.265,64,127.76H57.5Z" transform="translate(412.398 17.813)" fill="#fff"/>
+    <path id="路径_58189" data-name="路径 58189" d="M62.922,122.88H52.082a.9.9,0,0,0,0,1.793h10.84a.89.89,0,0,0,.882-.9A.881.881,0,0,0,62.922,122.88Zm-7.6,4.41H52.082a.89.89,0,0,0-.882.9.9.9,0,0,0,.882.9h3.244a.89.89,0,0,0,.882-.9A.881.881,0,0,0,55.326,127.29Zm0,4.41H52.082a.89.89,0,0,0-.882.9.9.9,0,0,0,.882.9h3.272a.85.85,0,0,0,.612-.256.869.869,0,0,0,.256-.64A.9.9,0,0,0,55.326,131.7Z" transform="translate(412.398 17.813)" fill="#fff"/>
+  </g>
 </svg>

+ 2 - 8
src/assets/images/ventAI/chatModalBlue/1-13.svg

@@ -1,9 +1,3 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12.442" height="12.414" viewBox="0 0 12.442 12.414">
-  <defs>
-    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
-      <stop offset="0" stop-color="#bce8ff"/>
-      <stop offset="1" stop-color="#28a6ea"/>
-    </linearGradient>
-  </defs>
-  <path id="路径_58052" data-name="路径 58052" d="M114.815,184.972a5.445,5.445,0,0,0-.124,1,4.328,4.328,0,0,0,4.355,4.355,3.757,3.757,0,0,0,1.866-.436v2.364a1.673,1.673,0,0,1-1.68,1.68h-2.551l-.933,1.12a.532.532,0,0,1-.809.062.061.061,0,0,1-.062-.062l-.933-1.12h-2.551a1.673,1.673,0,0,1-1.68-1.68v-5.6a1.673,1.673,0,0,1,1.68-1.68Zm4.23,4.106a3.111,3.111,0,1,1,3.111-3.111A3.08,3.08,0,0,1,119.045,189.078Zm.373-3.484v-1.306a.378.378,0,1,0-.747,0v1.618a.229.229,0,0,0,.062.187.342.342,0,0,0,.311.187h1.12a.378.378,0,1,0,0-.747h-.747Z" transform="translate(-109.713 -182.857)" fill="url(#linear-gradient)"/>
+<svg xmlns="http://www.w3.org/2000/svg" width="12.804" height="10.613" viewBox="0 0 12.804 10.613">
+  <path id="路径_58187" data-name="路径 58187" d="M62.922,122.88H52.082a.9.9,0,0,0,0,1.793h10.84a.89.89,0,0,0,.882-.9A.881.881,0,0,0,62.922,122.88Zm-7.6,4.41H52.082a.89.89,0,0,0-.882.9.9.9,0,0,0,.882.9h3.244a.89.89,0,0,0,.882-.9A.881.881,0,0,0,55.326,127.29Zm0,4.41H52.082a.89.89,0,0,0-.882.9.9.9,0,0,0,.882.9h3.272a.85.85,0,0,0,.612-.256.869.869,0,0,0,.256-.64A.9.9,0,0,0,55.326,131.7Zm5.42-3.941L64,133.265H57.5Z" transform="translate(-51.2 -122.88)" fill="#fff"/>
 </svg>

binární
src/assets/images/ventAI/chatModalBlue/1-14.png


+ 0 - 10
src/assets/images/ventAI/chatModalBlue/1-14.svg

@@ -1,10 +0,0 @@
-<svg id="组_16757" data-name="组 16757" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.901" height="13.9" viewBox="0 0 13.901 13.9">
-  <defs>
-    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
-      <stop offset="0" stop-color="#659ebc"/>
-      <stop offset="1" stop-color="#207aab"/>
-    </linearGradient>
-  </defs>
-  <path id="路径_58006" data-name="路径 58006" d="M464.881,147.213a.881.881,0,0,1-.881-.881V134.193a.881.881,0,0,1,1.762,0v12.139A.881.881,0,0,1,464.881,147.213Z" transform="translate(-457.931 -133.312)" fill="url(#linear-gradient)"/>
-  <path id="路径_58007" data-name="路径 58007" d="M146.332,465.762H134.193a.881.881,0,0,1,0-1.762h12.139a.881.881,0,1,1,0,1.762Z" transform="translate(-133.312 -457.931)" fill="url(#linear-gradient)"/>
-</svg>

binární
src/assets/images/ventAI/chatModalBlue/1-15.png


+ 0 - 10
src/assets/images/ventAI/chatModalBlue/1-15.svg

@@ -1,10 +0,0 @@
-<svg id="组_16758" data-name="组 16758" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.901" height="13.9" viewBox="0 0 13.901 13.9">
-  <defs>
-    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
-      <stop offset="0" stop-color="#bce8ff"/>
-      <stop offset="1" stop-color="#28a6ea"/>
-    </linearGradient>
-  </defs>
-  <path id="路径_58006" data-name="路径 58006" d="M464.881,147.213a.881.881,0,0,1-.881-.881V134.193a.881.881,0,0,1,1.762,0v12.139A.881.881,0,0,1,464.881,147.213Z" transform="translate(-457.931 -133.312)" fill="url(#linear-gradient)"/>
-  <path id="路径_58007" data-name="路径 58007" d="M146.332,465.762H134.193a.881.881,0,0,1,0-1.762h12.139a.881.881,0,1,1,0,1.762Z" transform="translate(-133.312 -457.931)" fill="url(#linear-gradient)"/>
-</svg>

binární
src/assets/images/ventAI/chatModalBlue/1-3.png


binární
src/assets/images/ventAI/chatModalBlue/1-4.png


binární
src/assets/images/ventAI/chatModalBlue/1-7.png


+ 4 - 0
src/assets/images/ventAI/chatModalBlue/1-7.svg

@@ -0,0 +1,4 @@
+<svg id="组_16862" data-name="组 16862" xmlns="http://www.w3.org/2000/svg" width="12.021" height="12.021" viewBox="0 0 12.021 12.021">
+  <path id="路径_58006" data-name="路径 58006" d="M464.762,145.333a.762.762,0,0,1-.762-.762v-10.5a.762.762,0,1,1,1.524,0v10.5A.762.762,0,0,1,464.762,145.333Z" transform="translate(-458.751 -133.312)" fill="#fff"/>
+  <path id="路径_58007" data-name="路径 58007" d="M144.571,465.524h-10.5a.762.762,0,1,1,0-1.524h10.5a.762.762,0,1,1,0,1.524Z" transform="translate(-133.312 -458.751)" fill="#fff"/>
+</svg>

+ 4 - 0
src/assets/images/ventAI/chatModalBlue/1-8.svg

@@ -0,0 +1,4 @@
+<svg id="组_16862" data-name="组 16862" xmlns="http://www.w3.org/2000/svg" width="10.382" height="10.415" viewBox="0 0 10.382 10.415">
+  <path id="路径_57050" data-name="路径 57050" d="M5.584,0A3.955,3.955,0,1,1,1.63,3.955,3.955,3.955,0,0,1,5.584,0Zm0,1.2A2.758,2.758,0,1,0,8.342,3.955,2.758,2.758,0,0,0,5.584,1.2Zm2.74,6.218c-.094.069-.117.092-.045.185.556.727,1.156,1.5,1.709,2.223,1.165,1.525,2.955-.244,1.443-1.427-.718-.562-1.483-1.171-2.2-1.735-.093-.073-.115-.05-.186.043a3.271,3.271,0,0,1-.719.711Z" transform="translate(-1.63)" fill="#fff"/>
+  <path id="路径_57051" data-name="路径 57051" d="M195.629,194.975H199.4a.1.1,0,0,1,.1.1v.87a.1.1,0,0,1-.1.1h-3.773a.1.1,0,0,1-.1-.1v-.87a.1.1,0,0,1,.1-.1Z" transform="translate(-193.539 -191.544)" fill="#fff"/>
+</svg>

+ 3 - 0
src/assets/images/ventAI/chatModalBlue/1-9.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="12.037" height="11.144" viewBox="0 0 12.037 11.144">
+  <path id="路径_58133" data-name="路径 58133" d="M11.037,6.232a.4.4,0,0,1-.4.4h-.8v.8a.4.4,0,0,1-.8,0v-.8h-.8a.4.4,0,1,1,0-.8h.8v-.8a.4.4,0,0,1,.8,0v.8h.8A.4.4,0,0,1,11.037,6.232Zm-9.2-4.2h.6v.6a.4.4,0,1,0,.8,0v-.6h.6a.4.4,0,0,0,0-.8h-.6v-.6a.4.4,0,1,0-.8,0v.6h-.6a.4.4,0,1,0,0,.8Zm6,6.2h-.4v-.4a.4.4,0,0,0-.8,0v.4h-.4a.4.4,0,1,0,0,.8h.4v.4a.4.4,0,1,0,.8,0v-.4h.4a.4.4,0,0,0,0-.8ZM7.721,4.517,2.4,9.832a.795.795,0,0,1-1.13,0L.236,8.8a.795.795,0,0,1,0-1.13L7.671.231a.805.805,0,0,1,1.13,0L9.837,1.267a.8.8,0,0,1,0,1.13L7.721,4.518ZM6.4,2.631,7.436,3.667,9.272,1.831,8.237.8Z" transform="translate(0.5 0.576)" fill="#fff" stroke="rgba(0,0,0,0)" stroke-miterlimit="10" stroke-width="1"/>
+</svg>

+ 3 - 0
src/assets/images/ventAI/chatModalBlue/2-1.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="18.926" height="19.755" viewBox="0 0 18.926 19.755">
+  <path id="路径_58149" data-name="路径 58149" d="M3.158,1.858H6.5A.878.878,0,0,0,7.432.929.878.878,0,0,0,6.5,0H.743C.557,0,.372.185.186.371A.683.683,0,0,0,0,.929V6.5a.878.878,0,0,0,.929.929A.878.878,0,0,0,1.858,6.5V3.158L6.874,8.174a.92.92,0,0,0,1.3-1.3ZM18,12.323a.878.878,0,0,0-.929.929V16.6L15.4,14.924,12.052,11.58a.92.92,0,0,0-1.3,1.3L14.1,16.225,15.767,17.9H12.423a.929.929,0,1,0,0,1.858H18a.878.878,0,0,0,.929-.929V13.252A.878.878,0,0,0,18,12.323Z" transform="translate(0 0)" fill="#9fdcfd"/>
+</svg>

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
src/assets/images/ventAI/chatModalBlue/2-2.svg


+ 11 - 0
src/assets/images/ventAI/chatModalBlue/2-3.svg

@@ -0,0 +1,11 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="12.465" height="12.465" viewBox="0 0 12.465 12.465">
+  <g id="组_16834" data-name="组 16834" transform="translate(-76.8 -76.8)">
+    <path id="路径_58166" data-name="路径 58166" d="M205.865,80.759a.135.135,0,0,1-.11-.037,2.017,2.017,0,1,1,2.676-1.906.367.367,0,0,1-.733,0,1.283,1.283,0,1,0-2.566,0,1.268,1.268,0,0,0,.843,1.21.381.381,0,0,1,.22.477A.352.352,0,0,1,205.865,80.759Zm2.2,3.3h0a.377.377,0,0,1-.367-.4,1.438,1.438,0,0,0-.147-.66,1.359,1.359,0,0,0-.733-.623,1.331,1.331,0,0,0-.99.073.377.377,0,1,1-.367-.66,2.045,2.045,0,0,1,1.54-.147,1.959,1.959,0,0,1,1.173.99,1.805,1.805,0,0,1,.22,1.063A.319.319,0,0,1,208.065,84.059Zm-1.65,5.206a2,2,0,0,1-1.43-.587,2.07,2.07,0,0,1-.4-2.31.361.361,0,0,1,.66.293,1.3,1.3,0,1,0,2.09-.367.363.363,0,0,1,.513-.513,2.059,2.059,0,0,1,0,2.859A1.9,1.9,0,0,1,206.415,89.265Z" transform="translate(-125.766 0)" fill="#fff"/>
+    <path id="路径_58167" data-name="路径 58167" d="M78.816,184.332a2.016,2.016,0,0,1,0-4.033,1.712,1.712,0,0,1,.623.11.371.371,0,0,1-.257.7,1.56,1.56,0,0,0-.4-.073,1.283,1.283,0,1,0,0,2.566.346.346,0,0,1,.367.367C79.146,184.186,79.036,184.332,78.816,184.332Zm3.483,4.4a.394.394,0,0,1-.367-.367v-8.8a.394.394,0,0,1,.367-.367.367.367,0,0,1,.367.367v8.8A.367.367,0,0,1,82.3,188.732Z" transform="translate(0 -100.934)" fill="#fff"/>
+    <path id="路径_58168" data-name="路径 58168" d="M207.754,715.7a1.945,1.945,0,0,1-1.65-.88,2.04,2.04,0,0,1,.037-2.346.387.387,0,0,1,.513-.073.353.353,0,0,1,.073.513,1.265,1.265,0,0,0,0,1.5,1.292,1.292,0,0,0,2.126-1.467.371.371,0,0,1,.623-.4,2.051,2.051,0,0,1-.513,2.823A2.507,2.507,0,0,1,207.754,715.7Z" transform="translate(-127.104 -626.434)" fill="#fff"/>
+    <path id="路径_58169" data-name="路径 58169" d="M78.816,86.7a2.016,2.016,0,1,1,0-4.033.367.367,0,0,1,0,.733A1.283,1.283,0,1,0,80.1,84.682a.367.367,0,0,1,.733,0A2.034,2.034,0,0,1,78.816,86.7Zm7.149-5.939a.352.352,0,0,1-.33-.257.381.381,0,0,1,.22-.477,1.268,1.268,0,0,0,.843-1.21,1.283,1.283,0,1,0-2.566,0,.367.367,0,0,1-.733,0,2.016,2.016,0,1,1,2.676,1.906C86.038,80.723,86,80.759,85.965,80.759Zm-2.2,3.3a.362.362,0,0,1-.367-.33,2.136,2.136,0,0,1,.22-1.063,1.958,1.958,0,0,1,1.173-.99,2.045,2.045,0,0,1,1.54.147.377.377,0,1,1-.367.66,1.318,1.318,0,0,0-.99-.073,1.243,1.243,0,0,0-.733.623,1.438,1.438,0,0,0-.147.66c.037.147-.11.33-.33.367Zm1.65,5.206a2,2,0,0,1-1.43-.587,2.059,2.059,0,0,1,0-2.86.363.363,0,0,1,.513.513,1.3,1.3,0,0,0,1.833,1.833,1.35,1.35,0,0,0,.257-1.466.361.361,0,1,1,.66-.293,2.019,2.019,0,0,1-.4,2.31A2.121,2.121,0,0,1,85.415,89.265Z" transform="translate(0 0)" fill="#fff"/>
+    <path id="路径_58170" data-name="路径 58170" d="M541.449,184.332a.367.367,0,0,1,0-.733,1.283,1.283,0,1,0,0-2.566,1.318,1.318,0,0,0-.4.073.371.371,0,1,1-.257-.7,1.861,1.861,0,0,1,.623-.11,2.034,2.034,0,0,1,2.016,2.016A2,2,0,0,1,541.449,184.332Zm-3.483,4.4a.394.394,0,0,0,.367-.367v-8.8a.394.394,0,0,0-.367-.367.367.367,0,0,0-.367.367v8.8A.367.367,0,0,0,537.967,188.732Z" transform="translate(-454.201 -100.934)" fill="#fff"/>
+    <path id="路径_58171" data-name="路径 58171" d="M540.534,713.175a1.833,1.833,0,0,1-1.137-.367,2.045,2.045,0,0,1-.513-2.823.371.371,0,0,1,.623.4,1.291,1.291,0,1,0,2.126,1.466,1.393,1.393,0,0,0,0-1.5.367.367,0,0,1,.587-.44,2.038,2.038,0,0,1,.037,2.346A2.16,2.16,0,0,1,540.534,713.175Z" transform="translate(-455.119 -623.91)" fill="#fff"/>
+    <path id="路径_58172" data-name="路径 58172" d="M667.616,490.433a2.034,2.034,0,0,1-2.016-2.016.367.367,0,0,1,.733,0,1.283,1.283,0,1,0,1.283-1.283.367.367,0,1,1,0-.733,2.016,2.016,0,0,1,0,4.033Z" transform="translate(-580.368 -403.734)" fill="#fff"/>
+  </g>
+</svg>

+ 3 - 0
src/assets/images/ventAI/chatModalBlue/2-4.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="15.577" height="14.275" viewBox="0 0 15.577 14.275">
+  <path id="路径_58175" data-name="路径 58175" d="M231.4,213.675a1.222,1.222,0,0,1,.651,2.254v.761h4.041l.087,0a.846.846,0,0,1,.759.841V226.1a.846.846,0,0,1-.845.846h-9.384a.846.846,0,0,1-.846-.846v-8.568a.846.846,0,0,1,.846-.846h4.041v-.761a1.221,1.221,0,0,1,.651-2.254Zm-4.236,11.974h8.471v-7.658h-8.471v7.658Zm-2.386-6.107a.651.651,0,0,1,.651.651v3.258a.651.651,0,0,1-1.3,0v-3.258a.651.651,0,0,1,.651-.651Zm13.276,0a.651.651,0,0,1,.651.651v3.258a.651.651,0,0,1-1.3,0v-3.258a.651.651,0,0,1,.651-.651Zm-8.795,1.1a1.313,1.313,0,1,1-1.313,1.313A1.313,1.313,0,0,1,229.257,220.644Zm4.313,0a1.314,1.314,0,1,1-1.314,1.314,1.314,1.314,0,0,1,1.314-1.314Z" transform="translate(-223.625 -213.175)" fill="#cdeeff" stroke="rgba(0,0,0,0)" stroke-miterlimit="10" stroke-width="1" opacity="0.5"/>
+</svg>

+ 1 - 0
src/assets/images/ventAI/chatModalBlue/2-5.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1784697577869" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5688" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M416.832 798.08c-16.192 0-32.32-6.208-44.672-18.56L119.424 525.76c-24.64-24.768-24.64-64.96 0-89.728 24.704-24.768 64.704-24.768 89.344 0l208.064 208.896L814.4 245.76c24.64-24.832 64.64-24.832 89.344 0 24.64 24.768 24.64 64.896 0 89.664L461.504 779.52c-12.352 12.352-28.544 18.56-44.672 18.56z" fill="#1AB394" p-id="5689"></path></svg>

binární
src/assets/images/ventAI/chatModalBlue/2-6.png


+ 3 - 0
src/assets/images/ventAI/chatModalBlue/2-6.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="15.966" height="17.738" viewBox="0 0 15.966 17.738">
+  <path id="路径_58128" data-name="路径 58128" d="M17.29,8.475c.6-.272.6-.712,0-.985L1.089.1A.705.705,0,0,0,.007.785L0,6.121,13.122,7.982,0,9.844.007,15.18a.7.7,0,0,0,1.082.687Z" transform="translate(0 17.738) rotate(-90)" fill="#fff"/>
+</svg>

binární
src/assets/images/ventAI/chatModalBlue/3-1.png


binární
src/assets/images/ventAI/chatModalBlue/3-2.png


binární
src/assets/images/ventAI/chatModalBlue/3-5.png


binární
src/assets/images/ventAI/chatModalBlue/3-6.png


+ 2 - 6
src/assets/images/ventAI/chatModalBlue/3-7.svg

@@ -1,7 +1,3 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="41.266" height="48.044" viewBox="0 0 41.266 48.044">
-  <g id="组_16767" data-name="组 16767" transform="translate(-102.4 -34.133)">
-    <path id="路径_58014" data-name="路径 58014" d="M296.429,342.194H271.378a3.442,3.442,0,0,1-3.432-3.432V312.338a3.442,3.442,0,0,1,3.432-3.432h25.051a3.442,3.442,0,0,1,3.432,3.432v26.424A3.442,3.442,0,0,1,296.429,342.194Z" transform="translate(-157.225 -260.96)" fill="#1e6f9f" opacity="0.3"/>
-    <path id="路径_58015" data-name="路径 58015" d="M138.947,82.177H107.033a4.614,4.614,0,0,1-4.633-4.633V38.766a4.614,4.614,0,0,1,4.633-4.633h32a4.614,4.614,0,0,1,4.633,4.633V77.458a4.7,4.7,0,0,1-4.719,4.719Zm-31.915-45.47a2.107,2.107,0,0,0-2.145,2.059V77.458a2.088,2.088,0,0,0,2.059,2.059h32a2.088,2.088,0,0,0,2.059-2.059V38.766a1.981,1.981,0,0,0-2.059-2.059H107.033Z" transform="translate(0)" fill="#1e6f9f"/>
-    <path id="路径_58016" data-name="路径 58016" d="M311.82,233.17H294.834a1.287,1.287,0,0,1,0-2.574H311.82a1.287,1.287,0,0,1,0,2.574Zm-8.493,6.863h-8.493a1.287,1.287,0,0,1,0-2.574h8.493a1.287,1.287,0,0,1,0,2.574Zm6.778-15.614H296.549a3.04,3.04,0,0,1-3-3v-8.493a3.04,3.04,0,0,1,3-3H310.1a3.04,3.04,0,0,1,3,3v8.493A3.04,3.04,0,0,1,310.1,224.419Zm-13.555-11.925a.405.405,0,0,0-.429.429v8.493a.405.405,0,0,0,.429.429H310.1a.405.405,0,0,0,.429-.429v-8.493a.405.405,0,0,0-.429-.429Z" transform="translate(-181.538 -166.95)" fill="#1e6f9f"/>
-  </g>
+<svg xmlns="http://www.w3.org/2000/svg" width="16.192" height="13.886" viewBox="0 0 16.192 13.886">
+  <path id="路径_58152" data-name="路径 58152" d="M69.385,132a1.527,1.527,0,0,1,1.023.393l2.048,1.849a.509.509,0,0,0,.341.131h3.244a1.526,1.526,0,0,1,1.526,1.526v1.7h.1a1.526,1.526,0,0,1,1.394,2.147l-1.889,4.239a1.526,1.526,0,0,1-1.394.905H65.526A1.526,1.526,0,0,1,64,143.36v-9.834A1.526,1.526,0,0,1,65.526,132Zm8.28,6.612h-9.7a.509.509,0,0,0-.465.3l-1.889,4.239a.509.509,0,0,0,.465.716h9.7a.509.509,0,0,0,.465-.3l1.889-4.239a.509.509,0,0,0-.465-.716Zm-8.28-5.6H65.526a.509.509,0,0,0-.509.509v8.454l1.55-3.48a1.526,1.526,0,0,1,1.394-.905h8.588v-1.7a.509.509,0,0,0-.509-.509H72.8A1.527,1.527,0,0,1,71.775,135l-2.048-1.849A.509.509,0,0,0,69.385,133.017Z" transform="translate(-63.5 -131.5)" fill="#fff" stroke="rgba(0,0,0,0)" stroke-miterlimit="10" stroke-width="1"/>
 </svg>

+ 1 - 0
src/assets/images/ventAI/chatModalBlue/4-5.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1784698235264" class="icon" viewBox="0 0 1050 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7017" xmlns:xlink="http://www.w3.org/1999/xlink" width="205.078125" height="200"><path d="M23.760635 1024c-13.130877 0-23.760635-10.629758-23.760635-23.760635 0-12.922451 10.629758-23.552208 23.760635-23.552208h1002.948911c13.130877 0 23.760635 10.629758 23.760635 23.552208 0 13.130877-10.629758 23.760635-23.760635 23.760635H23.760635zM500.849176 23.760635c0-13.130877 10.629758-23.760635 23.552208-23.760635 13.130877 0 23.760635 10.629758 23.760635 23.760635v802.4425c0 12.922451-10.629758 23.552208-23.760635 23.552208-12.922451 0-23.552208-10.629758-23.552208-23.552208V23.760635z" p-id="7018" fill="#ffffff"></path><path d="M93.375127 431.026257c-9.379198-9.170771-9.379198-24.177488-0.208426-33.34826 9.170771-9.379198 24.177488-9.379198 33.556686-0.208426l413.935274 411.851007c9.170771 9.170771 9.170771 24.177488 0 33.556686-9.170771 9.170771-24.177488 9.170771-33.34826 0L93.375127 431.026257z" p-id="7019" fill="#ffffff"></path><path d="M922.287808 397.469571c9.170771-9.170771 24.177488-9.170771 33.34826 0.208426 9.379198 9.170771 9.170771 24.177488 0 33.34826L540.658661 842.877264c-9.379198 9.170771-24.385915 9.170771-33.556687 0-9.170771-9.379198-9.170771-24.385915 0.208427-33.556686l414.977407-411.851007z" p-id="7020" fill="#ffffff"></path></svg>

+ 1 - 0
src/assets/images/ventAI/chatModalBlue/4-6.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1784698289493" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8101" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M959.825022 384.002258V191.939717C959.825022 121.2479 902.517291 63.940169 831.825474 63.940169H191.939717C121.2479 63.940169 63.940169 121.2479 63.940169 191.939717v639.885757C63.940169 902.517291 121.2479 959.825022 191.939717 959.825022h639.885757c70.691817 0 127.999548-57.307731 127.999548-127.999548V384.002258zM146.66502 146.66502a63.737872 63.737872 0 0 1 45.336109-18.784682h639.997742A63.961844 63.961844 0 0 1 895.884854 192.001129V320.062089H127.880338V192.001129A63.737872 63.737872 0 0 1 146.66502 146.66502z m269.1267 461.308451v-223.971213h192.181751v223.971213h-192.181751z m192.181751 63.940169v223.971214h-192.181751v-223.971214h192.181751z m-256.12192-63.940169H127.880338v-223.971213h223.971213v223.971213z m-205.186531 269.235073a63.466939 63.466939 0 0 1-18.784682-45.209673V671.91364h223.971213v223.971214H192.001129a63.625887 63.625887 0 0 1-45.336109-18.67631z m749.219834-45.209673A63.763159 63.763159 0 0 1 831.998871 895.884854H671.91364v-223.971214h223.971214v160.085231z m0-224.0254h-223.971214v-223.971213h223.971214v223.971213z" fill="#ffffff" p-id="8102"></path></svg>

binární
src/assets/images/ventAI/chatModalBlue/5-1.png


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
src/assets/images/ventAI/dataPicker/AI-icon.svg


+ 28 - 23
src/design/themify/deepblue.less

@@ -68,33 +68,38 @@ html[data-theme='deepblue'] {
   --img-ai-float: url('/src/assets/images/ventAI/chatModalBlue/4-1.png');
 
   // 聊天弹窗图片
-  --img-chat-header-icon: url('/src/assets/images/ventAI/chatModalBlue/2-5.png');
-  --img-chat-selector-bg: url('/src/assets/images/ventAI/chatModalBlue/2-6.png');
-  --img-chat-upload-bg: url('/src/assets/images/ventAI/chatModalBlue/2-7.png');
-  --img-chat-upload-icon: url('/src/assets/images/ventAI/chatModalBlue/2-10.svg');
-  --img-chat-download-icon: url('/src/assets/images/ventAI/chatModalBlue/2-8.svg');
-  --img-chat-modal-title: url('/src/assets/images/ventAI/chatModalBlue/1-1.png');
-  --img-chat-panel-header: url('/src/assets/images/ventAI/chatModalBlue/3-5.png');
-  --img-chat-close-icon: url('/src/assets/images/ventAI/chatModalBlue/2-11.svg');
-  --img-chat-thinking-bg: url('/src/assets/images/ventAI/chatModalBlue/3-6.png');
-  --img-chat-task-bg: url('/src/assets/images/ventAI/chatModalBlue/2-3.png');
-  --img-chat-options-active-bg: url('/src/assets/images/ventAI/chatModalBlue/1-3.png');
-  --img-chat-options-bg: url('/src/assets/images/ventAI/chatModalBlue/1-4.png');
+  --img-chat-modal-bg: url('/src/assets/images/ventAI/chatModalBlue/1-1.png');
+  --img-chat-close-bg: url('/src/assets/images/ventAI/chatModalBlue/1-2.png');
+  --img-chat-options-icon-border: url('/src/assets/images/ventAI/chatModalBlue/1-3.png');
   --img-chat-task-panel-bg: url('/src/assets/images/ventAI/chatModalBlue/1-5.png');
-  --img-chat-options-search-icon: url('/src/assets/images/ventAI/chatModalBlue/1-10.svg');
-  --img-chat-options-search-active-icon: url('/src/assets/images/ventAI/chatModalBlue/1-11.svg');
-  --img-chat-options-history-icon: url('/src/assets/images/ventAI/chatModalBlue/1-12.svg');
-  --img-chat-options-history-active-icon: url('/src/assets/images/ventAI/chatModalBlue/1-13.svg');
-  --img-chat-options-add-icon: url('/src/assets/images/ventAI/chatModalBlue/1-14.svg');
-  --img-chat-options-add-active-icon: url('/src/assets/images/ventAI/chatModalBlue/1-15.svg');
+  --img-chat-panel-bg: url('/src/assets/images/ventAI/chatModalBlue/1-6.png');
+  --img-chat-options-add-icon: url('/src/assets/images/ventAI/chatModalBlue/1-7.svg');
+  --img-chat-options-search-icon: url('/src/assets/images/ventAI/chatModalBlue/1-8.svg');
+  --img-chat-options-skill-icon: url('/src/assets/images/ventAI/chatModalBlue/1-9.svg');
+  --img-chat-expand-icon: url('/src/assets/images/ventAI/chatModalBlue/1-10.svg');
+  --img-chat-collapse-icon: url('/src/assets/images/ventAI/chatModalBlue/1-11.svg');
+  --img-chat-prev-icon: url('/src/assets/images/ventAI/chatModalBlue/1-14.png');
+  --img-chat-next-icon: url('/src/assets/images/ventAI/chatModalBlue/1-15.png');
+  --img-chat-maximize-icon: url('/src/assets/images/ventAI/chatModalBlue/2-1.svg');
+  --img-chat-minimize-icon: url('/src/assets/images/ventAI/chatModalBlue/2-2.svg');
+  --img-chat-thinking-icon: url('/src/assets/images/ventAI/chatModalBlue/2-3.svg');
   --img-chat-task-add-icon: url('/src/assets/images/ventAI/chatModalBlue/2-4.svg');
+  --img-chat-agent-icon: url('/src/assets/images/ventAI/chatModalBlue/2-4.svg');
+  --img-chat-copy-success-icon: url('/src/assets/images/ventAI/chatModalBlue/2-5.svg');
+  --img-chat-send-icon: url('/src/assets/images/ventAI/chatModalBlue/2-6.svg');
+  --img-chat-close-bg: url('/src/assets/images/ventAI/chatModalBlue/2-7.png');
+  --img-chat-download-icon: url('/src/assets/images/ventAI/chatModalBlue/2-8.png');
   --img-chat-ai-avatar: url('/src/assets/images/ventAI/chatModalBlue/2-9.png');
-  --img-chat-thinking-avatar: url('/src/assets/images/ventAI/chatModalBlue/3-1.png');
-  --img-chat-agent-card-bg: url('/src/assets/images/ventAI/chatModalBlue/3-2.png');
-  --img-chat-agent-card-header: url('/src/assets/images/ventAI/chatModalBlue/3-3.png');
+  --img-chat-upload-icon: url('/src/assets/images/ventAI/chatModalBlue/2-10.svg');
+  --img-chat-close-icon: url('/src/assets/images/ventAI/chatModalBlue/2-11.svg');
+  --img-chat-input-bg: url('/src/assets/images/ventAI/chatModalBlue/2-13.png');
   --img-chat-collapse-bg: url('/src/assets/images/ventAI/chatModalBlue/2-15.png');
   --img-chat-attach-icon: url('/src/assets/images/ventAI/chatModalBlue/3-7.svg');
-  --img-chat-send-icon: url('/src/assets/images/ventAI/chatModalBlue/2-6.png');
   --img-chat-scroll-bottom: url('/src/assets/images/ventAI/chatModalBlue/3-8.png');
-  --img-chat-input-bg: url('/src/assets/images/ventAI/chatModalBlue/2-13.png');
+  --img-chat-arrow-icon: url('/src/assets/images/ventAI/chatModalBlue/4-2.svg');
+  --img-chat-copy-icon: url('/src/assets/images/ventAI/chatModalBlue/4-3.svg');
+  --img-chat-close-icon-btn: url('/src/assets/images/ventAI/chatModalBlue/4-4.svg');
+  --img-chat-download-icon-btn: url('/src/assets/images/ventAI/chatModalBlue/4-5.svg');
+  --img-chat-preview-icon: url('/src/assets/images/ventAI/chatModalBlue/4-6.svg');
+  --img-chat-welcome-img: url('/src/assets/images/ventAI/chatModalBlue/5-1.png');
 }

+ 24 - 20
src/design/themify/default.less

@@ -77,31 +77,35 @@ html {
   // 聊天弹窗图片
   --img-chat-modal-bg: url('/src/assets/images/ventAI/chatModalBlue/1-1.png');
   --img-chat-close-bg: url('/src/assets/images/ventAI/chatModalBlue/1-2.png');
-  --img-chat-options-active-bg: url('/src/assets/images/ventAI/chatModalBlue/1-3.png');
-  --img-chat-options-bg: url('/src/assets/images/ventAI/chatModalBlue/1-4.png');
+  --img-chat-options-icon-border: url('/src/assets/images/ventAI/chatModalBlue/1-3.png');
   --img-chat-task-panel-bg: url('/src/assets/images/ventAI/chatModalBlue/1-5.png');
   --img-chat-panel-bg: url('/src/assets/images/ventAI/chatModalBlue/1-6.png');
-  --img-chat-selector-bg: url('/src/assets/images/ventAI/chatModalBlue/1-7.png');
-  --img-chat-upload-bg: url('/src/assets/images/ventAI/chatModalBlue/2-7.png');
-  --img-chat-upload-icon: url('/src/assets/images/ventAI/chatModalBlue/2-10.svg');
-  --img-chat-download-icon: url('/src/assets/images/ventAI/chatModalBlue/2-8.png');
-  --img-chat-panel-header: url('/src/assets/images/ventAI/chatModalBlue/3-5.png');
-  --img-chat-close-icon: url('/src/assets/images/ventAI/chatModalBlue/2-11.svg');
-  --img-chat-thinking-bg: url('/src/assets/images/ventAI/chatModalBlue/3-6.png');
-  --img-chat-options-search-icon: url('/src/assets/images/ventAI/chatModalBlue/1-10.svg');
-  --img-chat-options-search-active-icon: url('/src/assets/images/ventAI/chatModalBlue/1-11.svg');
-  --img-chat-options-history-icon: url('/src/assets/images/ventAI/chatModalBlue/1-12.svg');
-  --img-chat-options-history-active-icon: url('/src/assets/images/ventAI/chatModalBlue/1-13.svg');
-  --img-chat-options-add-icon: url('/src/assets/images/ventAI/chatModalBlue/1-14.svg');
-  --img-chat-options-add-active-icon: url('/src/assets/images/ventAI/chatModalBlue/1-15.svg');
+  --img-chat-options-add-icon: url('/src/assets/images/ventAI/chatModalBlue/1-7.svg');
+  --img-chat-options-search-icon: url('/src/assets/images/ventAI/chatModalBlue/1-8.svg');
+  --img-chat-options-skill-icon: url('/src/assets/images/ventAI/chatModalBlue/1-9.svg');
+  --img-chat-expand-icon: url('/src/assets/images/ventAI/chatModalBlue/1-10.svg');
+  --img-chat-collapse-icon: url('/src/assets/images/ventAI/chatModalBlue/1-11.svg');
+  --img-chat-prev-icon: url('/src/assets/images/ventAI/chatModalBlue/1-14.png');
+  --img-chat-next-icon: url('/src/assets/images/ventAI/chatModalBlue/1-15.png');
+  --img-chat-maximize-icon: url('/src/assets/images/ventAI/chatModalBlue/2-1.svg');
+  --img-chat-minimize-icon: url('/src/assets/images/ventAI/chatModalBlue/2-2.svg');
+  --img-chat-thinking-icon: url('/src/assets/images/ventAI/chatModalBlue/2-3.svg');
   --img-chat-task-add-icon: url('/src/assets/images/ventAI/chatModalBlue/2-4.svg');
+  --img-chat-agent-icon: url('/src/assets/images/ventAI/chatModalBlue/2-4.svg');
+  --img-chat-copy-success-icon: url('/src/assets/images/ventAI/chatModalBlue/2-5.svg');
+  --img-chat-send-icon: url('/src/assets/images/ventAI/chatModalBlue/2-6.svg');
+  --img-chat-download-icon: url('/src/assets/images/ventAI/chatModalBlue/2-8.png');
   --img-chat-ai-avatar: url('/src/assets/images/ventAI/chatModalBlue/2-9.png');
-  --img-chat-thinking-avatar: url('/src/assets/images/ventAI/chatModalBlue/3-1.png');
-  --img-chat-agent-card-bg: url('/src/assets/images/ventAI/chatModalBlue/3-2.png');
-  --img-chat-agent-card-header: url('/src/assets/images/ventAI/chatModalBlue/3-3.png');
+  --img-chat-upload-icon: url('/src/assets/images/ventAI/chatModalBlue/2-10.svg');
+  --img-chat-close-icon: url('/src/assets/images/ventAI/chatModalBlue/2-11.svg');
+  --img-chat-input-bg: url('/src/assets/images/ventAI/chatModalBlue/1-7.svg');
   --img-chat-collapse-bg: url('/src/assets/images/ventAI/chatModalBlue/2-15.png');
   --img-chat-attach-icon: url('/src/assets/images/ventAI/chatModalBlue/3-7.svg');
-  --img-chat-send-icon: url('/src/assets/images/ventAI/chatModalBlue/2-6.png');
   --img-chat-scroll-bottom: url('/src/assets/images/ventAI/chatModalBlue/3-8.png');
-  --img-chat-input-bg: url('/src/assets/images/ventAI/chatModalBlue/2-13.png');
+  --img-chat-arrow-icon: url('/src/assets/images/ventAI/chatModalBlue/4-2.svg');
+  --img-chat-copy-icon: url('/src/assets/images/ventAI/chatModalBlue/4-3.svg');
+  --img-chat-close-icon-btn: url('/src/assets/images/ventAI/chatModalBlue/4-4.svg');
+  --img-chat-download-icon-btn: url('/src/assets/images/ventAI/chatModalBlue/4-5.svg');
+  --img-chat-preview-icon: url('/src/assets/images/ventAI/chatModalBlue/4-6.svg');
+  --img-chat-welcome-img: url('/src/assets/images/ventAI/chatModalBlue/5-1.png');
 }

+ 13 - 8
src/store/modules/modelFile.ts

@@ -24,15 +24,20 @@ export const useModelFileStore = defineStore({
   },
   actions: {
     async fetchModelFileData() {
-      const raw = await getAllModelFileJsonApi();
-      const processed: Record<string, ModelFileItem[]> = {};
-      for (const [key, items] of Object.entries(raw)) {
-        processed[key] = items.map((item) => ({
-          fileName: item.fileName.replace(/\.[^.]+$/, ''),
-          filePath: item.filePath.replace(/^\/data\/file/, ''),
-        }));
+      try {
+        const raw = await getAllModelFileJsonApi();
+        const processed: Record<string, ModelFileItem[]> = {};
+        for (const [key, items] of Object.entries(raw)) {
+          processed[key] = items.map((item) => ({
+            fileName: item.fileName.replace(/\.[^.]+$/, ''),
+            filePath: item.filePath.replace(/^\/data\/file/, ''),
+          }));
+        }
+        this.modelFileData = processed;
+      } catch (err) {
+        console.warn('[modelFile] 获取模型文件数据失败:', err);
+        this.modelFileData = {};
       }
-      this.modelFileData = processed;
     },
   },
 });

+ 22 - 2
src/views/vent/deviceManager/comment/NormalTable.vue

@@ -239,8 +239,28 @@
     if (!props.batchDelete) return;
     doRequest(
       () =>
-        new Promise((resolve, _reject) => {
-          props.batchDelete!({ ids: selectedRowKeys.value }, (res: any) => resolve(res));
+        new Promise((resolve, reject) => {
+          let done = false;
+          props.batchDelete!(
+            { ids: selectedRowKeys.value },
+            (res: any) => {
+              if (done) return;
+              done = true;
+              resolve(res);
+            },
+            (err: any) => {
+              if (done) return;
+              done = true;
+              reject(err);
+            }
+          );
+          // 兜底:API 未触发任何回调时(如取消弹窗),自动结束 pending 状态
+          setTimeout(() => {
+            if (!done) {
+              done = true;
+              resolve(undefined);
+            }
+          }, 3000);
         }),
       { confirm: false }
     );

+ 4 - 1
src/views/vent/deviceManager/deviceTable/device.api.ts

@@ -64,7 +64,7 @@ export const deleteByIdF = (params, handleSuccess) => {
  * 批量删除用户
  * @param params
  */
-export const batchDeleteById = (params, handleSuccess) => {
+export const batchDeleteById = (params, handleSuccess, handleCancel) => {
   Modal.confirm({
     title: '确认删除',
     content: '是否删除选中数据',
@@ -75,6 +75,9 @@ export const batchDeleteById = (params, handleSuccess) => {
         handleSuccess();
       });
     },
+    onCancel: () => {
+      handleCancel?.();
+    },
   });
 };
 /**

+ 95 - 35
src/views/vent/deviceManager/substationTabel/substation.data.ts

@@ -102,40 +102,14 @@ export const formSchema: FormSchema[] = [
     component: 'Input',
     required: true,
   },
-
   {
     label: '读取数据方式',
     field: 'strtype',
     component: 'JDictSelectTag',
     required: true,
-    componentProps: ({ formModel, formActionType, schema }) => {
-      return {
-        dictCode: 'getdatatype',
-        placeholder: '请选择分站用途',
-        onChange: (e: any) => {
-          const { updateSchema } = formActionType;
-          if (e == 'plc' || e == 'modbus') {
-            updateSchema({
-              field: 'plcType',
-              show: true,
-            });
-          } else {
-            updateSchema({
-              field: 'plcType',
-              show: false,
-            });
-            if (e == 'http') {
-              updateSchema({
-                label: '请求参数或读取文件名',
-                field: 'reqparam',
-                component: 'Input',
-                required: false,
-                show: true,
-              });
-            }
-          }
-        },
-      };
+    componentProps: {
+      dictCode: 'getdatatype',
+      placeholder: '请选择读取数据方式',
     },
   },
   {
@@ -161,7 +135,7 @@ export const formSchema: FormSchema[] = [
     label: 'PLC类型',
     field: 'plcType',
     component: 'JDictSelectTag',
-    show: true,
+    ifShow: ({ values }) => values.strtype === 'plc',
     componentProps: {
       dictCode: 'plcType',
       placeholder: '请选择PLC类型',
@@ -171,17 +145,20 @@ export const formSchema: FormSchema[] = [
     label: '分站站号',
     field: 'code',
     component: 'InputNumber',
+    ifShow: ({ values }) => ['modbus', 'modbusRtu'].includes(values.strtype),
   },
   {
-    label: '系统缓存点表下标',
-    field: 'plcTable',
+    label: '节点码',
+    field: 'code',
     component: 'Input',
+    ifShow: ({ values }) => values.strtype === 'opc_ua',
   },
   {
     label: '是否从0开始',
     field: 'isZeroStart',
     component: 'RadioGroup',
     defaultValue: 1,
+    ifShow: ({ values }) => ['modbus', 'modbusRtu'].includes(values.strtype),
     componentProps: () => {
       return {
         options: [
@@ -191,10 +168,20 @@ export const formSchema: FormSchema[] = [
       };
     },
   },
+  {
+    label: '分站类型',
+    field: 'reqparam',
+    component: 'Input',
+    ifShow: ({ values }) => ['modbus', 'modbusRtu'].includes(values.strtype),
+    componentProps: {
+      placeholder: '请填写158/130/235',
+    },
+  },
   {
     label: '请求方式',
     field: 'reqtype',
     component: 'JDictSelectTag',
+    ifShow: ({ values }) => values.strtype && values.strtype.startsWith('http'),
     componentProps: {
       dictCode: 'reqtype',
       placeholder: '请选择请求方式',
@@ -204,56 +191,110 @@ export const formSchema: FormSchema[] = [
     label: 'reqHeader请求头',
     field: 'reqHeader',
     component: 'Input',
+    ifShow: ({ values }) =>
+      values.strtype &&
+      (values.strtype.startsWith('http') ||
+        !['plc', 'modbus', 'modbusRtu', 'opc_ua', 'txt'].some((type) => values.strtype && values.strtype.startsWith(type))),
+  },
+  {
+    label: '请求参数',
+    field: 'reqparam',
+    component: 'Input',
+    ifShow: ({ values }) => values.strtype && values.strtype.startsWith('http'),
+  },
+  {
+    label: '读取文件名',
+    field: 'reqparam',
+    component: 'Input',
+    ifShow: ({ values }) => values.strtype && values.strtype.startsWith('txt'),
   },
   {
     label: '请求参数或读取文件名',
     field: 'reqparam',
     component: 'Input',
+    ifShow: ({ values }) =>
+      values.strtype &&
+      !['plc', 'modbus', 'modbusRtu', 'opc_ua', 'txt', 'http'].some((type) => values.strtype && values.strtype.startsWith(type)) &&
+      !values.strtype?.startsWith('http') &&
+      !values.strtype?.startsWith('txt'),
   },
   {
-    label: '数据属性字段(json中数据列表的字段-)',
+    label: '返回数据解析',
     field: 'dataproperty',
     component: 'Input',
+    ifShow: ({ values }) => values.strtype && (values.strtype.startsWith('http') || values.strtype.startsWith('txt')),
   },
   {
     label: 'ID字段',
     field: 'idcode',
     component: 'Input',
+    ifShow: ({ values }) =>
+      values.strtype &&
+      (values.strtype.startsWith('http') ||
+        values.strtype.startsWith('txt') ||
+        !['plc', 'modbus', 'modbusRtu', 'opc_ua'].some((type) => values.strtype && values.strtype.startsWith(type))),
   },
   {
     label: '名称code',
     field: 'namecode',
     component: 'Input',
+    ifShow: ({ values }) =>
+      values.strtype &&
+      (values.strtype.startsWith('http') ||
+        values.strtype.startsWith('txt') ||
+        !['plc', 'modbus', 'modbusRtu', 'opc_ua'].some((type) => values.strtype && values.strtype.startsWith(type))),
   },
   {
     label: '连接用户名',
     field: 'remoteUser',
     component: 'Input',
+    ifShow: ({ values }) =>
+      values.strtype &&
+      (values.strtype.startsWith('http') ||
+        values.strtype === 'opc_ua' ||
+        !['plc', 'modbus', 'modbusRtu', 'txt'].some((type) => values.strtype && values.strtype.startsWith(type))),
   },
   {
     label: '连接密码',
     field: 'remotePass',
     component: 'Input',
+    ifShow: ({ values }) =>
+      values.strtype &&
+      (values.strtype.startsWith('http') ||
+        values.strtype === 'opc_ua' ||
+        !['plc', 'modbus', 'modbusRtu', 'txt'].some((type) => values.strtype && values.strtype.startsWith(type))),
   },
   {
     label: '数据格式化',
     field: 'dataformat',
     component: 'Input',
+    ifShow: ({ values }) =>
+      values.strtype &&
+      (values.strtype.startsWith('http') ||
+        values.strtype.startsWith('txt') ||
+        !['plc', 'modbus', 'modbusRtu', 'opc_ua'].some((type) => values.strtype && values.strtype.startsWith(type))),
   },
   {
-    label: '字符串分割符',
+    label: '字符串分符',
     field: 'splitchar',
     component: 'Input',
+    ifShow: ({ values }) =>
+      values.strtype &&
+      (values.strtype.startsWith('http') ||
+        values.strtype.startsWith('txt') ||
+        !['plc', 'modbus', 'modbusRtu', 'opc_ua'].some((type) => values.strtype && values.strtype.startsWith(type))),
   },
   {
     label: '控制请求地址',
     field: 'controlStrip',
     component: 'Input',
+    ifShow: ({ values }) => values.strtype && values.strtype.startsWith('http'),
   },
   {
     label: '控制请求类型',
     field: 'controlReqtype',
     component: 'JDictSelectTag',
+    ifShow: ({ values }) => values.strtype && values.strtype.startsWith('http'),
     componentProps: {
       dictCode: 'reqtype',
       placeholder: '请选择控制请求方式',
@@ -263,21 +304,40 @@ export const formSchema: FormSchema[] = [
     label: '控制请求Header',
     field: 'controlHeader',
     component: 'Input',
+    ifShow: ({ values }) => values.strtype && values.strtype.startsWith('http'),
   },
   {
     label: '控制请求参数',
     field: 'controlReqparam',
     component: 'Input',
+    ifShow: ({ values }) => values.strtype && values.strtype.startsWith('http'),
   },
   {
     label: '登录地址',
     field: 'loginUrl',
     component: 'Input',
+    ifShow: ({ values }) => values.strtype && values.strtype.startsWith('http'),
   },
   {
-    label: '登录结果解析(返回的token读取字段)',
+    label: '登录结果解析',
     field: 'loginResult',
     component: 'Input',
+    ifShow: ({ values }) => values.strtype && values.strtype.startsWith('http'),
+  },
+  {
+    label: '是否自动同步设备',
+    field: 'isAutoSyn',
+    component: 'RadioGroup',
+    defaultValue: 0,
+    ifShow: ({ values }) => values.strtype && (values.strtype.startsWith('http') || values.strtype.startsWith('txt')),
+    componentProps: () => {
+      return {
+        options: [
+          { label: '否', value: 0, key: '0' },
+          { label: '是', value: 1, key: '1' },
+        ],
+      };
+    },
   },
   {
     label: '备注',

+ 955 - 769
src/views/vent/home/configurable/components/detail/ComplexList.vue

@@ -5,793 +5,979 @@
     <!-- 部分类型的列表需要加一张图片 -->
     <div :class="`list__image_${type}`"></div>
     <!-- 剩下的部分填充剩余宽度 -->
-    <div class="flex-grow" :class="`list__wrapper_${type}`">
-      <div v-for="(item, i) in listConfig" :key="`customlist${i}`" class="flex items-center" :class="`list-item_${type}`">
+    <div class="flex-grow h-full" :class="`list__wrapper_${type}`">
+      <div v-for="(item, i) in listConfig" :key="`vvhccdcl${i}`" :class="`list-item_${type}`">
         <!-- 列表项前面的图标 -->
-        <div :class="`list-item__icon_${type}`"></div>
+        <div :class="`list-item__title_${type}`">{{ item.title }}</div>
         <!-- 列表项的具体内容填充剩余宽度 -->
-        <div class="flex-grow" :class="`list-item__content_${type}`">
-          <div class="list-item__label">{{ item.label }}</div>
-          <div class="list-item__info" :class="`list-item__info_${item.color}`">{{ item.info }}</div>
-          <div class="list-item__value" :class="`list-item__value_${item.color} list-item__value_${type}`">{{ item.value }}</div>
+        <div v-for="(ctx, j) in item.contents" :key="`vvhccdclc${j}`" :class="`list-item__content_${type}`">
+          <div class="list-item__label">{{ ctx.label }}</div>
+          <div class="list-item__info" :class="`list-item__info_${ctx.color}`">{{ ctx.info }}</div>
+          <div class="list-item__value" :class="`list-item__value_${ctx.color} list-item__value_${type}`">{{ ctx.value }}</div>
         </div>
       </div>
     </div>
   </div>
 </template>
 <script lang="ts" setup>
-const props = withDefaults(
-  defineProps<{
-    listConfig: {
-      value: string;
-      color: string;
-      label: string;
-      info: string;
-    }[];
-    /** A B C D E F G */
-    type: string;
-  }>(),
-  {
-    listConfig: () => [],
-    type: 'A',
-  }
-);
-//   defineEmits(['click']);
+  withDefaults(
+    defineProps<{
+      listConfig: {
+        title: string;
+        contents: {
+          value: string;
+          color: string;
+          label: string;
+          info: string;
+        }[];
+      }[];
+      /** A B */
+      type: string;
+    }>(),
+    {
+      listConfig: () => [],
+      type: 'A',
+    }
+  );
+
+  //   defineEmits(['click']);
 </script>
 <style lang="less" scoped>
-@import '/@/design/theme.less';
-@import '/@/design/theme.less';
-/* Timeline 相关的样式 */
-@{theme-green} {
-  .list {
-    // --image-list_bg_default: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_default.png);
-    // --image-triangle_icon: url(/@/assets/images/themify/deepblue/home-container/configurable/triangle_icon.png);
-    // --image-list_bg_b: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_b.png);
-    // --image-deco_1: url(/@/assets/images/themify/deepblue/home-container/configurable/deco_1.png);
-    // --image-list_bg_c: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_c.png);
-    // --image-list_bg_defflip: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_defflip.png);
-    // --image-list_bg_d: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_d.png);
-    // --image-list_bg_s: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_s.png);
-    // --image-list_bg_e: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_e.png);
-    --image-list: url(/@/assets/images/themify/green/home-container/configurable/list_bg_f.png);
-    --image-list_bg_h: url(/@/assets/images/themify/green/home-container/configurable/list_bg_h.png);
-    --image-list_bg_i: url(/@/assets/images/themify/green/home-container/configurable/list_bg_i.png);
-    // --image-list_bg_r: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_r.png);
-  }
-}
-@{theme-deepblue} {
-  .list {
-    --image-list_bg_default: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_default.png);
-    --image-triangle_icon: url(/@/assets/images/themify/deepblue/home-container/configurable/triangle_icon.png);
-    --image-list_bg_b: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_b.png);
-    --image-deco_1: url(/@/assets/images/themify/deepblue/home-container/configurable/deco_1.png);
-    --image-list_bg_c: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_c.png);
-    --image-list_bg_defflip: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_defflip.png);
-    --image-list_bg_d: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_d.png);
-    --image-list_bg_s: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_s.png);
-    --image-list_bg_e: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_e.png);
-    --image-list: url(/@/assets/images/themify/deepblue/home-container/configurable/firehome/list.png);
-    --image-list_bg_h: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_h.png);
-    --image-list_bg_i: url('/@/assets/images/themify/deepblue/home-container/configurable/list_bg_i.png');
-    --image-list_bg_r: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_r.png);
-  }
-}
-
-.list {
-  --image-list_bg_default: url(/@/assets/images/home-container/configurable/list_bg_default.png);
-  --image-triangle_icon: url(/@/assets/images/home-container/configurable/triangle_icon.png);
-  --image-list_bg_b: url(/@/assets/images/home-container/configurable/list_bg_b.png);
-  --image-deco_1: url(/@/assets/images/home-container/configurable/deco_1.png);
-  --image-list_bg_c: url(/@/assets/images/home-container/configurable/list_bg_c.png);
-  --image-list_bg_defflip: url(/@/assets/images/home-container/configurable/list_bg_defflip.png);
-  --image-list_bg_d: url(/@/assets/images/home-container/configurable/list_bg_d.png);
-  --image-list_bg_s: url(/@/assets/images/home-container/configurable/list_bg_s.png);
-  --image-list_bg_e: url(/@/assets/images/home-container/configurable/list_bg_e.png);
-  --image-list: url(/@/assets/images/home-container/configurable/firehome/list.png);
-  --image-list_bg_h: url(/@/assets/images/home-container/configurable/list_bg_h.png);
-  --image-list_bg_r: url(/@/assets/images/home-container/configurable/list_bg_r.png);
-  --image-list_bg_r_icon1: url(/@/assets/images/home-container/configurable/list_bg_r_icon1.png);
-  --image-list_bg_r_icon2: url(/@/assets/images/home-container/configurable/list_bg_r_icon2.png);
-  --image-list_bg_i: url('/@/assets/images/home-container/configurable/list_bg_i.png');
-  --image-list_bg_j: url('/@/assets/images/home-container/configurable/list_bg_j.png');
-  --image-linear-gradient-3: linear-gradient(to right, #39deff15, #3977e500);
-  --image-list_icon_l1: url('/@/assets/images/home-container/configurable/minehome/list-icon-wd.png');
-  --image-list_icon_l2: url('/@/assets/images/home-container/configurable/minehome/list-icon-CO.png');
-  --image-list_icon_l3: url('/@/assets/images/home-container/configurable/minehome/list-icon-yw.png');
-  --image-list_icon_l4: url('/@/assets/images/home-container/configurable/minehome/list-icon-hy.png');
-  --image-list_icon_m1: url('/@/assets/images/home-container/configurable/minehome/list-icon-co1.png');
-  --image-list_icon_m2: url('/@/assets/images/home-container/configurable/minehome/list-icon-co2.png');
-  --image-list_icon_m3: url('/@/assets/images/home-container/configurable/minehome/list-icon-ch4.png');
-  --image-list_icon_m4: url('/@/assets/images/home-container/configurable/minehome/list-icon-c2h2.png');
-  --image-list_icon_m5: url('/@/assets/images/home-container/configurable/minehome/list-icon-o2.png');
-  --image-list_icon_m6: url('/@/assets/images/home-container/configurable/minehome/list-icon-c2h4.png');
-  --image-list_icon_m7: url('/@/assets/images/home-container/configurable/minehome/list-icon-n2.png');
-  --image-list_icon_m8: url('/@/assets/images/home-container/configurable/minehome/list-icon-h2.png');
-  --image-list_bg_l1: url('/@/assets/images/home-container/configurable/minehome/list-bg-l1.png');
-  --image-list_bg_l2: url('/@/assets/images/home-container/configurable/minehome/list-bg-l2.png');
-  --image-list_bg_m1: url('/@/assets/images/home-container/configurable/minehome/list-bg-m1.png');
-  --image-list_bg_m2: url('/@/assets/images/home-container/configurable/minehome/list-bg-m2.png');
-  --image-list_bg_n1: url('/@/assets/images/home-container/configurable/minehome/list-bg-n1.png');
-  --image-list_bg_n2: url('/@/assets/images/home-container/configurable/minehome/list-bg-n2.png');
-  --image-list_bg_n3: url('/@/assets/images/home-container/configurable/minehome/list-bg-n3.png');
-  --image-list_bg_n4: url('/@/assets/images/home-container/configurable/minehome/list-bg-n4.png');
-  --image-list_bg_o1: url('/@/assets/images/beltFire/listO1.png');
-  --image-list_bg_o2: url('/@/assets/images/beltFire/listO2.png');
-  --image-list_icon_o1: url('/@/assets/images/beltFire/listO1.svg');
-  --image-list_icon_o2: url('/@/assets/images/beltFire/listO2.svg');
-  padding: 5px 20px;
-  position: relative;
-  background-repeat: no-repeat;
-  width: 100%;
-  height: 100%;
-  background-size: 100% 100%;
-  background-image: var(--image-list_bg_default);
-}
-
-.list_A {
-  padding-left: 5px;
-}
-.list-item__content_A {
-  background-repeat: no-repeat;
-  background-image: @vent-gas-list-item-bg-img;
-  // padding: 5px 10px;
-  display: flex;
-}
-.list-item__icon_A {
-  background-repeat: no-repeat;
-  width: 25px;
-  height: 29px;
-  background-image: var(--image-triangle_icon);
-}
-
-.list-item__content_B {
-  background-repeat: no-repeat;
-  padding: 5px 10px 10px 10px;
-  display: flex;
-  background-position: left bottom;
-  background-size: 100% auto;
-  background-image: var(--image-list_bg_b);
-}
-.list__image_B {
-  width: 77px;
-  height: 77px;
-  background-repeat: no-repeat;
-  background-image: var(--image-deco_1);
-  background-size: auto;
-  margin-right: 20px;
-}
-
-.list_C {
-  background: none;
-}
-.list-item__content_C {
-  height: 60px;
-  background-repeat: no-repeat;
-  padding: 25px 50px 0 50px;
-  display: flex;
-  background-position: center;
-  background-size: 100% 100%;
-  background-image: var(--image-list_bg_c);
-  margin-bottom: 10px;
-  text-align: center;
-}
-.list-item__content_C > div {
-  flex-basis: 33.3%;
-}
-
-.list_D {
-  background-image: var(--image-list_bg_defflip);
-}
-.list__wrapper_D {
-  display: flex;
-  flex-wrap: wrap;
-}
-.list-item__icon_D {
-  display: none;
-}
-.list-item_D {
-  flex-basis: 25%;
-  height: 60px;
-  background-repeat: no-repeat;
-  background-position: center;
-  background-size: auto 100%;
-  background-image: var(--image-list_bg_d);
-  text-align: center;
-  margin-bottom: 10px;
-}
-
-.list-item__content_D {
-  line-height: 30px;
-}
-.list-item__value_D {
-  font-weight: bold;
-}
-
-.list_S {
-  background: none;
-}
-.list__wrapper_S {
-  display: grid;
-  grid-template-columns: repeat(2, 1fr); /* 2列均等 */
-  gap: 10px;
-}
-.list-item_S {
-  height: 45px;
-  background-repeat: no-repeat;
-  background-position: center;
-  background-size: 100% 100%;
-  background-image: var(--image-list_bg_s);
-  text-align: center;
-  padding: 0 7px;
-}
-.list-item__content_S {
-  display: flex;
-}
-.list-item__value_S {
-  font-family: 'douyuFont';
-  font-size: 13px;
-  color: @vent-gas-primary-text;
-  padding-top: 3px;
-}
-.list_E {
-  background-image: var(--image-list_bg_defflip);
-}
-.list__wrapper_E {
-  display: flex;
-  flex-wrap: wrap;
-}
-.list-item__icon_E {
-  display: none;
-}
-.list-item_E {
-  flex-basis: 25%;
-  height: 70px;
-  background-repeat: no-repeat;
-  background-position: center;
-  background-size: auto 100%;
-  background-image: var(--image-list_bg_e);
-  text-align: center;
-  margin: 5px 0px;
-  padding-top: 32px;
-  font-size: 12px;
-}
-
-.list_F {
-  background: none;
-}
-.list-item__content_F {
-  height: 40px;
-  background-repeat: no-repeat;
-  padding: 0 50px 0 50px;
-  display: flex;
-  background-position: center;
-  background-size: 100% auto;
-  background-image: var(--image-list);
-  margin-top: 10px;
-  text-align: center;
-}
-.list-item__content_F > div {
-  flex-basis: 33.3%;
-}
-
-.list_G {
-  background: none;
-}
-.list__wrapper_G {
-  display: flex;
-  flex-wrap: wrap;
-  justify-content: space-between;
-}
-.list-item_G {
-  width: 130px;
-  height: 80px;
-  align-items: center;
-  text-align: center;
-  border: 1px solid rgba(25, 237, 255, 0.4);
-  box-shadow: inset 0 0 10px rgba(0, 197, 255, 0.6);
-  background: rgba(0, 0, 0, 0.1);
-  margin: 5px 10px;
-}
-.list-item__content_G {
-  position: relative;
-  width: 100%;
-  height: 100%;
-}
-.list-item__content_G > .list-item__label {
-  width: 60px;
-  height: 100%;
-  left: 0;
-  position: absolute;
-  font-size: 20px;
-  line-height: 80px;
-}
-.list-item__content_G > .list-item__info {
-  width: 70px;
-  height: 30px;
-  line-height: 30px;
-  right: 0;
-  position: absolute;
-}
-.list-item__content_G > .list-item__value {
-  width: 70px;
-  height: 50px;
-  line-height: 50px;
-  top: 30px;
-  right: 0;
-  position: absolute;
-  text-shadow: 0 0 25px #00fbfe;
-  background: linear-gradient(0deg, #45d3fd, #45d3fd, #61ddb1, #61ddb1);
-  font-style: normal;
-  background-size: cover;
-  font-family: electronicFont;
-  font-size: 30px;
-  -webkit-background-clip: text;
-  background-clip: text;
-  -webkit-text-fill-color: transparent;
-  font-family: Arial, Helvetica, sans-serif;
-  font-size: 18px;
-  color: aliceblue;
-}
-
-.list_H {
-  background: none;
-}
-.list-item__content_H {
-  height: 50px;
-  background-repeat: no-repeat;
-  padding: 20px 50px 0 50px;
-  display: flex;
-  background-position: bottom;
-  background-size: 100% auto;
-  background-image: var(--image-list_bg_h);
-  margin-bottom: 10px;
-  text-align: center;
-}
-.list-item__content_H > div {
-  flex-basis: 33.3%;
-}
-
-.list-item__icon_R {
-  width: 24px;
-  height: 25px;
-  background-image: var(--image-list_bg_r_icon1);
-  background-repeat: no-repeat;
-  background-position: center;
-  background-size: contain;
-  margin-bottom: 5px;
-  position: absolute;
-  left: 35px;
-}
-.list-item_R:last-of-type .list-item__icon_R {
-  background-image: var(--image-list_bg_r_icon2);
-}
-.list_R {
-  background: none;
-}
-.list-item__content_R {
-  height: 52px;
-  background-repeat: no-repeat;
-  padding: 0 30px;
-  display: flex;
-  background-position: bottom;
-  background-size: 100% 100%;
-  background-image: var(--image-list_bg_r);
-  text-align: center;
-  align-items: center;
-  .list-item__label {
-    font-size: 15px;
-  }
-  .list-item__value_R {
-    font-family: 'douyuFont';
-    font-size: 15px;
-    padding-top: 5px;
-    color: #00bfff;
-  }
-}
-.list-item__content_R > div {
-  flex-basis: 33.3%;
-}
-
-.list_fireList {
-  background: none;
-}
-.list__wrapper_fireList {
-  display: flex;
-  flex-wrap: wrap;
-  justify-content: flex-start;
-  margin-left: 86px;
-}
-.list-item_fireList {
-  width: 167px;
-  height: 58px;
-  align-items: center;
-  text-align: center;
-  background-image: var(--image-list_bg_i);
-  background-repeat: no-repeat;
-  background-size: auto 100%;
-  margin: 5px 10px;
-}
-.list-item__content_fireList {
-  position: relative;
-  width: 100%;
-  height: 100%;
-}
-.list-item__content_fireList > .list-item__label {
-  width: 60px;
-  height: 100%;
-  left: 0;
-  position: absolute;
-  font-size: 20px;
-  line-height: 63px;
-  color: #009bff;
-}
-.list-item__content_fireList > .list-item__info {
-  height: 50%;
-  left: 70px;
-  position: absolute;
-}
-.list-item__content_fireList > .list-item__value {
-  top: 50%;
-  height: 50%;
-  left: 70px;
-  position: absolute;
-  font-size: 18px;
-}
-.list_I {
-  background: none;
-}
-.list__wrapper_I {
-  display: flex;
-  flex-wrap: wrap;
-  justify-content: flex-start;
-}
-.list-item_I {
-  width: 160px;
-  height: 63px;
-  align-items: center;
-  text-align: center;
-  background-image: var(--image-list_bg_i);
-  background-repeat: no-repeat;
-  background-size: auto 100%;
-  margin: 5px 10px;
-}
-.list-item__content_I {
-  position: relative;
-  width: 100%;
-  height: 100%;
-}
-.list-item__content_I > .list-item__label {
-  width: 60px;
-  height: 100%;
-  left: 0;
-  position: absolute;
-  font-size: 20px;
-  line-height: 63px;
-  color: #009bff;
-}
-.list-item__content_I > .list-item__info {
-  height: 50%;
-  left: 70px;
-  position: absolute;
-}
-.list-item__content_I > .list-item__value {
-  top: 50%;
-  height: 50%;
-  left: 70px;
-  position: absolute;
-  font-size: 18px;
-}
-.list_J {
-  background: unset;
-  padding: 0 5px 0 10px;
-}
-.list-item_J {
-  width: 312px;
-  height: 57px;
-  align-items: center;
-  text-align: center;
-  background-image: var(--image-list_bg_j);
-  background-repeat: no-repeat;
-  background-size: auto 100%;
-  margin: 5px 10px;
-}
-.list-item__content_J {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  padding: 0 20px 0 15px;
-}
-.list_K {
-  background: unset;
-  padding: 0 5px 0 10px;
-}
-.list__wrapper_K {
-  height: 100%;
-}
-.list-item__content_K {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  padding: 5px;
-  margin: 4px 0;
-  background-image: var(--image-linear-gradient-3);
-
-  .list-item__value {
-    flex-basis: unset;
+    @import '@/design/theme.less';
+    @import '@/design/theme.less';
+    /* Timeline 相关的样式 */
+
+    @{theme-green} {
+      .list {
+        --image-list: url(/@/assets/images/themify/green/home-container/configurable/list_bg_f.png);
+        --image-list_bg_h: url(/@/assets/images/themify/green/home-container/configurable/list_bg_h.png);
+        --image-list_bg_i: url(/@/assets/images/themify/green/home-container/configurable/list_bg_i.png);
+      }
+    }
+    @{theme-deepblue} {
+      .list {
+      --image-img-3: url(/@/assets/images/themify/deepblue/home-container/configurable/firehome/img-3.png);
+      --image-img-7: url(/@/assets/images/themify/deepblue/home-container/configurable/firehome/img-7.png);
+      --image-img-8: url(/@/assets/images/themify/deepblue/home-container/configurable/firehome/img-8.png);
+      --image-img-9: url(/@/assets/images/themify/deepblue/home-container/configurable/firehome/img-9.png);
+      --image-list_bg_1: url(/@/assets/images/themify/deepblue/home-container/configurable/dusthome/list_bg_1.png);
+      --image-list_bg_default: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_default.png);
+      --image-triangle_icon: url(/@/assets/images/themify/deepblue/home-container/configurable/triangle_icon.png);
+      --image-list_bg_b: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_b.png);
+      --image-deco_1: url(/@/assets/images/themify/deepblue/home-container/configurable/deco_1.png);
+      --image-list_bg_c: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_c.png);
+      --image-list_bg_defflip: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_defflip.png);
+      --image-list_bg_d: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_d.png);
+      --image-list_bg_s: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_s.png);
+      --image-list_bg_e: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_e.png);
+      --image-list: url(/@/assets/images/themify/deepblue/home-container/configurable/firehome/list.png);
+      --image-list_bg_h: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_h.png);
+      --image-list_bg_i: url('/@/assets/images/themify/deepblue/home-container/configurable/list_bg_i.png');
+      --image-list_bg_r: url(/@/assets/images/themify/deepblue/home-container/configurable/list_bg_r.png);
+      }
+    }
+
+    .list {
+      --image-img-3: url(/@/assets/images/home-container/configurable/firehome/img-3.png);
+      --image-img-7: url(/@/assets/images/home-container/configurable/firehome/img-7.png);
+      --image-img-8: url(/@/assets/images/home-container/configurable/firehome/img-8.png);
+      --image-img-9: url(/@/assets/images/home-container/configurable/firehome/img-9.png);
+      --image-list_bg_1: url(/@/assets/images/home-container/configurable/dusthome/list_bg_1.png);
+      --image-linear-gradient-1: linear-gradient(to right, #39a3ff50, #39a3ff00);
+      --image-linear-gradient-2: linear-gradient(to right, #3df6ff40, #3df6ff00);
+      --image-linear-gradient-3: linear-gradient(to right, #39deff15, #3977e500);
+      --image-list_bg_default: url(/@/assets/images/home-container/configurable/list_bg_default.png);
+      --image-triangle_icon: url(/@/assets/images/home-container/configurable/triangle_icon.png);
+      --image-list_bg_b: url(/@/assets/images/home-container/configurable/list_bg_b.png);
+      --image-deco_1: url(/@/assets/images/home-container/configurable/deco_1.png);
+      --image-list_bg_c: url(/@/assets/images/home-container/configurable/list_bg_c.png);
+      --image-list_bg_defflip: url(/@/assets/images/home-container/configurable/list_bg_defflip.png);
+      --image-list_bg_d: url(/@/assets/images/home-container/configurable/list_bg_d.png);
+      --image-list_bg_s: url(/@/assets/images/home-container/configurable/list_bg_s.png);
+      --image-list_bg_e: url(/@/assets/images/home-container/configurable/list_bg_e.png);
+      --image-list: url(/@/assets/images/home-container/configurable/firehome/list.png);
+      --image-list_bg_h: url(/@/assets/images/home-container/configurable/list_bg_h.png);
+      --image-list_bg_r: url(/@/assets/images/home-container/configurable/list_bg_r.png);
+      --image-list_bg_r_icon1: url(/@/assets/images/home-container/configurable/list_bg_r_icon1.png);
+      --image-list_bg_r_icon2: url(/@/assets/images/home-container/configurable/list_bg_r_icon2.png);
+      --image-list_bg_i: url('/@/assets/images/home-container/configurable/list_bg_i.png');
+      --image-list_bg_j: url('/@/assets/images/home-container/configurable/list_bg_j.png');
+      --image-list_icon_l1: url('/@/assets/images/home-container/configurable/minehome/list-icon-wd.png');
+      --image-list_icon_l2: url('/@/assets/images/home-container/configurable/minehome/list-icon-CO.png');
+      --image-list_icon_l3: url('/@/assets/images/home-container/configurable/minehome/list-icon-yw.png');
+      --image-list_icon_l4: url('/@/assets/images/home-container/configurable/minehome/list-icon-hy.png');
+      --image-list_icon_m1: url('/@/assets/images/home-container/configurable/minehome/list-icon-co1.png');
+      --image-list_icon_m2: url('/@/assets/images/home-container/configurable/minehome/list-icon-co2.png');
+      --image-list_icon_m3: url('/@/assets/images/home-container/configurable/minehome/list-icon-ch4.png');
+      --image-list_icon_m4: url('/@/assets/images/home-container/configurable/minehome/list-icon-c2h2.png');
+      --image-list_icon_m5: url('/@/assets/images/home-container/configurable/minehome/list-icon-o2.png');
+      --image-list_icon_m6: url('/@/assets/images/home-container/configurable/minehome/list-icon-c2h4.png');
+      --image-list_icon_m7: url('/@/assets/images/home-container/configurable/minehome/list-icon-n2.png');
+      --image-list_icon_m8: url('/@/assets/images/home-container/configurable/minehome/list-icon-h2.png');
+      --image-list_bg_l1: url('/@/assets/images/home-container/configurable/minehome/list-bg-l1.png');
+      --image-list_bg_l2: url('/@/assets/images/home-container/configurable/minehome/list-bg-l2.png');
+      --image-list_bg_m1: url('/@/assets/images/home-container/configurable/minehome/list-bg-m1.png');
+      --image-list_bg_m2: url('/@/assets/images/home-container/configurable/minehome/list-bg-m2.png');
+      --image-list_bg_n1: url('/@/assets/images/home-container/configurable/minehome/list-bg-n1.png');
+      --image-list_bg_n2: url('/@/assets/images/home-container/configurable/minehome/list-bg-n2.png');
+      --image-list_bg_n3: url('/@/assets/images/home-container/configurable/minehome/list-bg-n3.png');
+      --image-list_bg_n4: url('/@/assets/images/home-container/configurable/minehome/list-bg-n4.png');
+      --image-list_bg_o1: url('/@/assets/images/beltFire/listO1.png');
+      --image-list_bg_o2: url('/@/assets/images/beltFire/listO2.png');
+      --image-list_icon_o1: url('/@/assets/images/beltFire/listO1.svg');
+      --image-list_icon_o2: url('/@/assets/images/beltFire/listO2.svg');
+      padding: 5px 20px;
+      position: relative;
+      width: 100%;
+      height: 100%;
+    }
+
+    .list-item_A {
+      position: relative;
+      height: 140px;
+      background-repeat: no-repeat;
+      background-image: var(--image-img-3);
+      background-size: auto 100%;
+      background-position: center;
+    }
+    .list-item__title_A {
+      position: absolute;
+      left: 41%;
+      // font-size: 14px;
+      top: 15px;
+    }
+    // .list-item__content_A {
+    //   position: absolute;
+    //   left: 35%;
+    //   top: 55px;
+    //   display: flex;
+    //   justify-content: space-evenly;
+    // }
+    .list-item__content_A:nth-of-type(2) {
+      position: absolute;
+      top: 15px;
+      left: 14%;
+      width: 22%;
+      text-align: center;
+      display: block;
+
+      .list-item__label {
+        font-size: 18px;
+        margin-bottom: 25px;
+      }
+      .list-item__info {
+        display: none;
+      }
+      .list-item__value {
+        font-size: 24px;
+      }
+    }
+    .list-item__content_A:nth-of-type(3) {
+      position: absolute;
+      left: 41%;
+      top: 55px;
+
+      .list-item__info {
+        display: none;
+      }
+      .list-item__value {
+        font-size: 20px;
+      }
+    }
+    .list-item__content_A:nth-of-type(4) {
+      position: absolute;
+      left: 66%;
+      top: 55px;
+
+      .list-item__info {
+        display: none;
+      }
+      .list-item__value {
+        font-size: 20px;
+      }
+    }
+    .list-item__content_A:nth-of-type(5) {
+      position: absolute;
+      left: 35%;
+      bottom: 10px;
+      display: flex;
+      align-items: center;
+
+      .list-item__info {
+        display: none;
+      }
+      .list-item__value {
+        font-size: 20px;
+        margin-left: 5px;
+      }
+    }
+
+    .list-item_B {
+      // height: 155px;
+      background-repeat: no-repeat;
+      // background-size: 100% 100%;
+      // background-size: auto 100%;
+      background-size: 87% auto;
+      background-position: center;
+      background-image: var(--image-img-7);
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      text-align: center;
+      padding: 0 10%;
+      margin-top: 5px;
+      height: 33px;
+
+      .list-item__label {
+        font-size: 11px;
+      }
+      .list-item__value {
+        font-size: 18px;
+        margin-left: 5px;
+      }
+      .list-item__content_B {
+        height: 100%;
+        display: flex;
+        align-items: center;
+        flex-basis: 100px;
+        flex-grow: 1;
+      }
+      .list-item__title_B {
+        width: 40px;
+        text-align: center;
+        margin-right: 50px
+        // height: 30px;
+        // background-size: auto 80%;
+        // background-position: center;
+        // background-repeat: no-repeat;
+      }
+      .list-item__info {
+        display: none;
+      }
+    }
+
+    .list_C {
+      padding: 5px 10px;
+    }
+
+    .list__wrapper_C {
+      display: flex;
+      justify-content: space-between;
+      flex-wrap: wrap;
+    }
+
+    .list-item_C {
+      position: relative;
+      height: 140px;
+      width: 200px;
+      background-repeat: no-repeat;
+      background-image: var(--image-img-8);
+      background-size: 100% 100%;
+      background-position: left center;
+    }
+    .list-item__title_C {
+      position: absolute;
+      left: 99px;
+      // font-size: 14px;
+      top: 15px;
+    }
+    .list-item__content_C:nth-of-type(2) {
+      position: absolute;
+      top: 15px;
+      left: 19px;
+      width: 30%;
+      text-align: center;
+      display: block;
+
+      .list-item__label {
+        // font-size: 18px;
+        margin-bottom: 25px;
+      }
+      .list-item__info {
+        display: none;
+      }
+      .list-item__value {
+        font-size: 18px;
+      }
+    }
+    .list-item__content_C:nth-of-type(3) {
+      position: absolute;
+      left: 99px;
+      top: 55px;
+
+      .list-item__info {
+        display: none;
+      }
+      .list-item__value {
+        font-size: 18px;
+      }
+    }
+
+
+    .list_D {
+      padding: 5px 10px;
+    }
+
+    .list__wrapper_D {
+      display: flex;
+      justify-content: space-between;
+      flex-wrap: wrap;
+    }
+
+    .list-item_D {
+      position: relative;
+      height: 110px;
+      width: 200px;
+      background-repeat: no-repeat;
+      background-image: var(--image-img-9);
+      background-size: 100% auto;
+      background-position: center top;
+      text-align: center;
+      margin-bottom: 20px;
+    }
+    .list-item__title_D {
+      position: absolute;
+      width: 100%;
+      bottom: 0;
+      font-size: 16px;
+      font-weight: bold;
+    }
+    .list-item__content_D:nth-of-type(2) {
+      position: absolute;
+      top: 10%;
+      left: 10%;
+      width: 30%;
+      text-align: center;
+
+      .list-item__info {
+        display: none;
+      }
+      .list-item__value {
+        font-size: 18px;
+      }
+    }
+    .list-item__content_D:nth-of-type(3) {
+      position: absolute;
+      top: 10%;
+      right: 10%;
+      width: 30%;
+      text-align: center;
+
+      .list-item__info {
+        display: none;
+      }
+      .list-item__value {
+        font-size: 18px;
+      }
+    }
+
+  .list_E {
+    padding: 5px 10px;
   }
-  .list-item__label {
-    flex-basis: unset;
+
+  .list__wrapper_E {
+    display: flex;
+    justify-content: space-between;
+    flex-wrap: wrap;
+    padding: 0 10px;
   }
-  .list-item__info {
-    display: none;
+
+  .list-item_E {
+    position: relative;
+    height: 104px;
+    width: 188px;
+    background-repeat: no-repeat;
+    background-image: var(--image-list_bg_1);
+    background-size: 100% auto;
+    background-position: center top;
+    text-align: center;
+    margin-bottom: 20px;
   }
-}
-
-.list_L {
-  background: none;
-  padding: 5px 10px;
-}
-.list-item_L {
-  width: 100%;
-  height: 37px;
-  background-repeat: no-repeat;
-  background-size: auto 100%;
-  margin-bottom: 8px;
-}
-/* 奇数项背景图 */
-.list-item_L:nth-child(odd) {
-  background-image: var(--image-list_bg_l1);
-}
-
-/* 偶数项背景图 */
-.list-item_L:nth-child(even) {
-  background-image: var(--image-list_bg_l2);
-}
-.list-item__icon_L {
-  background-repeat: no-repeat;
-  width: 16px;
-  height: 20px;
-  margin-left: 15px;
-  background-position: center;
-  background-size: contain;
-}
-/* 四个图标样式 */
-.list-item_L:nth-child(1) .list-item__icon_L {
-  background-image: var(--image-list_icon_l1);
-}
-
-.list-item_L:nth-child(2) .list-item__icon_L {
-  background-image: var(--image-list_icon_l2);
-}
-
-.list-item_L:nth-child(3) .list-item__icon_L {
-  background-image: var(--image-list_icon_l3);
-}
-
-.list-item_L:nth-child(4) .list-item__icon_L {
-  background-image: var(--image-list_icon_l4);
-}
-.list-item__content_L {
-  display: flex;
-  text-align: center;
-  align-items: center;
-  .list-item__value_L {
-    font-family: 'douyuFont';
+  .list-item__title_E {
+    // position: absolute;
+    width: 100%;
+    // top: 0;
+    font-size: 16px;
+    font-weight: bold;
+    margin-top: 10px;
   }
-}
-.list-item__content_L > div {
-  flex-basis: 33.3%;
-}
-
-.list_M {
-  background: none;
-  padding: 0;
-}
-.list__wrapper_M {
-  display: grid;
-  grid-template-columns: 1fr 1fr; /* 两列均等 */
-  gap: 18px; /* 统一间距 */
-}
-.list-item_M {
-  height: 37px;
-  background-repeat: no-repeat;
-  background-size: 100% 100%;
-}
-.list-item_M:nth-child(1),
-.list-item_M:nth-child(4),
-.list-item_M:nth-child(5),
-.list-item_M:nth-child(8) {
-  background-image: var(--image-list_bg_m1);
-}
-
-.list-item_M:nth-child(2),
-.list-item_M:nth-child(3),
-.list-item_M:nth-child(6),
-.list-item_M:nth-child(7) {
-  background-image: var(--image-list_bg_m2);
-}
-.list-item_M:nth-child(7),
-.list-item_M:nth-child(8) {
-  margin-bottom: 0;
-}
-.list-item__icon_M {
-  background-repeat: no-repeat;
-  height: 16px;
-  margin-left: 5px;
-  background-position: center;
-  background-size: auto 100%;
-  display: inline-block;
-  width: 40px;
-}
-/* 八个图标样式 */
-.list-item_M:nth-child(1) .list-item__icon_M {
-  background-image: var(--image-list_icon_m1);
-}
-.list-item_M:nth-child(2) .list-item__icon_M {
-  background-image: var(--image-list_icon_m2);
-}
-.list-item_M:nth-child(3) .list-item__icon_M {
-  background-image: var(--image-list_icon_m3);
-}
-.list-item_M:nth-child(4) .list-item__icon_M {
-  background-image: var(--image-list_icon_m4);
-}
-.list-item_M:nth-child(5) .list-item__icon_M {
-  background-image: var(--image-list_icon_m5);
-}
-.list-item_M:nth-child(6) .list-item__icon_M {
-  background-image: var(--image-list_icon_m6);
-}
-.list-item_M:nth-child(7) .list-item__icon_M {
-  background-image: var(--image-list_icon_m7);
-}
-.list-item_M:nth-child(8) .list-item__icon_M {
-  background-image: var(--image-list_icon_m8);
-}
-
-.list-item__content_M {
-  display: flex;
-  text-align: center;
-  align-items: center;
-
-  .list-item__value_M {
-    font-family: 'douyuFont';
-    font-size: 12px;
+  .list-item__content_E:nth-of-type(2) {
+    position: absolute;
+    top: 40%;
+    left: 5%;
+    text-align: left;
+
+    .list-item__info {
+      display: none;
+    }
+    .list-item__value {
+      font-size: 16px;
+    }
   }
-}
-.list_N {
-  background: none;
-  padding: 5px 10px;
-}
-.list-item_N {
-  width: 100%;
-  height: 42px;
-  background-repeat: no-repeat;
-  background-size: 100% 100%;
-  margin-bottom: 15px;
-}
-/* 四个背景样式 */
-.list-item_N:nth-child(1) {
-  background-image: var(--image-list_bg_n1);
-}
-
-.list-item_N:nth-child(2) {
-  background-image: var(--image-list_bg_n2);
-  .list-item__value_N {
-    color: #27cab7;
+  .list-item__content_E:nth-of-type(3) {
+    position: absolute;
+    top: 40%;
+    right: 5%;
+    text-align: right;
+
+    .list-item__info {
+      display: none;
+    }
+    .list-item__value {
+      font-size: 16px;
+    }
   }
-}
 
-.list-item_N:nth-child(3) {
-  background-image: var(--image-list_bg_n3);
-}
+  .list-item_F {
+      // height: 155px;
+      background-repeat: no-repeat;
+      background-size: 100% 100%;
+      // background-size: auto 100%;
+      background-position: center;
+      background-image: @vent-gas-list-item-bg-img;
+      display: flex;
+      align-items: center;
+      // justify-content: space-between;
+      // text-align: center;
+      padding: 0 5%;
+      margin-top: 5px;
+      height: 50px;
 
-.list-item_N:nth-child(4) {
-  background-image: var(--image-list_bg_n4);
-  .list-item__value_N {
-    color: #27cab7;
+      .list-item__title_F {
+        flex-basis: 25%;
+      }
+      .list-item__content_F {
+        flex-basis: 25%;
+      }
+      .list-item__label::after {
+        content: ':';
+      }
+      .list-item__value {
+        font-size: 18px;
+        margin-left: 5px;
+        font-weight: bold;
+      }
+      .list-item__content_F {
+        display: flex;
+        align-items: center;
+      }
+      .list-item__info {
+        display: none;
+      }
   }
-}
-.list-item__content_N {
-  display: flex;
-  text-align: center;
-  align-items: center;
-  .list-item__value_N {
-    font-family: 'douyuFont';
+
+  .list-item_G {
+      // height: 155px;
+      // background-repeat: no-repeat;
+      // background-size: 100% 100%;
+      // background-position: center;
+      // justify-content: space-between;
+      // text-align: center;
+      margin-top: 5px;
+
+      .list-item__title_G {
+        position: relative;
+        width: 100%;
+        height: 16px;
+        margin-top: 10px;
+        margin-bottom: 5px;
+        padding-left: 8px;
+        top: -2px;
+        background-image: var(--image-linear-gradient-1);
+        &::before{
+          position: absolute;
+          content: '';
+          width: 100%;
+          height: 100%;
+          top: 4px;
+          left: 0;
+          background-image: var(--image-linear-gradient-2);
+        }
+      }
+      .list-item__content_G {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        padding: 4px;
+        margin: 8px 0;
+        background-image: var(--image-linear-gradient-3);
+      }
   }
-}
-.list-item__content_N > div:last-child {
-  flex-basis: 60%;
-}
-
-.list_U {
-  background: none;
-  padding: 0px 20px;
-}
-.list__wrapper_U {
-  display: flex;
-  flex-direction: row;
-  gap: 10px;
-}
-.list-item_U {
-  width: 80%;
-  height: 42px;
-  position: relative;
-  display: flex;
-  align-items: center;
-}
-
-/* 左右两个背景图(你可以自己换图) */
-.list-item_U:nth-child(odd) {
-  background: var(--image-list_bg_o1);
-  background-size: 100% 100%;
-  background-repeat: no-repeat;
-}
-.list-item_U:nth-child(even) {
-  background: var(--image-list_bg_o2);
-  background-size: 100% 100%;
-  background-repeat: no-repeat;
-}
-
-.list-item__icon_U {
-  width: 24px;
-  height: 24px;
-  margin-left: 12px;
-  background-position: center;
-  background-size: contain;
-  background-repeat: no-repeat;
-}
-
-.list-item_U:nth-child(1) .list-item__icon_U {
-  background-image: var(--image-list_icon_o1);
-}
-.list-item_U:nth-child(2) .list-item__icon_U {
-  background-image: var(--image-list_icon_o2);
-}
-.list-item__content_U {
-  flex: 1;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  padding: 0 50px 0 15px;
-}
-.list-item__content_U > .list-item__label {
-  font-weight: bold;
-  margin-left: 20px;
-}
-.list-item__value_U {
-  font-family: 'douyuFont';
-  color: #ffffff;
-}
-
-.list-item__label {
-  flex-basis: 55%;
-}
-.list-item__info {
-  flex-grow: 1;
-}
-.list-item__value {
-  flex-basis: 30%;
-}
-.list-item__value_red {
-  color: red;
-}
-.list-item__value_orange {
-  color: orange;
-}
-.list-item__value_yellow {
-  color: yellow;
-}
-.list-item__value_green {
-  color: yellowgreen;
-}
-.list-item__value_blue {
-  color: @vent-table-action-link;
-}
-.list-item__value_white {
-  color: white;
-}
-.gallery-item__value_lightblue {
-  color: @vent-configurable-home-light-border;
-}
+
+    // .list-item__title_B_O2 {
+    //   background-image: url(/@/assets/images/home-container/configurable/firehome/O₂.png);
+    // }
+    // .list-item__title_B_CH4 {
+    //   background-image: url(/@/assets/images/home-container/configurable/firehome/CH₄.png);
+    // }
+    // .list-item__title_B_CO {
+    //   background-image: url(/@/assets/images/home-container/configurable/firehome/CO.png);
+    // }
+    // .list-item__title_B_CO2 {
+    //   background-image: url(/@/assets/images/home-container/configurable/firehome/CO₂.png);
+    // }
+
+    // .list-item__label {
+    //   flex-basis: 55%;
+    // }
+    // .list-item__info {
+    //   flex-grow: 1;
+    // }
+    // .list-item__value {
+    //   flex-basis: 30%;
+    // }
+    /* ===== 后续新增的类型样式 (H, I, J, K, L, M, N, S, R, U, fireList) ===== */
+    .list_S {
+      background: none;
+    }
+    .list__wrapper_S {
+      display: grid;
+      grid-template-columns: repeat(2, 1fr); /* 2列均等 */
+      gap: 10px;
+    }
+    .list-item_S {
+      height: 45px;
+      background-repeat: no-repeat;
+      background-position: center;
+      background-size: 100% 100%;
+      background-image: var(--image-list_bg_s);
+      text-align: center;
+      padding: 0 7px;
+    }
+    .list-item__content_S {
+      display: flex;
+    }
+    .list-item__value_S {
+      font-family: 'douyuFont';
+      font-size: 13px;
+      color: @vent-gas-primary-text;
+      padding-top: 3px;
+    }
+
+    .list_H {
+      background: none;
+    }
+    .list-item__content_H {
+      height: 50px;
+      background-repeat: no-repeat;
+      padding: 20px 50px 0 50px;
+      display: flex;
+      background-position: bottom;
+      background-size: 100% auto;
+      background-image: var(--image-list_bg_h);
+      margin-bottom: 10px;
+      text-align: center;
+    }
+    .list-item__content_H > div {
+      flex-basis: 33.3%;
+    }
+
+    .list_R {
+      background: none;
+    }
+    .list-item__icon_R {
+      width: 24px;
+      height: 25px;
+      background-image: var(--image-list_bg_r_icon1);
+      background-repeat: no-repeat;
+      background-position: center;
+      background-size: contain;
+      margin-bottom: 5px;
+      position: absolute;
+      left: 35px;
+    }
+    .list-item_R:last-of-type .list-item__icon_R {
+      background-image: var(--image-list_bg_r_icon2);
+    }
+    .list-item__content_R {
+      height: 52px;
+      background-repeat: no-repeat;
+      padding: 0 30px;
+      display: flex;
+      background-position: bottom;
+      background-size: 100% 100%;
+      background-image: var(--image-list_bg_r);
+      text-align: center;
+      align-items: center;
+      .list-item__label {
+        font-size: 15px;
+      }
+      .list-item__value_R {
+        font-family: 'douyuFont';
+        font-size: 15px;
+        padding-top: 5px;
+        color: #00bfff;
+      }
+    }
+    .list-item__content_R > div {
+      flex-basis: 33.3%;
+    }
+
+    .list_fireList {
+      background: none;
+    }
+    .list__wrapper_fireList {
+      display: flex;
+      flex-wrap: wrap;
+      justify-content: flex-start;
+      margin-left: 86px;
+    }
+    .list-item_fireList {
+      width: 167px;
+      height: 58px;
+      align-items: center;
+      text-align: center;
+      background-image: var(--image-list_bg_i);
+      background-repeat: no-repeat;
+      background-size: auto 100%;
+      margin: 5px 10px;
+    }
+    .list-item__content_fireList {
+      position: relative;
+      width: 100%;
+      height: 100%;
+    }
+    .list-item__content_fireList > .list-item__label {
+      width: 60px;
+      height: 100%;
+      left: 0;
+      position: absolute;
+      font-size: 20px;
+      line-height: 63px;
+      color: #009bff;
+    }
+    .list-item__content_fireList > .list-item__info {
+      height: 50%;
+      left: 70px;
+      position: absolute;
+    }
+    .list-item__content_fireList > .list-item__value {
+      top: 50%;
+      height: 50%;
+      left: 70px;
+      position: absolute;
+      font-size: 18px;
+    }
+
+    .list_I {
+      background: none;
+    }
+    .list__wrapper_I {
+      display: flex;
+      flex-wrap: wrap;
+      justify-content: flex-start;
+    }
+    .list-item_I {
+      width: 160px;
+      height: 63px;
+      align-items: center;
+      text-align: center;
+      background-image: var(--image-list_bg_i);
+      background-repeat: no-repeat;
+      background-size: auto 100%;
+      margin: 5px 10px;
+    }
+    .list-item__content_I {
+      position: relative;
+      width: 100%;
+      height: 100%;
+    }
+    .list-item__content_I > .list-item__label {
+      width: 60px;
+      height: 100%;
+      left: 0;
+      position: absolute;
+      font-size: 20px;
+      line-height: 63px;
+      color: #009bff;
+    }
+    .list-item__content_I > .list-item__info {
+      height: 50%;
+      left: 70px;
+      position: absolute;
+    }
+    .list-item__content_I > .list-item__value {
+      top: 50%;
+      height: 50%;
+      left: 70px;
+      position: absolute;
+      font-size: 18px;
+    }
+
+    .list_J {
+      background: unset;
+      padding: 0 5px 0 10px;
+    }
+    .list-item_J {
+      width: 312px;
+      height: 57px;
+      align-items: center;
+      text-align: center;
+      background-image: var(--image-list_bg_j);
+      background-repeat: no-repeat;
+      background-size: auto 100%;
+      margin: 5px 10px;
+    }
+    .list-item__content_J {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 0 20px 0 15px;
+    }
+
+    .list_K {
+      background: unset;
+      padding: 0 5px 0 10px;
+    }
+    .list__wrapper_K {
+      height: 100%;
+    }
+    .list-item__content_K {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 5px;
+      margin: 4px 0;
+      background-image: var(--image-linear-gradient-3);
+
+      .list-item__value {
+        flex-basis: unset;
+      }
+      .list-item__label {
+        flex-basis: unset;
+      }
+      .list-item__info {
+        display: none;
+      }
+    }
+
+    .list_L {
+      background: none;
+      padding: 5px 10px;
+    }
+    .list-item_L {
+      width: 100%;
+      height: 37px;
+      background-repeat: no-repeat;
+      background-size: auto 100%;
+      margin-bottom: 8px;
+    }
+    /* 奇数项背景图 */
+    .list-item_L:nth-child(odd) {
+      background-image: var(--image-list_bg_l1);
+    }
+    /* 偶数项背景图 */
+    .list-item_L:nth-child(even) {
+      background-image: var(--image-list_bg_l2);
+    }
+    .list-item__icon_L {
+      background-repeat: no-repeat;
+      width: 16px;
+      height: 20px;
+      margin-left: 15px;
+      background-position: center;
+      background-size: contain;
+    }
+    /* 四个图标样式 */
+    .list-item_L:nth-child(1) .list-item__icon_L {
+      background-image: var(--image-list_icon_l1);
+    }
+    .list-item_L:nth-child(2) .list-item__icon_L {
+      background-image: var(--image-list_icon_l2);
+    }
+    .list-item_L:nth-child(3) .list-item__icon_L {
+      background-image: var(--image-list_icon_l3);
+    }
+    .list-item_L:nth-child(4) .list-item__icon_L {
+      background-image: var(--image-list_icon_l4);
+    }
+    .list-item__content_L {
+      display: flex;
+      text-align: center;
+      align-items: center;
+      .list-item__value_L {
+        font-family: 'douyuFont';
+      }
+    }
+    .list-item__content_L > div {
+      flex-basis: 33.3%;
+    }
+
+    .list_M {
+      background: none;
+      padding: 0;
+    }
+    .list__wrapper_M {
+      display: grid;
+      grid-template-columns: 1fr 1fr; /* 两列均等 */
+      gap: 18px; /* 统一间距 */
+    }
+    .list-item_M {
+      height: 37px;
+      background-repeat: no-repeat;
+      background-size: 100% 100%;
+    }
+    .list-item_M:nth-child(1),
+    .list-item_M:nth-child(4),
+    .list-item_M:nth-child(5),
+    .list-item_M:nth-child(8) {
+      background-image: var(--image-list_bg_m1);
+    }
+    .list-item_M:nth-child(2),
+    .list-item_M:nth-child(3),
+    .list-item_M:nth-child(6),
+    .list-item_M:nth-child(7) {
+      background-image: var(--image-list_bg_m2);
+    }
+    .list-item_M:nth-child(7),
+    .list-item_M:nth-child(8) {
+      margin-bottom: 0;
+    }
+    .list-item__icon_M {
+      background-repeat: no-repeat;
+      height: 16px;
+      margin-left: 5px;
+      background-position: center;
+      background-size: auto 100%;
+      display: inline-block;
+      width: 40px;
+    }
+    /* 八个图标样式 */
+    .list-item_M:nth-child(1) .list-item__icon_M { background-image: var(--image-list_icon_m1); }
+    .list-item_M:nth-child(2) .list-item__icon_M { background-image: var(--image-list_icon_m2); }
+    .list-item_M:nth-child(3) .list-item__icon_M { background-image: var(--image-list_icon_m3); }
+    .list-item_M:nth-child(4) .list-item__icon_M { background-image: var(--image-list_icon_m4); }
+    .list-item_M:nth-child(5) .list-item__icon_M { background-image: var(--image-list_icon_m5); }
+    .list-item_M:nth-child(6) .list-item__icon_M { background-image: var(--image-list_icon_m6); }
+    .list-item_M:nth-child(7) .list-item__icon_M { background-image: var(--image-list_icon_m7); }
+    .list-item_M:nth-child(8) .list-item__icon_M { background-image: var(--image-list_icon_m8); }
+    .list-item__content_M {
+      display: flex;
+      text-align: center;
+      align-items: center;
+      .list-item__value_M {
+        font-family: 'douyuFont';
+        font-size: 12px;
+      }
+    }
+
+    .list_N {
+      background: none;
+      padding: 5px 10px;
+    }
+    .list-item_N {
+      width: 100%;
+      height: 42px;
+      background-repeat: no-repeat;
+      background-size: 100% 100%;
+      margin-bottom: 15px;
+    }
+    /* 四个背景样式 */
+    .list-item_N:nth-child(1) {
+      background-image: var(--image-list_bg_n1);
+    }
+    .list-item_N:nth-child(2) {
+      background-image: var(--image-list_bg_n2);
+      .list-item__value_N { color: #27cab7; }
+    }
+    .list-item_N:nth-child(3) {
+      background-image: var(--image-list_bg_n3);
+    }
+    .list-item_N:nth-child(4) {
+      background-image: var(--image-list_bg_n4);
+      .list-item__value_N { color: #27cab7; }
+    }
+    .list-item__content_N {
+      display: flex;
+      text-align: center;
+      align-items: center;
+      .list-item__value_N { font-family: 'douyuFont'; }
+    }
+    .list-item__content_N > div:last-child {
+      flex-basis: 60%;
+    }
+
+    .list_U {
+      background: none;
+      padding: 0px 20px;
+    }
+    .list__wrapper_U {
+      display: flex;
+      flex-direction: row;
+      gap: 10px;
+    }
+    .list-item_U {
+      width: 80%;
+      height: 42px;
+      position: relative;
+      display: flex;
+      align-items: center;
+    }
+    .list-item_U:nth-child(odd) {
+      background: var(--image-list_bg_o1);
+      background-size: 100% 100%;
+      background-repeat: no-repeat;
+    }
+    .list-item_U:nth-child(even) {
+      background: var(--image-list_bg_o2);
+      background-size: 100% 100%;
+      background-repeat: no-repeat;
+    }
+    .list-item__icon_U {
+      width: 24px;
+      height: 24px;
+      margin-left: 12px;
+      background-position: center;
+      background-size: contain;
+      background-repeat: no-repeat;
+    }
+    .list-item_U:nth-child(1) .list-item__icon_U { background-image: var(--image-list_icon_o1); }
+    .list-item_U:nth-child(2) .list-item__icon_U { background-image: var(--image-list_icon_o2); }
+    .list-item__content_U {
+      flex: 1;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 0 50px 0 15px;
+    }
+    .list-item__content_U > .list-item__label {
+      font-weight: bold;
+      margin-left: 20px;
+    }
+    .list-item__value_U {
+      font-family: 'douyuFont';
+      color: #ffffff;
+    }
+    /* ===== 通用布局 ===== */
+    .list-item__label {
+      flex-basis: 55%;
+    }
+    .list-item__info {
+      flex-grow: 1;
+    }
+    .list-item__value {
+      flex-basis: 30%;
+    }
+    /* ===== 颜色类 ===== */
+    .list-item__value_red {
+      color: red;
+    }
+    .list-item__value_orange {
+      color: orange;
+    }
+    .list-item__value_yellow {
+      color: yellow;
+    }
+    .list-item__value_green {
+      color: yellowgreen;
+    }
+    .list-item__value_blue {
+      color: @vent-table-action-link;
+    }
+    .list-item__value_white {
+      color: white;
+    }
+    .gallery-item__value_lightblue {
+      color: @vent-configurable-home-light-border;
+    }
 </style>

+ 5 - 1
src/views/vent/monitorManager/fanLocalMonitor/fanLocal.threejs.ts

@@ -3,6 +3,7 @@ import UseThree from '../../../../utils/threejs/useThree';
 
 import { animateCamera } from '/@/utils/threejs/util';
 import useEvent from '../../../../utils/threejs/useEvent';
+import { useModelFileStore } from '/@/store/modules/modelFile';
 import { getDictItemsByCode } from '/@/utils/dict';
 
 /** 模型总控制器 */
@@ -129,7 +130,10 @@ export function mountedThree(sceneSelctor: string, cssSelectors: string[]) {
     }
 
     // 这里根据字典判断
-    const dictCodes = getDictItemsByCode('fanlocal_install_kind');
+    const store = useModelFileStore();
+    const apiDict = getDictItemsByCode('fanlocal_install_kind');
+    const storeData = store.getModelFileDataByKey('fanlocal');
+    const dictCodes = apiDict && apiDict.length ? apiDict : storeData.map((item) => ({ ...item, value: item.fileName }));
     if (dictCodes && dictCodes.length > 0) {
       for (let i = 0; i < dictCodes.length; i++) {
         const dict = dictCodes[i];

+ 5 - 1
src/views/vent/monitorManager/fireDoorMonitor/fireDoor.threejs.ts

@@ -1,6 +1,7 @@
 import * as THREE from 'three';
 import UseThree from '../../../../utils/threejs/useThree';
 import { getDictItemsByCode } from '/@/utils/dict';
+import { useModelFileStore } from '/@/store/modules/modelFile';
 import { animateCamera } from '/@/utils/threejs/util';
 import useEvent from '../../../../utils/threejs/useEvent';
 
@@ -204,7 +205,10 @@ export const mountedThree = () => {
     model.setEnvMap('test1.hdr');
     model.renderer.toneMappingExposure = 1.0;
     model.camera.position.set(100, 0, 1000);
-    const dictCodes = getDictItemsByCode('fireDoorStyle');
+    const store = useModelFileStore();
+    const apiDict = getDictItemsByCode('fireDoorStyle');
+    const storeData = store.getModelFileDataByKey('door');
+    const dictCodes = apiDict && apiDict.length ? apiDict : storeData.map((item) => ({ ...item, value: item.fileName }));
     if (dictCodes && dictCodes.length > 0) {
       for (let i = 0; i < dictCodes.length; i++) {
         const dict = dictCodes[i];

+ 4 - 2
src/views/vent/monitorManager/gateMonitor/gate.threejs.ts

@@ -870,11 +870,13 @@ export const mountedThree = () => {
     model.renderer.toneMappingExposure = 0.9;
     model.camera.position.set(100, 0, 1000);
     const store = useModelFileStore();
-    const dictCodes = store.getModelFileDataByKey('gate').length ? store.getModelFileDataByKey('gate') : getDictItemsByCode('gateStyle');
+    const apiDict = getDictItemsByCode('gateStyle');
+    const storeData = store.getModelFileDataByKey('gate');
+    const dictCodes = apiDict && apiDict.length ? apiDict : storeData.map((item) => ({ ...item, value: item.fileName }));
     if (dictCodes && dictCodes.length > 0) {
       for (let i = 0; i < dictCodes.length; i++) {
         const dict = dictCodes[i];
-        switch (dict.fileName) {
+        switch (dict.value) {
           case 'fmXr':
             const FmXR = await loadModel('FmXR');
             fmXr = new FmXR(model);

+ 5 - 1
src/views/vent/monitorManager/mainFanMonitor/main.threejs.ts

@@ -7,6 +7,7 @@ import mainLjWindRect from './mainWind.lj.threejs';
 import mainWindLj3 from './mainWind.li3.threejs';
 import mainWindLjDt from './mainWind.lidt.threejs';
 import useEvent from '../../../../utils/threejs/useEvent';
+import { useModelFileStore } from '/@/store/modules/modelFile';
 import { getDictItemsByCode } from '/@/utils/dict';
 
 // import * as dat from 'dat.gui';
@@ -749,7 +750,10 @@ export const mountedThree = (playerVal1) => {
       model?.scene?.add(bgGroup);
 
       // 这里根据字典判断
-      const dictCodes = getDictItemsByCode('mainFanType');
+      const store = useModelFileStore();
+      const apiDict = getDictItemsByCode('mainFanType');
+      const storeData = store.getModelFileDataByKey('fanmain');
+      const dictCodes = apiDict && apiDict.length ? apiDict : storeData.map((item) => ({ ...item, value: item.fileName }));
       if (dictCodes && dictCodes.length > 0) {
         for (let i = 0; i < dictCodes.length; i++) {
           const dict = dictCodes[i];

+ 5 - 1
src/views/vent/monitorManager/windowMonitor/window.threejs.ts

@@ -17,6 +17,7 @@ import ddFc_lt from './dandaoFcLt.threejs';
 import SdFcZhq from './shuangdaoFcZhq.threejs';
 import { animateCamera } from '/@/utils/threejs/util';
 import useEvent from '../../../../utils/threejs/useEvent';
+import { useModelFileStore } from '/@/store/modules/modelFile';
 import { getDictItemsByCode } from '/@/utils/dict';
 
 // import * as dat from 'dat.gui';
@@ -426,7 +427,10 @@ export const mountedThree = () => {
     model.renderer.toneMappingExposure = 1.8;
     model.camera.position.set(100, 0, 1000);
     // 根据模型类型判断要初始化哪些模型
-    const dictCodes = getDictItemsByCode('windowModalType');
+    const store = useModelFileStore();
+    const apiDict = getDictItemsByCode('windowModalType');
+    const storeData = store.getModelFileDataByKey('windows');
+    const dictCodes = apiDict && apiDict.length ? apiDict : storeData.map((item) => ({ ...item, value: item.fileName }));
     for (let i = 0; i < dictCodes.length; i++) {
       const dict = dictCodes[i];
 

+ 5 - 1
src/views/vent/monitorManager/windrectMonitor/windrect.threejs.ts

@@ -10,6 +10,7 @@ import fixedWindRect from './duisheFixed.threejs';
 import useEvent from '../../../../utils/threejs/useEvent';
 import gsap from 'gsap';
 import { getDictItemsByCode } from '/@/utils/dict';
+import { useModelFileStore } from '/@/store/modules/modelFile';
 // import * as dat from 'dat.gui';
 // const gui = new dat.GUI();
 // gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
@@ -353,7 +354,10 @@ export const mountedThree = (playerDom) => {
     model.setEnvMap('test1.hdr');
     model.renderer.toneMappingExposure = 1.0;
 
-    const dictCodes = getDictItemsByCode('windrecModel');
+    const store = useModelFileStore();
+    const apiDict = getDictItemsByCode('windrecModel');
+    const storeData = store.getModelFileDataByKey('windrect');
+    const dictCodes = apiDict && apiDict.length ? apiDict : storeData.map((item) => ({ ...item, value: item.fileName }));
     for (let i = 0; i < dictCodes.length; i++) {
       const dict = dictCodes[i];
 

+ 308 - 0
src/views/vent/packageUpload/index.vue

@@ -0,0 +1,308 @@
+<template>
+  <div class="package-upload">
+    <div class="upload-header">
+      <span class="title">部署包管理</span>
+    </div>
+    <div class="upload-content">
+      <a-card title="上传部署包" :bordered="true" style="width: 100%">
+        <a-form :label-col="{ span: 4 }" :wrapper-col="{ span: 16 }">
+          <a-form-item label="部署包类型">
+            <a-radio-group v-model:value="packageType">
+              <a-radio value="frontend">前端部署包 (zip)</a-radio>
+              <a-radio value="backend">后端部署包 (jar)</a-radio>
+            </a-radio-group>
+          </a-form-item>
+          <a-form-item label="选择文件">
+            <a-alert type="warning" show-icon style="margin-bottom: 12px">
+              <template #message>
+                <template v-if="packageType === 'frontend'">
+                  <span style="font-weight: bold">前端包文件命名规则:</span>
+                  <div>
+                    dist + 端口号.zip,例如一通三防智能管控平台前端包为
+                    <b>dist8092.zip</b>
+                  </div>
+                  <div style="margin-top: 4px; font-weight: bold">上传包时请严格按照命名规则,否则会导致部署失败或引起其他系统问题!!!</div>
+                </template>
+                <template v-else>
+                  <span style="font-weight: bold">后端包文件命名规则:</span>
+                  <div style="margin-top: 4px">
+                    <div>jeecg-cloud-gateway-3.2.0.jar</div>
+                    <div>jeecg-cloud-nacos-3.2.0.jar</div>
+                    <div>jeecg-cloud-system-start-3.2.0.jar</div>
+                    <div>ventanaly-monitor-3.2.0.jar</div>
+                    <div>ventanaly-model-3.2.0.jar</div>
+                    <div>ventanaly-jingtaifengliang-3.2.0.jar</div>
+                    <div>ventanaly-sharefile-3.2.0.jar</div>
+                    <div>ventanaly-province-3.2.0.jar</div>
+                    <div>ventanaly-ai-service-3.2.0.jar</div>
+                    <div>ventanaly-company-3.2.0.jar</div>
+                  </div>
+                  <div style="margin-top: 4px; font-weight: bold">上传包时请严格按照命名规则,否则会导致部署失败或引起其他系统问题!!!</div>
+                </template>
+              </template>
+            </a-alert>
+            <a-upload :before-upload="beforeUpload" :file-list="fileList" :remove="handleRemove" :max-count="1">
+              <a-button type="primary">
+                <template #icon><upload-outlined /></template>
+                选择文件
+              </a-button>
+            </a-upload>
+            <div class="file-tip" v-if="fileList.length > 0">
+              <span>已选择: {{ fileList[0]?.name }}</span>
+              <span style="margin-left: 12px; color: #999">({{ formatFileSize(fileList[0]?.size) }})</span>
+              <span v-if="nameWarning" class="name-warning">{{ nameWarning }}</span>
+            </div>
+          </a-form-item>
+          <a-form-item :wrapper-col="{ offset: 4, span: 16 }">
+            <a-button type="primary" danger :loading="deploying" :disabled="fileList.length === 0" @click="handleUploadAndDeploy">
+              <template #icon><cloud-upload-outlined /></template>
+              上传并部署
+            </a-button>
+          </a-form-item>
+        </a-form>
+      </a-card>
+    </div>
+
+    <!-- 全屏loading -->
+    <div class="fullscreen-loading" v-if="deploying">
+      <a-spin size="large" />
+      <span class="loading-text">上传并部署中,请勿关闭或操作页面</span>
+    </div>
+
+    <!-- 部署结果弹框 -->
+    <a-modal v-model:visible="resultVisible" :title="deployIsSuccess ? '部署成功' : '部署失败'" :footer="null" width="600px">
+      <div class="deploy-status-icon" :class="deployIsSuccess ? 'is-success' : 'is-fail'">
+        <template v-if="deployIsSuccess">
+          <span class="icon-check"></span>
+        </template>
+        <template v-else>
+          <span class="icon-cross"></span>
+        </template>
+      </div>
+      <div class="deploy-msg">{{ deployMsg }}</div>
+    </a-modal>
+  </div>
+</template>
+
+<script setup lang="ts">
+  import { ref, watch } from 'vue';
+  import { UploadOutlined, CloudUploadOutlined } from '@ant-design/icons-vue';
+  import { message } from 'ant-design-vue';
+  import { uploadProgramApi } from './package.api';
+
+  const packageType = ref<string>('frontend');
+  const fileList = ref<any[]>([]);
+  const deploying = ref<boolean>(false);
+  const resultVisible = ref<boolean>(false);
+  const deployIsSuccess = ref<boolean>(false);
+  const deployMsg = ref<string>('');
+  const nameWarning = ref<string>('');
+
+  const acceptMap: Record<string, string> = {
+    frontend: '.zip',
+    backend: '.jar',
+  };
+
+  const backendJarNames = [
+    'jeecg-cloud-gateway-3.2.0.jar',
+    'jeecg-cloud-nacos-3.2.0.jar',
+    'jeecg-cloud-system-start-3.2.0.jar',
+    'ventanaly-monitor-3.2.0.jar',
+    'ventanaly-model-3.2.0.jar',
+    'ventanaly-jingtaifengliang-3.2.0.jar',
+    'ventanaly-sharefile-3.2.0.jar',
+    'ventanaly-province-3.2.0.jar',
+    'ventanaly-ai-service-3.2.0.jar',
+    'ventanaly-company-3.2.0.jar',
+  ];
+
+  watch(packageType, () => {
+    fileList.value = [];
+    nameWarning.value = '';
+  });
+
+  function beforeUpload(file) {
+    const accept = acceptMap[packageType.value];
+    const acceptExts = accept.split(',');
+    const ext = '.' + file.name.split('.').pop().toLowerCase();
+    if (!acceptExts.includes(ext)) {
+      message.error(`当前类型仅支持 ${accept} 格式的文件`);
+      return false;
+    }
+    if (packageType.value === 'frontend') {
+      nameWarning.value = /^dist\d+\.zip$/i.test(file.name) ? '' : '包名不符合命名规则,请检查!!!';
+    } else {
+      nameWarning.value = backendJarNames.includes(file.name) ? '' : '包名不符合命名规则,请检查!!!';
+    }
+    fileList.value = [file];
+    return false;
+  }
+
+  function handleRemove() {
+    fileList.value = [];
+    nameWarning.value = '';
+  }
+
+  function formatFileSize(size?: number): string {
+    if (!size) return '0 B';
+    const units = ['B', 'KB', 'MB', 'GB'];
+    let i = 0;
+    let s = size;
+    while (s >= 1024 && i < units.length - 1) {
+      s /= 1024;
+      i++;
+    }
+    return s.toFixed(2) + ' ' + units[i];
+  }
+
+  async function handleUploadAndDeploy() {
+    if (fileList.value.length === 0) {
+      message.warning('请先选择文件');
+      return;
+    }
+    deploying.value = true;
+    try {
+      const res = await uploadProgramApi(fileList.value[0]);
+      const result = res?.result || {};
+      deployIsSuccess.value = result.isSuccess === true;
+      deployMsg.value = result.msg || res?.message || '未知结果';
+      resultVisible.value = true;
+      if (result.isSuccess) {
+        fileList.value = [];
+      }
+    } catch (e: any) {
+      deployIsSuccess.value = false;
+      deployMsg.value = e?.message || '上传请求失败,请检查网络连接';
+      resultVisible.value = true;
+    } finally {
+      deploying.value = false;
+    }
+  }
+</script>
+
+<style lang="less" scoped>
+  @import '/@/design/theme.less';
+
+  .package-upload {
+    padding: 20px;
+    height: 100%;
+    overflow-y: auto;
+
+    :deep(.zxm-card-head-title),
+    :deep(.zxm-form-item-label > label) {
+      color: #fff !important;
+    }
+
+    :deep(.anticon-exclamation-circle) {
+      display: none;
+    }
+
+    .upload-header {
+      margin-bottom: 20px;
+
+      .title {
+        font-size: 20px;
+        font-weight: bold;
+        color: #fff;
+      }
+    }
+
+    .file-tip {
+      margin-top: 8px;
+      font-size: 13px;
+      color: #fff;
+    }
+
+    .name-warning {
+      margin-left: 12px;
+      color: #ff4d4f;
+      font-weight: bold;
+    }
+  }
+
+  .fullscreen-loading {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background: rgba(0, 0, 0, 0.45);
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    z-index: 9999;
+
+    .loading-text {
+      margin-top: 16px;
+      color: #fff;
+      font-size: 16px;
+    }
+  }
+
+  .deploy-status-icon {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 48px;
+    height: 48px;
+    border-radius: 50%;
+    margin: 8px auto 20px;
+
+    &.is-success {
+      background: #52c41a;
+
+      .icon-check {
+        display: block;
+        width: 20px;
+        height: 36px;
+        border: solid #fff;
+        border-width: 0 5px 5px 0;
+        transform: rotate(45deg) translate(-3px, -3px);
+      }
+    }
+
+    &.is-fail {
+      background: #ff4d4f;
+
+      .icon-cross {
+        display: block;
+        width: 32px;
+        height: 32px;
+        position: relative;
+
+        &::before,
+        &::after {
+          content: '';
+          position: absolute;
+          top: 50%;
+          left: 50%;
+          width: 5px;
+          height: 32px;
+          background: #fff;
+          border-radius: 2px;
+        }
+
+        &::before {
+          transform: translate(-50%, -50%) rotate(45deg);
+        }
+
+        &::after {
+          transform: translate(-50%, -50%) rotate(-45deg);
+        }
+      }
+    }
+  }
+
+  .deploy-msg {
+    white-space: pre-wrap;
+    word-break: break-all;
+    max-height: 400px;
+    overflow-y: auto;
+    padding: 12px;
+    border-radius: 4px;
+    font-size: 20px;
+    line-height: 1.6;
+    text-align: center;
+  }
+</style>

+ 15 - 0
src/views/vent/packageUpload/package.api.ts

@@ -0,0 +1,15 @@
+import { defHttp } from '/@/utils/http/axios';
+
+enum Api {
+  sysUploadProgram = '/ventanaly-device/safety/common/uploadProgram',
+  uploadProgram = '/jeecg-system/sys/common/uploadProgram',
+}
+
+/**
+ * 上传部署包 - 文件名包含system时使用sysUploadProgram,否则使用uploadProgram
+ */
+export const uploadProgramApi = async (file: File) => {
+  const fileName = file.name.toLowerCase();
+  const url = fileName.includes('system') ? Api.sysUploadProgram : Api.uploadProgram;
+  return defHttp.uploadFile({ url, timeout: 15 * 60 * 1000 }, { file, name: 'file' }, { isReturnResponse: true });
+};

+ 70 - 32
src/views/ventAI/dataPicker/components/DataPickerModal.vue

@@ -10,39 +10,48 @@
     @cancel="$emit('close')"
   >
     <div class="di-header">
-      <span class="di-header__title">数据解读</span>
+      <span class="di-header__title"><img :src="aiIcon" width="20" height="20" alt="" class="di-header__icon" />数据解读</span>
       <span class="di-header__close" @click="$emit('close')">✕</span>
     </div>
     <div ref="bodyRef" class="di-body">
-      <div v-if="showProcess" class="di-process">
-        <div v-if="processCollapsed" class="di-process__summary" @click="processCollapsed = false">
-          <span class="di-process__summary-icon">▸</span>
-          <span>查看处理过程</span>
-        </div>
-        <template v-else>
-          <div v-if="!props.loading" class="di-process__summary" @click="processCollapsed = true">
-            <span class="di-process__summary-icon">▾</span>
-            <span>收起处理过程</span>
-          </div>
-          <div v-if="thinking" class="di-process__row di-process__thinking"><a-spin size="small" /><span>AI 正在思考...</span></div>
-          <div v-if="todos.length > 0" class="di-process__todos">
-            <div v-for="(todo, i) in todos" :key="i" class="di-todo-item" :class="`di-todo-item--${todo.status}`">
-              <span class="di-todo-item__icon">
-                <span v-if="todo.status === 'completed'" class="di-todo-check">✓</span>
-                <span v-else-if="todo.status === 'in_progress'" class="di-todo-spinner"></span>
-                <span v-else class="di-todo-dot"></span>
-              </span>
-              <span class="di-todo-item__text">{{ todo.content }}</span>
+      <div class="di-section">
+        <div class="di-section__title">监测对象</div>
+        <div class="di-section__content di-section__content--target">{{ props.itemName }}</div>
+      </div>
+      <div class="di-section">
+        <div class="di-section__title">分析结论</div>
+        <div class="di-section__content">
+          <div v-if="showProcess" class="di-process">
+            <div v-if="processCollapsed" class="di-process__summary" @click="processCollapsed = false">
+              <span class="di-process__summary-icon">▸</span>
+              <span>查看处理过程</span>
             </div>
+            <template v-else>
+              <div v-if="!props.loading" class="di-process__summary" @click="processCollapsed = true">
+                <span class="di-process__summary-icon">▾</span>
+                <span>收起处理过程</span>
+              </div>
+              <div v-if="thinking" class="di-process__row di-process__thinking"><a-spin size="small" /><span>AI 正在思考...</span></div>
+              <div v-if="todos.length > 0" class="di-process__todos">
+                <div v-for="(todo, i) in todos" :key="i" class="di-todo-item" :class="`di-todo-item--${todo.status}`">
+                  <span class="di-todo-item__icon">
+                    <span v-if="todo.status === 'completed'" class="di-todo-check">✓</span>
+                    <span v-else-if="todo.status === 'in_progress'" class="di-todo-spinner"></span>
+                    <span v-else class="di-todo-dot"></span>
+                  </span>
+                  <span class="di-todo-item__text">{{ todo.content }}</span>
+                </div>
+              </div>
+              <div v-if="props.latestMessage && loading" class="di-process__row di-process__message">
+                <span class="di-process__dot"></span><span>{{ props.latestMessage }}</span>
+              </div>
+            </template>
           </div>
-          <div v-if="props.latestMessage && loading" class="di-process__row di-process__message">
-            <span class="di-process__dot"></span><span>{{ props.latestMessage }}</span>
-          </div>
-        </template>
+          <div v-if="loading && !hasContent" class="di-loading"><a-spin tip="正在分析数据..." /></div>
+          <div v-if="hasContent" class="di-markdown" v-html="renderedText"></div>
+          <div v-else-if="error && !loading" class="di-error">数据解读失败:{{ error }}</div>
+        </div>
       </div>
-      <div v-if="loading && !hasContent" class="di-loading"><a-spin tip="正在分析数据..." /></div>
-      <div v-if="hasContent" class="di-markdown" v-html="renderedText"></div>
-      <div v-else-if="error && !loading" class="di-error">数据解读失败:{{ error }}</div>
     </div>
     <div v-if="loading && hasContent" class="di-streaming-bar"><a-spin size="small" /><span class="di-streaming-bar__tip">AI 正在生成...</span></div>
   </a-modal>
@@ -52,6 +61,7 @@
   import { computed, ref, watch, nextTick, onMounted, onBeforeUnmount } from 'vue';
   import { marked } from 'marked';
   import type { TodoItem, ToolCallRecord } from '../types';
+  import aiIcon from '@/assets/images/ventAI/dataPicker/AI-icon.svg';
 
   const props = defineProps<{
     visible: boolean;
@@ -63,6 +73,7 @@
     executingTools: string[];
     toolCalls: ToolCallRecord[];
     latestMessage: string;
+    itemName: string;
   }>();
 
   defineEmits<{ close: [] }>();
@@ -147,10 +158,9 @@
     }
     .ant-modal-content {
       color: var(--vent-font-color) !important;
-      background-color: var(--vent-modal-bg) !important;
-      border: 1px solid var(--vent-modal-border) !important;
-      -webkit-box-shadow: 0px 0px 10px var(--vent-modal-box-shadow) inset !important;
-      box-shadow: 0px 0px 10px var(--vent-modal-box-shadow) inset !important;
+      background-color: rgba(9, 23, 44, 0.3);
+      border: 1px solid #3df6ff;
+      box-shadow: inset 0 0 12px #2cb6ff;
       backdrop-filter: blur(30px);
     }
     .ant-modal-body {
@@ -169,14 +179,21 @@
     display: flex;
     justify-content: space-between;
     align-items: center;
-    padding: 18px 24px;
+    padding: 8px;
     border-bottom: 1px solid rgba(30, 144, 255, 0.15);
     flex-shrink: 0;
+    background-color: rgba(57, 163, 255, 0.2);
     &__title {
       font-size: 18px;
       font-weight: bold;
       color: #fff;
       letter-spacing: 2px;
+      display: flex;
+      align-items: center;
+      gap: 8px;
+    }
+    &__icon {
+      display: inline-block;
     }
     &__close {
       cursor: pointer;
@@ -193,6 +210,27 @@
     max-height: 700px;
     overflow-y: auto;
   }
+  .di-section {
+    margin-bottom: 16px;
+    &:last-child {
+      margin-bottom: 0;
+    }
+    &__title {
+      color: #c9f0ff;
+      font-size: 15px;
+      font-weight: bold;
+      margin-bottom: 8px;
+    }
+    &__content {
+      border-top: 2px solid #2cb6ff;
+      background: rgba(36, 138, 191, 0.1);
+      padding: 12px;
+      &--target {
+        color: #fff;
+        font-size: 14px;
+      }
+    }
+  }
   .di-loading {
     display: flex;
     justify-content: center;

+ 10 - 8
src/views/ventAI/dataPicker/useDataPicker.ts

@@ -3,6 +3,7 @@ import Antd from 'ant-design-vue';
 import { fetchTunnelInterpretation, fetchDeviceInterpretation } from './api';
 import type { TodoItem, ToolCallRecord, SSERawEvent } from './types';
 import DataPickerModal from './components/DataPickerModal.vue';
+import aiIcon from '@/assets/images/ventAI/dataPicker/AI-icon.svg';
 
 // ─── 按钮 DOM 构建(悬停模式专用)──────────────────────────────────────────
 const BUTTON_CLASS = 'di-floating-btn';
@@ -10,24 +11,21 @@ const BUTTON_CLASS = 'di-floating-btn';
 function createButtonEl(): HTMLElement {
   const btn = document.createElement('div');
   btn.className = BUTTON_CLASS;
-  btn.innerHTML = '<span>数据解读</span>';
+  btn.title = '数据解读';
+  btn.innerHTML = `<img src="${aiIcon}" width="24" height="24" alt="数据解读" />`;
   Object.assign(btn.style, {
     position: 'fixed',
     zIndex: '99999',
-    padding: '8px 12px',
+    padding: '8px',
     background: 'linear-gradient(135deg, #1e90ff, #4da6ff)',
-    borderRadius: '3px',
+    borderRadius: '50%',
     cursor: 'pointer',
-    fontSize: '16px',
-    color: '#fff',
-    letterSpacing: '1px',
-    whiteSpace: 'nowrap',
-    boxShadow: '0 0 10px rgba(30,144,255,0.4)',
     display: 'none',
     pointerEvents: 'auto',
     transition: 'transform 0.15s ease-out, opacity 0.15s ease-out',
     transform: 'scale(0.9)',
     opacity: '0',
+    boxShadow: '0 0 10px rgba(30,144,255,0.4)',
   });
   btn.addEventListener('mouseenter', () => {
     const owner = (btn as any).__di_owner;
@@ -188,6 +186,7 @@ export function useDataPicker(
   const toolCalls = ref<ToolCallRecord[]>([]);
   const latestMessage = ref('');
   const modalVisible = ref(false);
+  const itemName = ref('');
 
   // 弹框容器 + 独立 Vue 应用
   const modalContainer = document.createElement('div');
@@ -216,6 +215,7 @@ export function useDataPicker(
         executingTools,
         toolCalls,
         latestMessage,
+        itemName,
         onClose: () => {
           modalVisible.value = false;
           streamingText.value = '';
@@ -239,6 +239,7 @@ export function useDataPicker(
             executingTools: this.executingTools,
             toolCalls: this.toolCalls,
             latestMessage: this.latestMessage,
+            itemName: this.itemName,
             onClose: this.onClose,
           }),
         ]);
@@ -297,6 +298,7 @@ export function useDataPicker(
     latestMessage.value = '';
 
     const params = mapParams(item);
+    itemName.value = 'tun_name' in params ? params.tun_name : params.device_name;
     const request = 'tun_id' in params ? fetchTunnelInterpretation(params, handleEvent) : fetchDeviceInterpretation(params, handleEvent);
 
     request

+ 285 - 83
src/views/ventAI/manageAssistent/components/AiAssistantModal.vue

@@ -1,33 +1,51 @@
 <template>
-  <a-modal :visible="props.visible" @cancel="emit('close')" :width="1400" :footer="null" destroyOnClose class="ai-assistant-modal">
+  <a-modal
+    :visible="props.visible"
+    @cancel="emit('close')"
+    :width="isFullscreen ? '100vw' : 1400"
+    :footer="null"
+    destroyOnClose
+    :class="['ai-assistant-modal', { fullscreen: isFullscreen }]"
+  >
     <template #title>
-      <div class="draggable-title" @mousedown="onDragStart">"通安智风"大模型</div>
+      <div :class="['draggable-title', { 'no-drag': isFullscreen }]" @mousedown="onDragStart">"通安智风"大模型</div>
     </template>
+    <!-- 最大化/还原按钮 -->
+    <div class="maximize-btn" @click="toggleFullscreen">
+      <div :class="['maximize-icon', { minimized: isFullscreen }]"></div>
+    </div>
+    <!-- 收起/展开按钮 -->
+    <div class="collapse-btn" @click="togglePanel">
+      <div :class="['collapse-icon', { collapsed: panelCollapsed }]"></div>
+    </div>
     <div class="ai-container">
       <!-- 左侧任务列表 -->
-      <TaskListPanel
-        :taskList="taskList"
-        :currentTaskId="currentTaskId"
-        @switch-task="switchTask"
-        @create-task="createNewTask"
-        @delete-task="handleDeleteTask"
-      />
+      <div :class="['task-panel-wrapper', { collapsed: panelCollapsed }]">
+        <TaskListPanel
+          :taskList="taskList"
+          :currentTaskId="currentTaskId"
+          @switch-task="switchTask"
+          @create-task="createNewTask"
+          @delete-task="handleDeleteTask"
+        />
+      </div>
 
       <!-- 中间聊天区域 -->
       <div class="chat-panel">
         <!-- 顶部任务选择器 -->
         <div class="chat-header">
-          <a-select
-            v-model:value="currentTaskId"
-            style="width: 300px"
-            @change="handleTaskChange"
-            :getContainer="false"
-            popup-class-name="ai-task-select-dropdown"
-          >
-            <a-select-option v-for="task in taskList" :key="task.id" :value="task.id">
-              {{ task.name }}
-            </a-select-option>
-          </a-select>
+          <template v-if="panelCollapsed">
+            <div :class="['nav-btn', { disabled: !canGoPrev }]" @click="goToPrev">
+              <div class="nav-icon prev-icon"></div>
+            </div>
+            <div :class="['nav-btn', { disabled: !canGoNext }]" @click="goToNext">
+              <div class="nav-icon next-icon"></div>
+            </div>
+            <div class="nav-btn" @click="createNewTask">
+              <div class="nav-icon add-icon"></div>
+            </div>
+          </template>
+          <span v-if="currentTask?.sessionId" class="chat-header-title">{{ currentTask.name }}</span>
           <div v-if="currentWordUrl" class="upload-bg" @click="downloadWordReport">
             <div class="download-icon"></div>
           </div>
@@ -92,12 +110,13 @@
       const res = await getHistoryList({});
       const sessions = res?.sessions || res?.data || [];
       if (Array.isArray(sessions)) {
-        const apiTasks: Task[] = sessions.map((item: { session_id: string; title: string }) => ({
+        const apiTasks: Task[] = sessions.map((item: { session_id: string; title: string; updated_at: string }) => ({
           id: item.session_id,
           name: item.title || '未命名会话',
           sessionId: item.session_id,
           messages: [],
           attachedFiles: [],
+          updatedAt: item.updated_at,
         }));
 
         const mergedTasks = apiTasks.map((apiTask) => {
@@ -132,13 +151,49 @@
   const showFileList = ref(false);
   const pendingFile = ref<AttachedFile | null>(null);
 
-  const messages = ref<Message[]>([
-    {
-      type: 'ai',
-      content: '您好!我是通安智风助手,请问有什么可以帮助您的吗?',
-      time: dayjs().format('HH:mm'),
-    },
-  ]);
+  const messages = ref<Message[]>([]);
+
+  const panelCollapsed = ref(false);
+  const togglePanel = () => {
+    panelCollapsed.value = !panelCollapsed.value;
+  };
+
+  const isFullscreen = ref(false);
+  const toggleFullscreen = () => {
+    isFullscreen.value = !isFullscreen.value;
+    nextTick(() => {
+      const wraps = document.querySelectorAll<HTMLElement>('.zxm-modal-wrap, .ant-modal-wrap, [class*="modal-wrap"]');
+      wraps.forEach((wrap) => {
+        if (isFullscreen.value) {
+          wrap.style.position = '';
+          wrap.style.left = '';
+          wrap.style.top = '0';
+          wrap.style.right = '';
+          wrap.style.bottom = '';
+          wrap.style.width = '';
+          wrap.style.height = '';
+          wrap.style.margin = '0';
+          wrap.style.padding = '0';
+          wrap.style.transform = '';
+        } else {
+          wrap.style.position = '';
+          wrap.style.left = '';
+          wrap.style.top = '';
+          wrap.style.right = '';
+          wrap.style.bottom = '';
+          wrap.style.width = '';
+          wrap.style.height = '';
+          wrap.style.margin = '';
+          wrap.style.padding = '';
+          wrap.style.transform = '';
+        }
+      });
+      draggedEl = null;
+      if (!isFullscreen.value) {
+        centerModal();
+      }
+    });
+  };
 
   const inputMessage = ref('');
   const loading = ref(false);
@@ -199,11 +254,7 @@
     messages.value = newTask.messages && newTask.messages.length > 0 ? [...newTask.messages] : getDefaultMessages();
 
     await nextTick();
-    scrollToBottom();
-  };
-
-  const handleTaskChange = (taskId: string) => {
-    switchTask(taskId);
+    chatMessagesRef.value?.forceScrollToBottom();
   };
 
   const createNewTask = () => {
@@ -254,13 +305,7 @@
   };
 
   const getDefaultMessages = (): Message[] => {
-    return [
-      {
-        type: 'ai',
-        content: '您好!我是通安智风助手,请问有什么可以帮助您的吗?',
-        time: dayjs().format('HH:mm'),
-      },
-    ];
+    return [];
   };
 
   const normalizeLineBreaks = (str: string): string => {
@@ -370,11 +415,28 @@
     return currentTask?.attachedFiles || [];
   };
 
+  const currentTask = computed(() => taskList.value.find((t) => t.id === currentTaskId.value));
+
   const currentWordUrl = computed(() => {
-    const currentTask = taskList.value.find((t) => t.id === currentTaskId.value);
-    return currentTask?.wordUrl || '';
+    return currentTask.value?.wordUrl || '';
   });
 
+  const currentTaskIndex = computed(() => taskList.value.findIndex((t) => t.id === currentTaskId.value));
+  const canGoPrev = computed(() => currentTaskIndex.value > 0);
+  const canGoNext = computed(() => currentTaskIndex.value >= 0 && currentTaskIndex.value < taskList.value.length - 1);
+
+  const goToPrev = () => {
+    if (!canGoPrev.value) return;
+    const prevTask = taskList.value[currentTaskIndex.value - 1];
+    if (prevTask) switchTask(prevTask.id);
+  };
+
+  const goToNext = () => {
+    if (!canGoNext.value) return;
+    const nextTask = taskList.value[currentTaskIndex.value + 1];
+    if (nextTask) switchTask(nextTask.id);
+  };
+
   const downloadWordReport = () => {
     const url = currentWordUrl.value;
     if (!url) return;
@@ -473,15 +535,9 @@
     return nameMap[toolName] || nameMap[toolName.toLowerCase()] || '智能分析助手';
   };
 
-  // 每个 agent 只保留最新一条步骤,新数据替换旧数据
+  // 累积所有步骤,保留完整历史
   const upsertStep = (steps: any[], step: any) => {
-    const agentName = step.agent || '系统';
-    const idx = steps.findIndex((s) => (s.agent || '系统') === agentName && s.type !== 'updated_todo_list');
-    if (idx !== -1) {
-      steps.splice(idx, 1, step);
-    } else {
-      steps.push(step);
-    }
+    steps.push(step);
   };
 
   const handleSSEMessage = (data: any, aiMsgIndex: number) => {
@@ -856,7 +912,7 @@
         inputMessage.value = '';
 
         await nextTick(() => {
-          scrollToBottom();
+          chatMessagesRef.value?.forceScrollToBottom();
         });
       }
     }
@@ -894,6 +950,7 @@
   };
 
   const onDragStart = (e: MouseEvent) => {
+    if (isFullscreen.value) return;
     draggedEl = findModalWrap(e.target as HTMLElement) || queryModalWrap();
     if (!draggedEl) return;
 
@@ -955,6 +1012,54 @@
     font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
   }
 
+  .collapse-btn {
+    position: absolute;
+    top: 16px;
+    left: 24px;
+    z-index: 10;
+    width: 32px;
+    height: 32px;
+    background: #1a6696;
+    border-radius: 4px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    cursor: pointer;
+    transition: background 0.3s;
+
+    &:hover {
+      background: #1f7ab8;
+    }
+
+    .collapse-icon {
+      width: 16px;
+      height: 16px;
+      background-image: var(--img-chat-collapse-icon);
+      background-repeat: no-repeat;
+      background-size: 100% 100%;
+
+      &.collapsed {
+        background-image: var(--img-chat-expand-icon);
+      }
+    }
+  }
+
+  .task-panel-wrapper {
+    width: 260px;
+    flex-shrink: 0;
+    overflow: hidden;
+    transition:
+      width 0.35s cubic-bezier(0.4, 0, 0.2, 1),
+      margin 0.35s cubic-bezier(0.4, 0, 0.2, 1),
+      opacity 0.25s ease;
+
+    &.collapsed {
+      width: 0;
+      margin: 0;
+      opacity: 0;
+    }
+  }
+
   .chat-panel {
     flex: 1;
     display: flex;
@@ -972,6 +1077,7 @@
       padding: 12px 20px;
       flex-shrink: 0;
       align-items: center;
+      background: rgba(2, 53, 100, 0.3);
 
       .header-icon {
         width: 35px;
@@ -981,33 +1087,60 @@
         background-size: 100% 100%;
         margin-right: 10px;
       }
-      .zxm-select-selector {
-        height: 40px;
-        background-image: var(--img-chat-selector-bg);
-        background-repeat: no-repeat;
-        background-size: 100% 100%;
-        border: none;
-        border-color: unset !important;
-        box-shadow: unset !important;
-        color: #e0e6ed;
-        background-color: unset;
-        border-radius: 0;
-        padding-left: 40px;
-        padding-top: 10px;
-      }
-      .zxm-select-arrow {
+
+      .chat-header-title {
+        font-size: 16px;
         color: #e0e6ed;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+        margin-left: 10px;
       }
 
-      .zxm-select-selection-item {
-        color: #e0e6ed;
+      .nav-btn {
+        width: 28px;
+        height: 28px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        cursor: pointer;
+        border-radius: 4px;
+        transition: background 0.2s;
+
+        &:hover:not(.disabled) {
+          background: rgba(10, 132, 255, 0.15);
+        }
+
+        &.disabled {
+          opacity: 0.3;
+          cursor: not-allowed;
+        }
+
+        .nav-icon {
+          width: 16px;
+          height: 16px;
+          background-repeat: no-repeat;
+          background-size: 100% 100%;
+        }
+
+        .prev-icon {
+          background-image: var(--img-chat-prev-icon);
+        }
+
+        .next-icon {
+          background-image: var(--img-chat-next-icon);
+        }
+
+        .add-icon {
+          background-image: var(--img-chat-options-add-icon);
+        }
       }
 
       .upload-bg {
         cursor: pointer;
         width: 36px;
         height: 36px;
-        background-image: var(--img-chat-upload-bg);
+        background-image: var(--img-chat-close-bg);
         background-repeat: no-repeat;
         background-size: 100% 100%;
         display: flex;
@@ -1031,8 +1164,9 @@
     height: 100%;
     display: flex;
     flex-direction: column;
-    background: linear-gradient(to bottom, rgba(10, 132, 255, 0.08), rgba(2, 22, 50, 0.95));
-    border: 2px solid rgba(63, 80, 106, 0.5);
+    background-image: var(--img-chat-panel-bg);
+    background-repeat: no-repeat;
+    background-size: 100% 100%;
     border-radius: 4px;
     flex-shrink: 0;
   }
@@ -1044,6 +1178,14 @@
     &:active {
       cursor: grabbing;
     }
+
+    &.no-drag {
+      cursor: default;
+
+      &:active {
+        cursor: default;
+      }
+    }
   }
 </style>
 
@@ -1062,8 +1204,8 @@
       background-image: var(--img-chat-close-bg);
       background-repeat: no-repeat;
       background-size: 100% 100%;
-      top: -6px;
-      right: -6px;
+      top: 0px;
+      right: 0px;
       width: 38px;
       height: 38px;
       .zxm-modal-close-x {
@@ -1077,6 +1219,76 @@
       }
     }
 
+    .maximize-btn {
+      position: absolute;
+      top: 0px;
+      right: 56px;
+      width: 38px;
+      height: 38px;
+      background-image: var(--img-chat-close-bg);
+      background-repeat: no-repeat;
+      background-size: 100% 100%;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      cursor: pointer;
+      z-index: 10;
+
+      .maximize-icon {
+        width: 22px;
+        height: 22px;
+        background-image: var(--img-chat-maximize-icon);
+        background-repeat: no-repeat;
+        background-size: 100% 100%;
+
+        &.minimized {
+          background-image: var(--img-chat-minimize-icon);
+        }
+      }
+    }
+
+    &.fullscreen {
+      top: 0 !important;
+      padding: 0 !important;
+      max-width: 100vw !important;
+      margin: 0 !important;
+
+      .zxm-modal-wrap,
+      .ant-modal-wrap {
+        padding: 0 !important;
+        margin: 0 !important;
+        top: 0 !important;
+      }
+
+      .zxm-modal-content {
+        width: 100vw !important;
+        height: 100vh !important;
+        max-width: 100vw !important;
+        margin: 0;
+        border-radius: 0;
+        overflow: hidden;
+      }
+      .zxm-modal-header {
+        height: 120px;
+      }
+      .no-drag {
+        cursor: default;
+        font-size: 32px !important;
+      }
+      .zxm-modal-title {
+        height: 90px;
+      }
+      .zxm-modal-body {
+        height: calc(100vh - 120px);
+        overflow: hidden;
+        padding: 0 24px 12px;
+      }
+      .ai-container {
+        height: 100%;
+        overflow: hidden;
+      }
+    }
+
     .zxm-modal-header {
       background-color: unset !important;
       background: unset;
@@ -1106,14 +1318,4 @@
       padding: 12px 24px;
     }
   }
-  .ai-task-select-dropdown {
-    background-color: rgba(10, 132, 255, 0.1);
-    .zxm-select-item {
-      color: #e0e6ed;
-    }
-    .zxm-select-item-option-selected {
-      color: #e0e6ed !important;
-      background-color: rgba(10, 132, 255, 0.15) !important;
-    }
-  }
 </style>

+ 4 - 4
src/views/ventAI/manageAssistent/components/chatModal/ChatInputArea.vue

@@ -81,10 +81,10 @@
   .chat-input-area {
     padding: 5px 10px;
     flex-shrink: 0;
-    background-color: rgba(10, 132, 255, 0.05);
-    border: 1px solid rgba(63, 80, 106, 0.5);
+    background-color: #002f4a;
+    border: 1px solid #005482;
     border-radius: 4px;
-    margin: 5px 10px;
+    margin: 10px 16px 16px 16px;
 
     .pending-file-display {
       margin-bottom: 5px;
@@ -170,7 +170,7 @@
     }
     .input-actions {
       display: flex;
-      justify-content: end;
+      justify-content: space-between;
       align-items: center;
       margin-top: 12px;
 

+ 239 - 173
src/views/ventAI/manageAssistent/components/chatModal/ChatMessages.vue

@@ -1,92 +1,100 @@
 <template>
   <div class="chat-messages-container">
     <div class="chat-messages" ref="messagesRef">
-      <div v-for="(message, index) in messages" :key="index" :class="['message-wrapper', message.type]">
+      <!-- 新对话缺省图 -->
+      <div v-if="messages.length === 0" class="welcome-empty">
+        <img :src="getCssUrl('--img-chat-welcome-img')" class="welcome-img" />
+      </div>
+      <div v-for="(message, index) in messages" :key="index" :class="['message-wrapper', message.type]" @mouseleave="copiedMessageIndex = -1">
         <!-- AI消息 -->
         <div v-if="message.type === 'ai'" class="ai-message">
-          <div class="message-agent">
+          <!-- <div class="message-agent">
             <div class="agent-icon"></div>
-          </div>
+          </div> -->
           <div class="message-body">
             <!-- 思考过程折叠卡片 -->
             <div v-if="message.thinkingSteps && message.thinkingSteps.length > 0" class="thinking-card">
-              <div class="thinking-header" @click="toggleThinking(index)">
-                <div class="thinking-header-left">
-                  <div class="thinking-icon"></div>
-                  <span class="thinking-title">思考过程</span>
-                  <span class="thinking-count">{{ getAgentCount(message.thinkingSteps) }} 个子任务</span>
-                  <span v-if="getDurationText(message)" class="thinking-duration">{{ getDurationText(message) }}</span>
-                </div>
-                <div :class="['thinking-arrow', { expanded: expandedThinking[index] }]">
-                  <img :src="arrowIcon" width="12" height="12" />
+              <div class="thinking-duration-bar" @click="toggleThinkingCard(index)">
+                <span v-if="getDurationText(message)" class="thinking-duration">{{ getDurationText(message) }}</span>
+                <div :class="['thinking-arrow', { expanded: !collapsedThinking[index] }]">
+                  <img :src="getCssUrl('--img-chat-arrow-icon')" width="12" height="12" />
                 </div>
               </div>
-              <div v-show="expandedThinking[index]" class="thinking-body">
-                <div v-for="(group, groupIdx) in groupStepsByAgent(message.thinkingSteps)" :key="groupIdx" class="agent-group">
-                  <div class="agent-group-header" @click="toggleAgent(index + '-' + group.agent)">
-                    <div class="agent-group-header-left">
-                      <div class="agent-group-icon"></div>
-                      <span class="agent-group-name">{{ group.agent }}</span>
-                      <span class="agent-group-count">{{ group.steps.length }} 步</span>
-                    </div>
-                    <div :class="['thinking-arrow', { expanded: expandedAgents[index + '-' + group.agent] }]">
-                      <img :src="arrowIcon" width="10" height="10" />
-                    </div>
+              <div v-show="!collapsedThinking[index]">
+                <div class="thinking-header">
+                  <div class="thinking-header-left">
+                    <div class="thinking-icon"></div>
+                    <span class="thinking-title">思考过程 持续了几秒</span>
                   </div>
-                  <div v-show="expandedAgents[index + '-' + group.agent]" class="agent-group-body">
-                    <div v-for="(step, stepIdx) in group.steps" :key="stepIdx" class="thinking-step">
-                      <!-- agent_start -->
-                      <div v-if="step.type === 'agent_start'" class="step-item step-agent-start">
-                        <div class="step-icon agent-icon-start"></div>
-                        <div class="step-content">
-                          <span class="step-desc">{{ step.message }}</span>
-                        </div>
+                </div>
+                <div class="thinking-body">
+                  <div
+                    v-for="(group, groupIdx) in groupStepsByAgent(message.thinkingSteps)"
+                    :key="groupIdx"
+                    :class="['agent-group', { expanded: expandedAgents[index + '-' + group.agent] }]"
+                  >
+                    <div class="agent-group-header" @click="toggleAgent(index + '-' + group.agent)">
+                      <div class="agent-group-header-left">
+                        <div class="agent-group-icon"></div>
+                        <span class="agent-group-name">{{ group.agent }}</span>
                       </div>
-                      <!-- tool_call -->
-                      <div v-else-if="step.type === 'tool_call'" class="step-item step-tool-call">
-                        <div class="step-icon tool-icon"></div>
-                        <div class="step-content">
-                          <span class="step-label">调用工具:</span>
-                          <span class="step-tool-name">{{ step.tool }}</span>
-                          <span v-if="step.message" class="step-desc">{{ step.message }}</span>
-                        </div>
+                      <!-- 最新一条执行结果,内联显示 -->
+                      <span v-if="getLatestStepMessage(group)" class="agent-group-latest">
+                        {{ getLatestStepMessage(group) }}
+                      </span>
+                      <div :class="['thinking-arrow', 'agent-arrow', { expanded: expandedAgents[index + '-' + group.agent] }]">
+                        <img :src="getCssUrl('--img-chat-arrow-icon')" width="10" height="10" />
                       </div>
-                      <!-- executing -->
-                      <div v-else-if="step.type === 'executing'" class="step-item step-executing">
-                        <div class="step-icon executing-icon"></div>
-                        <div class="step-content">
-                          <span class="step-desc">{{ step.message || '正在执行...' }}</span>
-                          <span v-if="step.tool" class="step-tool-name">{{ step.tool }}</span>
+                    </div>
+                    <div v-show="expandedAgents[index + '-' + group.agent]" class="agent-group-body">
+                      <div v-for="(step, stepIdx) in group.steps" :key="stepIdx" class="thinking-step">
+                        <!-- agent_start -->
+                        <div v-if="step.type === 'agent_start'" class="step-item step-agent-start">
+                          <div class="step-content">
+                            <span class="step-desc">{{ step.message }}</span>
+                          </div>
                         </div>
-                      </div>
-                      <!-- updated_todo_list -->
-                      <div v-else-if="step.type === 'updated_todo_list'" class="step-item step-todo">
-                        <div class="step-icon todo-icon"></div>
-                        <div class="step-content">
-                          <div class="todo-list">
-                            <div v-for="(todo, todoIdx) in step.todos" :key="todoIdx" class="todo-item">
-                              <span :class="['todo-status', todo.status]">
-                                {{ todo.status === 'completed' ? '✓' : todo.status === 'in_progress' ? '●' : '○' }}
-                              </span>
-                              <span class="todo-text">{{ todo.content }}</span>
+                        <!-- tool_call -->
+                        <div v-else-if="step.type === 'tool_call'" class="step-item step-tool-call">
+                          <div class="step-content">
+                            <span class="step-label">调用工具:</span>
+                            <span class="step-tool-name">{{ step.tool }}</span>
+                            <span v-if="step.message" class="step-desc">{{ step.message }}</span>
+                          </div>
+                        </div>
+                        <!-- executing -->
+                        <div v-else-if="step.type === 'executing'" class="step-item step-executing">
+                          <div class="step-content">
+                            <span class="step-desc">{{ step.message || '正在执行...' }}</span>
+                            <span v-if="step.tool" class="step-tool-name">{{ step.tool }}</span>
+                          </div>
+                        </div>
+                        <!-- updated_todo_list -->
+                        <div v-else-if="step.type === 'updated_todo_list'" class="step-item step-todo">
+                          <div class="step-content">
+                            <div class="todo-list">
+                              <div v-for="(todo, todoIdx) in step.todos" :key="todoIdx" class="todo-item">
+                                <span :class="['todo-status', todo.status]">
+                                  {{ todo.status === 'completed' ? '✓' : todo.status === 'in_progress' ? '●' : '○' }}
+                                </span>
+                                <span class="todo-text">{{ todo.content }}</span>
+                              </div>
                             </div>
                           </div>
                         </div>
-                      </div>
-                      <!-- tool_result -->
-                      <div v-else-if="step.type === 'tool_result'" class="step-item step-tool-result">
-                        <div class="step-icon result-icon"></div>
-                        <div class="step-content">
-                          <span class="step-label">工具结果:</span>
-                          <span class="step-tool-name">{{ step.tool }}</span>
-                          <span class="step-desc">{{ step.message }}</span>
+                        <!-- tool_result -->
+                        <div v-else-if="step.type === 'tool_result'" class="step-item step-tool-result">
+                          <div class="step-content">
+                            <span class="step-label">工具结果:</span>
+                            <span class="step-tool-name">{{ step.tool }}</span>
+                            <span class="step-desc">{{ step.message }}</span>
+                          </div>
                         </div>
-                      </div>
-                      <!-- agent_done -->
-                      <div v-else-if="step.type === 'agent_done'" class="step-item step-agent-done">
-                        <div class="step-icon done-icon"></div>
-                        <div class="step-content">
-                          <span class="step-desc">{{ step.message }}</span>
+                        <!-- agent_done -->
+                        <div v-else-if="step.type === 'agent_done'" class="step-item step-agent-done">
+                          <div class="step-content">
+                            <span class="step-desc">{{ step.message }}</span>
+                          </div>
                         </div>
                       </div>
                     </div>
@@ -95,7 +103,7 @@
               </div>
             </div>
 
-            <div v-if="message.content" class="message-text" v-html="renderMarkdown(message.content)"></div>
+            <div v-if="message.content" class="message-text" v-html="renderMarkdown(message.content, tableIcons)"></div>
             <div v-if="message.wordDownloadUrl" class="word-download-area">
               <a-button type="link" @click="emit('download-word', message.wordDownloadUrl)"> 下载报告文件 (.docx) </a-button>
             </div>
@@ -107,8 +115,8 @@
           </div>
           <!-- AI消息操作栏 -->
           <div class="message-actions">
-            <div class="action-btn" @click="copyMessageContent(message.content)" title="复制">
-              <img :src="copyIcon" width="14" height="14" />
+            <div class="action-btn" @click="copyMessageContent(message.content, index)" :title="copiedMessageIndex === index ? '复制成功' : '复制'">
+              <img :src="copyIconUrl(index)" width="14" height="14" />
             </div>
             <span v-if="message.createdAt" class="action-time">{{ formatFullTime(message.createdAt) }}</span>
           </div>
@@ -117,7 +125,7 @@
         <!-- 用户消息 -->
         <div v-else class="user-message">
           <div class="message-body">
-            <div class="message-text" v-html="renderMarkdown(message.content)"></div>
+            <div class="message-text" v-html="renderMarkdown(message.content, tableIcons)"></div>
             <div v-if="message.attachedFile" class="attached-file-card" @click="emit('file-preview', message.attachedFile)">
               <div class="file-icon-card"></div>
               <div class="file-info-card">
@@ -128,8 +136,8 @@
           </div>
           <!-- 用户消息操作栏 -->
           <div class="message-actions">
-            <div class="action-btn" @click="copyMessageContent(message.content)" title="复制">
-              <img :src="copyIcon" width="14" height="14" />
+            <div class="action-btn" @click="copyMessageContent(message.content, index)" :title="copiedMessageIndex === index ? '复制成功' : '复制'">
+              <img :src="copyIconUrl(index)" width="14" height="14" />
             </div>
             <span v-if="message.createdAt" class="action-time">{{ formatFullTime(message.createdAt) }}</span>
           </div>
@@ -148,7 +156,7 @@
         <div class="table-preview-header">
           <span class="table-preview-title">表格预览</span>
           <div class="table-preview-close" @click="closePreview">
-            <img :src="closeIcon" width="16" height="16" />
+            <img :src="getCssUrl('--img-chat-close-icon-btn')" width="16" height="16" />
           </div>
         </div>
         <div class="table-preview-body" v-html="previewTableHtml"></div>
@@ -158,13 +166,28 @@
 </template>
 
 <script setup lang="ts">
-  import { ref, reactive, onMounted, onBeforeUnmount } from 'vue';
+  import { ref, reactive, computed, onMounted, onBeforeUnmount } from 'vue';
   import dayjs from 'dayjs';
   import { renderMarkdown, formatFileSize, tableHtmlToMarkdown, tableHtmlToCsv } from './utils';
   import type { Message, AttachedFile, ThinkingStep } from './types';
-  import arrowIcon from '@/assets/images/ventAI/chatModalBlue/4-2.svg';
-  import copyIcon from '@/assets/images/ventAI/chatModalBlue/4-3.svg';
-  import closeIcon from '@/assets/images/ventAI/chatModalBlue/4-4.svg';
+
+  const getCssUrl = (varName: string) => {
+    const val = getComputedStyle(document.documentElement).getPropertyValue(varName).trim();
+    return val.replace(/^url\(["']?/, '').replace(/["']?\)$/, '');
+  };
+
+  const tableIcons = {
+    copy: getCssUrl('--img-chat-copy-icon'),
+    download: getCssUrl('--img-chat-download-icon-btn'),
+    preview: getCssUrl('--img-chat-preview-icon'),
+    copySuccess: getCssUrl('--img-chat-copy-success-icon'),
+  };
+
+  const copyIconUrl = computed(() => {
+    const icon = getCssUrl('--img-chat-copy-icon');
+    const successIcon = getCssUrl('--img-chat-copy-success-icon');
+    return (index: number) => (copiedMessageIndex.value === index ? successIcon : icon);
+  });
 
   // 全局计时器 - 每秒刷新一次,用于实时显示思考耗时
   const nowTs = ref(Date.now());
@@ -198,9 +221,10 @@
   }>();
 
   const messagesRef = ref<HTMLElement>();
-  const expandedThinking = reactive<Record<number, boolean>>({});
+  const collapsedThinking = reactive<Record<number, boolean>>({});
   const expandedAgents = reactive<Record<string, boolean>>({});
   const isAtBottom = ref(true);
+  const copiedMessageIndex = ref(-1);
 
   // 表格预览状态
   const previewTableHtml = ref('');
@@ -219,15 +243,36 @@
     switch (action) {
       case 'copy': {
         const markdown = tableHtmlToMarkdown(tableHtml);
-        navigator.clipboard.writeText(markdown).catch(() => {
-          const ta = document.createElement('textarea');
-          ta.value = markdown;
-          ta.style.position = 'fixed';
-          ta.style.opacity = '0';
-          document.body.appendChild(ta);
-          ta.select();
-          document.execCommand('copy');
-          document.body.removeChild(ta);
+        const doCopy = async () => {
+          try {
+            await navigator.clipboard.writeText(markdown);
+          } catch {
+            const ta = document.createElement('textarea');
+            ta.value = markdown;
+            ta.style.position = 'fixed';
+            ta.style.opacity = '0';
+            document.body.appendChild(ta);
+            ta.select();
+            document.execCommand('copy');
+            document.body.removeChild(ta);
+          }
+        };
+        doCopy().then(() => {
+          const btn = target;
+          const img = btn.querySelector('img');
+          const successIcon = btn.dataset.iconSuccess;
+          const originalIcon = btn.dataset.icon;
+          if (img && successIcon) {
+            img.src = successIcon;
+            btn.title = '复制成功';
+            const reset = () => {
+              img.src = originalIcon!;
+              btn.title = '复制Markdown';
+              wrapper.removeEventListener('mouseleave', reset);
+            };
+            const wrapper = btn.closest('.markdown-table-wrapper')!;
+            wrapper.addEventListener('mouseleave', reset);
+          }
         });
         break;
       }
@@ -269,6 +314,14 @@
     }
   };
 
+  const forceScrollToBottom = () => {
+    const el = messagesRef.value;
+    if (el) {
+      el.scrollTop = el.scrollHeight;
+    }
+    isAtBottom.value = true;
+  };
+
   onMounted(() => {
     messagesRef.value?.addEventListener('click', handleTableAction);
     messagesRef.value?.addEventListener('scroll', checkScrollBottom);
@@ -286,14 +339,26 @@
     }
   });
 
-  const toggleThinking = (index: number) => {
-    expandedThinking[index] = !expandedThinking[index];
+  const toggleThinkingCard = (index: number) => {
+    collapsedThinking[index] = !collapsedThinking[index];
   };
 
   const toggleAgent = (key: string) => {
     expandedAgents[key] = !expandedAgents[key];
   };
 
+  const getLatestStepMessage = (group: AgentGroup): string => {
+    if (group.steps.length === 0) return '';
+    const last = group.steps[group.steps.length - 1];
+    if (last.type === 'executing') return last.message || '正在执行...';
+    if (last.type === 'tool_call') return last.message || last.tool || '';
+    if (last.type === 'tool_result') return last.message || '';
+    if (last.type === 'agent_start') return last.message || '';
+    if (last.type === 'agent_done') return last.message || '';
+    if (last.type === 'updated_todo_list') return '任务列表已更新';
+    return '';
+  };
+
   interface AgentGroup {
     agent: string;
     steps: ThinkingStep[];
@@ -324,10 +389,11 @@
     return dayjs(createdAt).format('YYYY-MM-DD HH:mm:ss');
   };
 
-  const copyMessageContent = async (content: string) => {
+  const copyMessageContent = async (content: string, index: number) => {
     if (!content) return;
     try {
       await navigator.clipboard.writeText(content);
+      copiedMessageIndex.value = index;
     } catch {
       const textarea = document.createElement('textarea');
       textarea.value = content;
@@ -337,10 +403,11 @@
       textarea.select();
       document.execCommand('copy');
       document.body.removeChild(textarea);
+      copiedMessageIndex.value = index;
     }
   };
 
-  defineExpose({ messagesRef, isAtBottom });
+  defineExpose({ messagesRef, isAtBottom, forceScrollToBottom });
 </script>
 
 <style scoped lang="less">
@@ -356,9 +423,26 @@
     flex: 1;
     overflow-y: auto;
     padding: 20px;
+    position: relative;
+
+    .welcome-empty {
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      display: flex;
+      align-items: center;
+      justify-content: center;
+
+      .welcome-img {
+        max-width: 300px;
+        max-height: 300px;
+        object-fit: contain;
+      }
+    }
 
     .message-wrapper {
-      margin-bottom: 20px;
+      // margin-bottom: 20px;
 
       .ai-message {
         display: flex;
@@ -385,16 +469,14 @@
           /* 思考过程卡片 */
           .thinking-card {
             margin-bottom: 12px;
-            border: 1px solid rgba(63, 80, 106, 0.4);
-            border-radius: 8px;
-            background: rgba(10, 132, 255, 0.04);
             overflow: hidden;
 
-            .thinking-header {
+            .thinking-duration-bar {
               display: flex;
               align-items: center;
               justify-content: space-between;
-              padding: 10px 14px;
+              padding: 8px 14px;
+              border-bottom: 1px solid rgba(63, 80, 106, 0.3);
               cursor: pointer;
               user-select: none;
               transition: background 0.2s;
@@ -403,6 +485,28 @@
                 background: rgba(10, 132, 255, 0.08);
               }
 
+              .thinking-duration {
+                font-size: 16px;
+                color: #8b949e;
+              }
+
+              .thinking-arrow {
+                color: #8b949e;
+                display: flex;
+                align-items: center;
+                transition: transform 0.2s;
+
+                &.expanded {
+                  transform: rotate(180deg);
+                }
+              }
+            }
+
+            .thinking-header {
+              display: flex;
+              align-items: center;
+              padding: 10px 14px;
+
               .thinking-header-left {
                 display: flex;
                 align-items: center;
@@ -412,17 +516,15 @@
               .thinking-icon {
                 width: 16px;
                 height: 16px;
-                background-image: var(--img-chat-thinking-icon, none);
+                background-image: var(--img-chat-thinking-icon);
                 background-repeat: no-repeat;
                 background-size: 100% 100%;
-                /* fallback: 用一个 brain/lightbulb emoji 风格的 SVG */
-                background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M8 1.5a4.5 4.5 0 0 1 3.5 7.35V11a1 1 0 0 1-1 1H5.5a1 1 0 0 1-1-1v-2.15A4.5 4.5 0 0 1 8 1.5Z' stroke='%230a84ff' stroke-width='1.2'/%3E%3Cpath d='M6 13.5h4M6.5 15h3' stroke='%230a84ff' stroke-width='1.2' stroke-linecap='round'/%3E%3C/svg%3E");
               }
 
               .thinking-title {
                 font-size: 13px;
                 font-weight: 500;
-                color: #0a84ff;
+                color: #8b949e;
               }
 
               .thinking-count {
@@ -432,36 +534,21 @@
                 padding: 1px 6px;
                 border-radius: 10px;
               }
-
-              .thinking-duration {
-                font-size: 12px;
-                color: #8b949e;
-                margin-left: 4px;
-              }
-            }
-
-            .thinking-arrow {
-              color: #8b949e;
-              display: flex;
-              align-items: center;
-              transition: transform 0.2s;
-
-              &.expanded {
-                transform: rotate(180deg);
-              }
             }
 
             .thinking-body {
-              border-top: 1px solid rgba(63, 80, 106, 0.3);
               padding: 8px 14px;
-              max-height: 400px;
-              overflow-y: auto;
 
               .agent-group {
                 margin-bottom: 8px;
-                border: 1px solid rgba(63, 80, 106, 0.25);
+                border: 1px solid transparent;
                 border-radius: 6px;
                 overflow: hidden;
+                transition: border-color 0.2s;
+
+                &.expanded {
+                  border-color: rgba(63, 80, 106, 0.25);
+                }
 
                 &:last-child {
                   margin-bottom: 0;
@@ -474,7 +561,6 @@
                   padding: 8px 12px;
                   cursor: pointer;
                   user-select: none;
-                  background: rgba(10, 132, 255, 0.06);
                   transition: background 0.2s;
 
                   &:hover {
@@ -490,7 +576,7 @@
                   .agent-group-icon {
                     width: 14px;
                     height: 14px;
-                    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14' fill='none'%3E%3Ccircle cx='7' cy='5' r='2.5' stroke='%230a84ff' stroke-width='1'/%3E%3Cpath d='M2.5 12.5c0-2.49 2.01-4.5 4.5-4.5s4.5 2.01 4.5 4.5' stroke='%230a84ff' stroke-width='1' stroke-linecap='round'/%3E%3C/svg%3E");
+                    background-image: var(--img-chat-agent-icon);
                     background-repeat: no-repeat;
                     background-size: 100% 100%;
                     flex-shrink: 0;
@@ -499,20 +585,37 @@
                   .agent-group-name {
                     font-size: 13px;
                     font-weight: 500;
-                    color: #0a84ff;
+                    color: #fff;
                   }
 
-                  .agent-group-count {
-                    font-size: 11px;
+                  .agent-group-latest {
+                    font-size: 12px;
                     color: #8b949e;
-                    background: rgba(10, 132, 255, 0.08);
-                    padding: 1px 5px;
-                    border-radius: 8px;
+                    margin-left: 8px;
+                    overflow: hidden;
+                    text-overflow: ellipsis;
+                    white-space: nowrap;
+                    flex: 1;
+                    min-width: 0;
+                  }
+
+                  .agent-arrow {
+                    margin-left: 8px;
+                    flex-shrink: 0;
+                    display: flex;
+                    align-items: center;
+                    transition: transform 0.2s;
+
+                    &.expanded {
+                      transform: rotate(180deg);
+                    }
                   }
                 }
 
                 .agent-group-body {
                   padding: 4px 12px;
+                  max-height: 300px;
+                  overflow-y: auto;
                 }
               }
 
@@ -520,7 +623,6 @@
                 .step-item {
                   display: flex;
                   align-items: flex-start;
-                  gap: 8px;
                   padding: 6px 0;
                   border-bottom: 1px solid rgba(63, 80, 106, 0.15);
 
@@ -528,15 +630,6 @@
                     border-bottom: none;
                   }
 
-                  .step-icon {
-                    width: 18px;
-                    height: 18px;
-                    flex-shrink: 0;
-                    margin-top: 1px;
-                    background-repeat: no-repeat;
-                    background-size: 100% 100%;
-                  }
-
                   .step-content {
                     flex: 1;
                     font-size: 13px;
@@ -567,25 +660,8 @@
                   }
                 }
 
-                /* agent_start */
-                .step-agent-start .step-icon {
-                  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none'%3E%3Ccircle cx='9' cy='6' r='3' stroke='%230a84ff' stroke-width='1.2'/%3E%3Cpath d='M3 16c0-3.31 2.69-6 6-6s6 2.69 6 6' stroke='%230a84ff' stroke-width='1.2' stroke-linecap='round'/%3E%3C/svg%3E");
-                }
-
-                /* tool_call */
-                .step-tool-call .step-icon {
-                  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none'%3E%3Cpath d='M10.5 2.5l5 5-8 8H2.5v-5.5l8-8Z' stroke='%23d29922' stroke-width='1.2' stroke-linejoin='round'/%3E%3Cpath d='M7 7l4 4' stroke='%23d29922' stroke-width='1.2'/%3E%3C/svg%3E");
-                }
-
-                /* executing */
-                .step-executing .step-icon {
-                  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none'%3E%3Ccircle cx='9' cy='9' r='7' stroke='%230a84ff' stroke-width='1.2' stroke-dasharray='4 2'%3E%3CanimateTransform attributeName='transform' type='rotate' from='0 9 9' to='360 9 9' dur='2s' repeatCount='indefinite'/%3E%3C/circle%3E%3C/svg%3E");
-                }
-
                 /* updated_todo_list */
-                .step-todo .step-icon {
-                  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none'%3E%3Crect x='2' y='2' width='14' height='14' rx='2' stroke='%233fb950' stroke-width='1.2'/%3E%3Cpath d='M5 9l3 3 5-6' stroke='%233fb950' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
-
+                .step-todo {
                   .todo-list {
                     .todo-item {
                       display: flex;
@@ -617,16 +693,6 @@
                     }
                   }
                 }
-
-                /* tool_result */
-                .step-tool-result .step-icon {
-                  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none'%3E%3Ccircle cx='9' cy='9' r='7' stroke='%233fb950' stroke-width='1.2'/%3E%3Cpath d='M6 9l2 2 4-4' stroke='%233fb950' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
-                }
-
-                /* agent_done */
-                .step-agent-done .step-icon {
-                  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none'%3E%3Ccircle cx='9' cy='9' r='7' stroke='%233fb950' stroke-width='1.2'/%3E%3Cpath d='M5.5 9l2.5 2.5 4.5-5' stroke='%233fb950' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
-                }
               }
             }
           }
@@ -919,7 +985,7 @@
       }
 
       .ai-message .message-actions {
-        padding: 4px 0 0 50px;
+        padding: 4px 0 0 10px;
       }
 
       .user-message .message-actions {

+ 2 - 2
src/views/ventAI/manageAssistent/components/chatModal/FilePreviewPanel.vue

@@ -64,7 +64,7 @@
       cursor: pointer;
       width: 36px;
       height: 36px;
-      background-image: var(--img-chat-upload-bg);
+      background-image: var(--img-chat-close-bg);
       background-repeat: no-repeat;
       background-size: 100% 100%;
       display: flex;
@@ -77,7 +77,7 @@
       .btn-close-icon {
         width: 20px;
         height: 20px;
-        background-image: var(--img-chat-close-icon);
+        background-image: var(--img-chat-minimize-icon);
         background-repeat: no-repeat;
         background-size: 100% 100%;
       }

+ 76 - 87
src/views/ventAI/manageAssistent/components/chatModal/TaskListPanel.vue

@@ -1,13 +1,19 @@
 <template>
   <div class="task-list-panel">
+    <!-- 操作区域(顶部) -->
+    <div class="options-area">
+      <div v-for="item in optionItems" :key="item.type" :class="['options-area-item', `options-${item.type}`]" @click="handleOptionClick(item.type)">
+        <div class="options-img">
+          <div class="options-icon"></div>
+        </div>
+        <a-button size="small" type="primary">{{ item.label }}</a-button>
+      </div>
+    </div>
+
     <!-- 搜索模式 -->
     <div v-if="activeOption === 'search'" class="search-header">
       <a-input v-model:value="searchKeyword" placeholder="搜索任务名称..." allow-clear size="small" class="search-input" />
     </div>
-    <!-- 历史记录模式 -->
-    <div v-else class="task-header">
-      <span class="task-title">历史记录</span>
-    </div>
 
     <div class="task-list">
       <div
@@ -17,26 +23,15 @@
         @click="emit('switch-task', task.id)"
       >
         <span class="task-name">{{ task.name }}</span>
-        <div class="task-delete" @click.stop="emit('delete-task', task, index)">
-          <DeleteOutlined />
+        <div class="task-right">
+          <span class="task-time">{{ formatRelativeTime(task.updatedAt) }}</span>
+          <div class="task-delete" @click.stop="emit('delete-task', task, index)">
+            <DeleteOutlined />
+          </div>
         </div>
       </div>
       <div v-if="activeOption === 'search' && searchKeyword && filteredTaskList.length === 0" class="empty-hint"> 未找到匹配的任务 </div>
     </div>
-
-    <div class="options-area">
-      <div
-        v-for="item in optionItems"
-        :key="item.type"
-        :class="['options-area-item', `options-${item.type}`, { active: activeOption === item.type }]"
-        @click="handleOptionClick(item.type)"
-      >
-        <div class="options-img">
-          <div class="options-icon"></div>
-        </div>
-        <a-button size="small" type="primary">{{ item.label }}</a-button>
-      </div>
-    </div>
   </div>
 </template>
 
@@ -56,15 +51,15 @@
     (e: 'delete-task', task: Task, index: number): void;
   }>();
 
-  type OptionType = 'search' | 'history' | 'add';
+  type OptionType = 'add' | 'search' | 'skill';
 
-  const activeOption = ref<OptionType>('history');
+  const activeOption = ref<OptionType>('add');
   const searchKeyword = ref('');
 
   const optionItems = [
-    { type: 'search' as OptionType, label: '内容搜索' },
-    { type: 'history' as OptionType, label: '历史记录' },
-    { type: 'add' as OptionType, label: '新增任务' },
+    { type: 'add' as OptionType, label: '新建任务' },
+    { type: 'search' as OptionType, label: '搜索' },
+    { type: 'skill' as OptionType, label: '技能' },
   ];
 
   const filteredTaskList = computed(() => {
@@ -75,15 +70,24 @@
     return props.taskList.filter((task) => task.name.toLowerCase().includes(keyword));
   });
 
-  const handleAddTask = () => {
-    emit('create-task');
+  const formatRelativeTime = (dateStr?: string) => {
+    if (!dateStr) return '刚刚';
+    const now = Date.now();
+    const time = new Date(dateStr).getTime();
+    const diff = now - time;
+    if (diff < 60 * 1000) return '刚刚';
+    if (diff < 60 * 60 * 1000) return `${Math.floor(diff / (60 * 1000))}分钟前`;
+    if (diff < 24 * 60 * 60 * 1000) return `${Math.floor(diff / (60 * 60 * 1000))}小时前`;
+    return `${Math.floor(diff / (24 * 60 * 60 * 1000))}天前`;
   };
 
   const handleOptionClick = (type: OptionType) => {
-    activeOption.value = type;
     if (type === 'add') {
       emit('create-task');
+    } else if (type === 'skill') {
+      // TODO: 技能点击事件
     } else {
+      activeOption.value = type;
       searchKeyword.value = '';
     }
   };
@@ -92,6 +96,7 @@
 <style scoped lang="less">
   .task-list-panel {
     width: 260px;
+    height: 100%;
     display: flex;
     flex-direction: column;
     background-image: var(--img-chat-task-panel-bg);
@@ -117,31 +122,12 @@
       }
     }
 
-    .task-header {
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      padding-bottom: 10px;
-
-      .task-title {
-        font-size: 15px;
-        line-height: 1.4;
-        color: #0a84ff;
-      }
-      .task-add-btn {
-        background-color: #0a84ff;
-
-        &:hover {
-          background-color: #0077e6;
-        }
-      }
-    }
-
     .task-list {
       flex: 1;
       overflow-y: auto;
 
       .task-item {
+        height: 36px;
         display: flex;
         align-items: center;
         gap: 10px;
@@ -157,8 +143,9 @@
         }
 
         &.active {
-          background: rgba(10, 132, 255, 0.1);
-          box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+          background: transparent;
+          box-shadow: inset 0 0 8px rgba(10, 132, 255, 0.4);
+          border: 1px solid rgba(10, 132, 255, 0.3);
           color: #e0e6ed;
         }
 
@@ -181,17 +168,23 @@
           flex: 1;
         }
 
+        .task-time {
+          font-size: 12px;
+          color: #8b949e;
+          flex-shrink: 0;
+          white-space: nowrap;
+        }
+
         .task-delete {
           flex-shrink: 0;
           width: 28px;
           height: 28px;
-          display: flex;
+          display: none;
           align-items: center;
           justify-content: center;
           border-radius: 4px;
           color: #8b949e;
           font-size: 14px;
-          visibility: hidden;
           transition: all 0.2s;
 
           &:hover {
@@ -200,8 +193,12 @@
           }
         }
 
+        &:hover .task-time {
+          display: none;
+        }
+
         &:hover .task-delete {
-          visibility: visible;
+          display: flex;
         }
       }
 
@@ -215,73 +212,65 @@
 
     .options-area {
       display: flex;
-      gap: 6px;
-      padding-top: 8px;
-      border-top: 1px solid rgba(63, 80, 106, 0.3);
+      flex-direction: column;
+      gap: 4px;
+      padding-bottom: 10px;
+      border-bottom: 1px solid rgba(63, 80, 106, 0.3);
 
       .options-area-item {
-        flex: 1;
         display: flex;
-        flex-direction: column;
+        flex-direction: row;
         align-items: center;
-        gap: 6px;
+        gap: 10px;
         cursor: pointer;
         border-radius: 6px;
+        padding: 6px 8px;
         transition: all 0.3s;
 
+        &:hover {
+          background: rgba(10, 132, 255, 0.1);
+        }
+
         .options-img {
-          width: 60px;
-          height: 60px;
+          width: 32px;
+          height: 32px;
           display: flex;
           align-items: center;
           justify-content: center;
-          background-image: var(--img-chat-options-bg);
+          flex-shrink: 0;
+          background-image: var(--img-chat-options-icon-border);
           background-repeat: no-repeat;
-          background-size: 45px 45px;
+          background-size: 100% 100%;
           background-position: center;
         }
 
-        &.active .options-img {
-          background-image: var(--img-chat-options-active-bg);
-          background-size: 60px 60px;
-        }
-
         .options-icon {
-          width: 16px;
-          height: 16px;
+          width: 14px;
+          height: 14px;
           background-repeat: no-repeat;
           background-size: 100% 100%;
           background-position: center;
         }
 
-        &.options-search .options-icon {
-          background-image: var(--img-chat-options-search-icon);
-        }
-        &.options-search.active .options-icon {
-          background-image: var(--img-chat-options-search-active-icon);
+        &.options-add .options-icon {
+          background-image: var(--img-chat-options-add-icon);
         }
 
-        &.options-history .options-icon {
-          background-image: var(--img-chat-options-history-icon);
-        }
-        &.options-history.active .options-icon {
-          background-image: var(--img-chat-options-history-active-icon);
+        &.options-search .options-icon {
+          background-image: var(--img-chat-options-search-icon);
         }
 
-        &.options-add .options-icon {
-          background-image: var(--img-chat-options-add-icon);
-        }
-        &.options-add.active .options-icon {
-          background-image: var(--img-chat-options-add-active-icon);
+        &.options-skill .options-icon {
+          background-image: var(--img-chat-options-skill-icon);
         }
 
         .zxm-btn {
           font-size: 14px;
-          padding: 2px 6px;
+          padding: 0;
           height: auto;
           background: transparent !important;
           border: none;
-          color: #0a84ff;
+          color: #e0e6ed;
           box-shadow: none;
         }
       }

+ 0 - 397
src/views/ventAI/manageAssistent/components/chatModal/ThinkingPanel.vue

@@ -1,397 +0,0 @@
-<template>
-  <div class="thinking-panel">
-    <div class="panel-header">
-      <div class="panel-left">
-        <div class="agent-avatar-small"></div>
-        <div class="panel-title-group">
-          <div class="panel-title">{{ currentDisplayAgent?.agentName || '智能分析' }}</div>
-        </div>
-      </div>
-      <div class="close-btn" @click="emit('close')">
-        <div class="btn-close-icon"></div>
-      </div>
-    </div>
-
-    <div class="thinking-section">
-      <div class="section-content thinking-content" ref="thinkingContentRef">
-        <div v-if="!thinkingSections.length" class="empty-thinking">暂无思考过程</div>
-        <div v-for="(section, idx) in thinkingSections" :key="idx" :class="['timeline-item', `timeline-${section.type}`]">
-          <div class="timeline-marker">
-            <div class="timeline-dot"></div>
-            <div v-if="idx < thinkingSections.length - 1" class="timeline-line"></div>
-          </div>
-          <div class="timeline-body">
-            <div class="timeline-header">
-              <span class="timeline-label">{{ section.label }}</span>
-            </div>
-            <div class="timeline-text" v-html="renderMarkdown(section.content)"></div>
-          </div>
-        </div>
-      </div>
-    </div>
-
-    <div class="agent-horizontal-list" v-if="selectedAgentParentMsg?.agentAnswers?.length">
-      <div
-        v-for="agent in selectedAgentParentMsg!.agentAnswers"
-        :key="agent.id"
-        :class="['agent-chip', { active: currentDisplayAgent?.id === agent.id }]"
-        @click="emit('select-agent', agent)"
-      >
-        <div class="chip-body">
-          <div class="chip-icon"></div>
-          <div class="chip-name">
-            {{ agent.agentName || '智能分析' }}
-          </div>
-        </div>
-        <div class="chip-status">
-          <span v-if="agent.status === 'thinking'">正在连接</span>
-          <span v-else>已完成</span>
-        </div>
-        <div class="chip-border"></div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-  import { ref } from 'vue';
-  import { renderMarkdown } from './utils';
-  import type { AgentAnswer, Message, ThinkingSection } from './types';
-
-  defineProps<{
-    currentDisplayAgent: AgentAnswer | null;
-    selectedAgentParentMsg: Message | null;
-    thinkingSections: ThinkingSection[];
-  }>();
-
-  const emit = defineEmits<{
-    (e: 'select-agent', answer: AgentAnswer): void;
-    (e: 'close'): void;
-  }>();
-
-  const thinkingContentRef = ref<HTMLElement | null>(null);
-
-  defineExpose({ thinkingContentRef });
-</script>
-
-<style scoped lang="less">
-  .thinking-panel {
-    height: 100%;
-    width: 100%;
-    display: flex;
-    flex-direction: column;
-    padding: 12px 16px;
-
-    .panel-header {
-      display: flex;
-      padding: 0;
-      justify-content: space-between;
-      align-items: center;
-      margin-bottom: 6px;
-      flex-shrink: 0;
-
-      .panel-left {
-        display: flex;
-        align-items: center;
-        gap: 12px;
-      }
-
-      .agent-avatar-small {
-        width: 35px;
-        height: 36px;
-        border-radius: 8px;
-        background-image: var(--img-chat-panel-header);
-        background-repeat: no-repeat;
-        background-size: 100% 100%;
-        flex-shrink: 0;
-      }
-
-      .panel-title-group {
-        display: flex;
-        flex-direction: column;
-        line-height: 1;
-      }
-
-      .panel-title {
-        font-size: 15px;
-        font-weight: 600;
-        line-height: 1.4;
-        color: #0a84ff;
-      }
-      .close-btn {
-        cursor: pointer;
-        width: 36px;
-        height: 36px;
-        background-image: var(--img-chat-upload-bg);
-        background-repeat: no-repeat;
-        background-size: 100% 100%;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        flex-shrink: 0;
-        transition: all 0.3s;
-        margin-bottom: auto;
-
-        .btn-close-icon {
-          width: 20px;
-          height: 20px;
-          background-image: var(--img-chat-close-icon);
-          background-repeat: no-repeat;
-          background-size: 100% 100%;
-        }
-      }
-    }
-
-    .thinking-section {
-      flex: 1;
-      height: 0;
-      display: flex;
-      flex-direction: column;
-      border: 1px solid #0a84ff;
-      border-radius: 4px 4px 0 0;
-
-      .thinking-content {
-        flex: 1;
-        background: rgba(10, 132, 255, 0.05);
-        border: 1px solid rgba(63, 80, 106, 0.5);
-        border-radius: 8px;
-        padding: 20px 16px;
-        overflow-y: auto;
-        font-size: 12px;
-        font-weight: 400;
-        color: #e0e6ed;
-        line-height: 1.6;
-
-        .empty-thinking {
-          color: #8b949e;
-          font-style: italic;
-          text-align: center;
-          padding: 32px 0;
-        }
-
-        .timeline-item {
-          display: flex;
-          gap: 0;
-          position: relative;
-
-          .timeline-marker {
-            display: flex;
-            flex-direction: column;
-            align-items: center;
-            width: 28px;
-            flex-shrink: 0;
-            position: relative;
-          }
-
-          .timeline-dot {
-            width: 12px;
-            height: 12px;
-            border-radius: 50%;
-            border: 2px solid #fff;
-            flex-shrink: 0;
-            margin-top: 6px;
-            position: relative;
-            z-index: 1;
-          }
-
-          .timeline-line {
-            flex: 1;
-            width: 0;
-            min-height: 16px;
-            margin: 4px 0;
-            border-left: 2px dashed #8b949e;
-          }
-
-          &.timeline-select {
-            .timeline-dot {
-              background: #0a84ff;
-              box-shadow: 0 0 0 3px rgba(10, 132, 255, 0.15);
-            }
-            .timeline-header {
-              color: #e0e6ed;
-            }
-          }
-          &.timeline-params {
-            display: none;
-            .timeline-dot {
-              background: #faad14;
-              box-shadow: 0 0 0 3px rgba(223, 91, 12, 0.15);
-            }
-            .timeline-header {
-              color: #e0e6ed;
-            }
-          }
-          &.timeline-result {
-            .timeline-dot {
-              background: #52c41a;
-              box-shadow: 0 0 0 3px rgba(46, 125, 50, 0.15);
-            }
-          }
-
-          .timeline-body {
-            flex: 1;
-            min-width: 0;
-            padding-bottom: 16px;
-            padding-left: 12px;
-          }
-
-          .timeline-header {
-            font-size: 13px;
-            font-weight: 500;
-            margin-bottom: 8px;
-            line-height: 1.4;
-          }
-
-          .timeline-text {
-            font-size: 14px;
-            font-weight: 400;
-            color: #e0e6ed;
-            line-height: 1.6;
-
-            :deep(p) {
-              margin: 0 0 6px;
-            }
-            :deep(code) {
-              background: rgba(10, 132, 255, 0.1);
-              padding: 2px 6px;
-              border-radius: 3px;
-              font-family: monospace;
-              font-size: 12px;
-            }
-            :deep(pre) {
-              background: rgba(10, 132, 255, 0.1);
-              padding: 10px;
-              border-radius: 4px;
-              overflow-x: auto;
-              margin: 8px 0;
-            }
-            :deep(pre code) {
-              background: transparent;
-              padding: 0;
-            }
-            :deep(ul),
-            :deep(ol) {
-              padding-left: 20px;
-              margin: 4px 0;
-            }
-            :deep(li) {
-              margin-bottom: 2px;
-            }
-            :deep(h1),
-            :deep(h2),
-            :deep(h3),
-            :deep(h4) {
-              margin: 8px 0 4px;
-              font-weight: 600;
-            }
-            :deep(blockquote) {
-              border-left: 3px solid rgba(63, 80, 106, 0.5);
-              padding-left: 12px;
-              margin: 8px 0;
-              color: #8b949e;
-            }
-            :deep(table) {
-              border-collapse: collapse;
-              width: 100%;
-              margin: 8px 0;
-            }
-            :deep(th),
-            :deep(td) {
-              border: 1px solid rgba(63, 80, 106, 0.5);
-              padding: 6px 10px;
-              text-align: left;
-            }
-            :deep(th) {
-              background: rgba(10, 132, 255, 0.1);
-              font-weight: 600;
-            }
-            :deep(strong) {
-              font-weight: 600;
-            }
-          }
-        }
-      }
-    }
-
-    .agent-horizontal-list {
-      display: flex;
-      gap: 10px;
-      padding: 8px 0;
-      overflow-x: auto;
-      align-items: center;
-      flex-shrink: 0;
-      border-radius: 0 0 4px 4px;
-      border-top: none;
-      background-color: rgba(10, 132, 255, 0.05);
-    }
-
-    .agent-chip {
-      display: flex;
-      align-items: center;
-      gap: 10px;
-      padding: 8px 12px 8px 20px;
-      background: rgba(10, 132, 255, 0.08);
-      border-radius: 10px;
-      border: 1px solid rgba(63, 80, 106, 0.5);
-      min-width: 140px;
-      cursor: pointer;
-      transition: all 0.2s;
-      position: relative;
-
-      .chip-body {
-        display: flex;
-        align-items: start;
-        gap: 8px;
-        flex-direction: column;
-      }
-
-      .chip-border {
-        position: absolute;
-        left: 10px;
-        top: 16px;
-        width: 5px;
-        height: 35px;
-        border: 2px solid #0a84ff;
-        pointer-events: none;
-        border-right: none;
-      }
-      .chip-icon {
-        width: 24px;
-        height: 24px;
-        background-image: var(--img-chat-thinking-bg);
-        background-repeat: no-repeat;
-        background-size: 100% 100%;
-      }
-      .chip-name {
-        font-size: 13px;
-        font-weight: 500;
-        line-height: 1.4;
-        color: #e0e6ed;
-        white-space: nowrap;
-        overflow: hidden;
-        text-overflow: ellipsis;
-        width: 100px;
-      }
-
-      .chip-status {
-        font-size: 11px;
-        font-weight: 400;
-        line-height: 1.3;
-        color: #8b949e;
-        position: absolute;
-        top: 10px;
-        right: 10px;
-      }
-
-      &.active {
-        background-color: rgba(10, 132, 255, 0.12);
-        box-shadow: 0 6px 18px rgba(10, 132, 255, 0.06);
-        border-color: #0a84ff;
-
-        .chip-status {
-          color: #0a84ff;
-        }
-      }
-    }
-  }
-</style>

+ 1 - 0
src/views/ventAI/manageAssistent/components/chatModal/types.ts

@@ -53,6 +53,7 @@ export interface Task {
   messages: Message[];
   attachedFiles: AttachedFile[];
   wordUrl?: string;
+  updatedAt?: string;
 }
 
 export type SectionType = 'select' | 'params' | 'result';

+ 7 - 7
src/views/ventAI/manageAssistent/components/chatModal/utils.ts

@@ -1,25 +1,25 @@
 import { marked } from 'marked';
 
-export const renderMarkdown = (text: string): string => {
+export const renderMarkdown = (text: string, icons?: { copy: string; download: string; preview: string; copySuccess: string }): string => {
   if (!text) return '';
   const processed = text.replace(/<br\s*\/?>/gi, '  \n');
   const html = marked.parse(processed) as string;
-  return wrapTables(html);
+  return icons ? wrapTables(html, icons) : html;
 };
 
-const wrapTables = (html: string): string => {
+export const wrapTables = (html: string, icons: { copy: string; download: string; preview: string; copySuccess: string }): string => {
   return html.replace(/<table>([\s\S]*?)<\/table>/g, (match) => {
     const encodedTable = encodeURIComponent(match);
     return `<div class="markdown-table-wrapper">
       <div class="table-actions">
-        <span class="table-action-btn" data-action="copy" data-table="${encodedTable}" title="复制Markdown">
-          <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="4.5" y="4.5" width="7" height="7" rx="1" stroke="currentColor" stroke-width="1.2"/><path d="M9.5 4.5V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v5.5a1 1 0 0 0 1 1h1.5" stroke="currentColor" stroke-width="1.2"/></svg>
+        <span class="table-action-btn" data-action="copy" data-table="${encodedTable}" data-icon="${icons.copy}" data-icon-success="${icons.copySuccess}" title="复制Markdown">
+          <img src="${icons.copy}" width="14" height="14" />
         </span>
         <span class="table-action-btn" data-action="csv" data-table="${encodedTable}" title="下载CSV">
-          <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v7M4 7l3 3 3-3M3 12h8" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
+          <img src="${icons.download}" width="14" height="14" />
         </span>
         <span class="table-action-btn" data-action="preview" data-table="${encodedTable}" title="预览表格">
-          <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="1" y="1" width="12" height="12" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M1 5h12M1 9h12M5 1v12M9 1v12" stroke="currentColor" stroke-width="1.2"/></svg>
+          <img src="${icons.preview}" width="14" height="14" />
         </span>
       </div>
       ${match}

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů