Browse Source

添加导出及文献知识库任务监控

yangg 7 months ago
parent
commit
1ff507919b
70 changed files with 1361 additions and 172 deletions
  1. 3 2
      .env.development
  2. 0 0
      dist/index.html
  3. 0 0
      dist/static/css/chunk-016e5c0e.210d0353.css
  4. 0 1
      dist/static/css/chunk-10bfc27e.6044f932.css
  5. 0 0
      dist/static/css/chunk-240a34fe.13ca31d4.css
  6. 0 0
      dist/static/css/chunk-2bb7cc0a.e7ff2f91.css
  7. 1 0
      dist/static/css/chunk-3429c79e.29a5f1a6.css
  8. 0 0
      dist/static/css/chunk-3ab88ac2.f7015c45.css
  9. 1 0
      dist/static/css/chunk-4a670a7f.e09c1a2a.css
  10. 0 0
      dist/static/css/chunk-5c6eee35.5e1eb2f5.css
  11. 0 0
      dist/static/css/chunk-5d47eef5.172a45be.css
  12. 0 0
      dist/static/css/chunk-5f2ff500.df38a7bc.css
  13. 0 0
      dist/static/css/chunk-6ec5c8f6.4e41c7ab.css
  14. 0 0
      dist/static/css/chunk-85a6c838.775a21e3.css
  15. 0 0
      dist/static/css/chunk-a239f95e.c30800b1.css
  16. 0 0
      dist/static/css/chunk-a61249b0.cf8f9f2d.css
  17. 0 0
      dist/static/css/chunk-b83b1a34.30cf7b33.css
  18. 0 0
      dist/static/css/chunk-c46a82fe.6d7ac802.css
  19. 0 1
      dist/static/css/chunk-dbd45e38.46a88685.css
  20. 0 1
      dist/static/css/chunk-f0e12ffc.3401da8f.css
  21. 0 0
      dist/static/css/chunk-fa78c2d4.f7015c45.css
  22. 0 0
      dist/static/js/app.60e751ba.js
  23. 0 0
      dist/static/js/chunk-0074d5fe.5c548739.js
  24. 0 0
      dist/static/js/chunk-016e5c0e.8e936c43.js
  25. 0 0
      dist/static/js/chunk-079de15b.f02245ea.js
  26. 0 0
      dist/static/js/chunk-0c69682a.47a2a742.js
  27. 0 0
      dist/static/js/chunk-10bfc27e.1fe82521.js
  28. 0 0
      dist/static/js/chunk-138f7583.d42376cc.js
  29. 0 0
      dist/static/js/chunk-240a34fe.7ae7f5bc.js
  30. 0 0
      dist/static/js/chunk-2bb7cc0a.97525803.js
  31. 2 0
      dist/static/js/chunk-2d216214.6db767db.js
  32. 0 0
      dist/static/js/chunk-338eb143.42e3db80.js
  33. 0 0
      dist/static/js/chunk-3429c79e.cc16357b.js
  34. 0 0
      dist/static/js/chunk-35a1fd98.d4cfc313.js
  35. 0 0
      dist/static/js/chunk-388d864f.851b6941.js
  36. 0 0
      dist/static/js/chunk-3ab88ac2.1f293b16.js
  37. 0 0
      dist/static/js/chunk-48f27aa5.6cc16cc7.js
  38. 0 0
      dist/static/js/chunk-4a670a7f.cd9e5300.js
  39. 0 0
      dist/static/js/chunk-4ac7f82e.17490404.js
  40. 0 0
      dist/static/js/chunk-4ac7f82e.6188aaa1.js
  41. 0 0
      dist/static/js/chunk-534f5a65.6cf360c8.js
  42. 0 0
      dist/static/js/chunk-5c6eee35.99b57c03.js
  43. 0 0
      dist/static/js/chunk-5d47eef5.0350fcf8.js
  44. 0 0
      dist/static/js/chunk-5f2ff500.a8624792.js
  45. 0 0
      dist/static/js/chunk-6ec5c8f6.063b6a0d.js
  46. 0 0
      dist/static/js/chunk-6f0044a0.8c7340af.js
  47. 0 0
      dist/static/js/chunk-708604c0.4534fef5.js
  48. 0 0
      dist/static/js/chunk-72e66010.791f4cac.js
  49. 0 0
      dist/static/js/chunk-72e66010.8c872c81.js
  50. 1 1
      dist/static/js/chunk-85a6c838.c1bbaf69.js
  51. 0 0
      dist/static/js/chunk-9235c1ae.81ac9858.js
  52. 0 0
      dist/static/js/chunk-9235c1ae.b7d96db4.js
  53. 0 0
      dist/static/js/chunk-a239f95e.dd37555f.js
  54. 0 0
      dist/static/js/chunk-a61249b0.2d618739.js
  55. 0 0
      dist/static/js/chunk-b83b1a34.3883aeb1.js
  56. 0 0
      dist/static/js/chunk-c0d178b4.dc121bb2.js
  57. 0 0
      dist/static/js/chunk-c46a82fe.626ca9aa.js
  58. 0 0
      dist/static/js/chunk-cda0aa98.7cfab00f.js
  59. 0 0
      dist/static/js/chunk-dbd45e38.b383ae3a.js
  60. 0 0
      dist/static/js/chunk-e08ed888.b7a2af8a.js
  61. 0 0
      dist/static/js/chunk-f0e12ffc.a2e53f2c.js
  62. 0 0
      dist/static/js/chunk-fa78c2d4.82c9c341.js
  63. 11 0
      src/api/document.js
  64. 19 0
      src/api/knowledge.js
  65. 535 16
      src/views/dashboard/admin/chart.vue
  66. 389 53
      src/views/knowledgeMenu/category/knowledgeSet.vue
  67. 27 5
      src/views/login/aiIndex.vue
  68. 12 15
      src/views/middPage/index.vue
  69. 213 59
      src/views/middPage/list.vue
  70. 147 18
      src/views/project/components/dataList.vue

+ 3 - 2
.env.development

@@ -4,5 +4,6 @@ port = 8080
 # base api
 VUE_APP_BASE_API = 'http://192.168.66.208:8084'
 #192.168.66.208
-#测试服务器:121.36.251.245:8084
-#183.195.216.54
+#朱:192.168.66.163
+#测试服务器:121.36.251.245
+#线上:183.195.216.54

File diff suppressed because it is too large
+ 0 - 0
dist/index.html


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/chunk-016e5c0e.210d0353.css


+ 0 - 1
dist/static/css/chunk-10bfc27e.6044f932.css

@@ -1 +0,0 @@
-.sub-imgs{padding:0;margin:0}.sub-imgs li{float:left;margin-right:10px;width:100px;height:100px;list-style:none}.data-search{padding:20px 10px 0 10px}.data-list .btns,.data-list .page-info{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.data-list .page-info{margin-top:10px}.data-list .page-info .opt{width:50%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.data-list .page-info .opt .pick{width:100px}.data-list .page-info .opt .section{margin-left:10px}.data-list .page-info .page-data{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%}.data-list .page-info .page-data .page-item{width:100%}.data-list .page-info .page-data .page-opt{width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.project-search{padding:30px;font-size:12px}

File diff suppressed because it is too large
+ 0 - 0
dist/static/css/chunk-240a34fe.13ca31d4.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/chunk-2bb7cc0a.e7ff2f91.css


+ 1 - 0
dist/static/css/chunk-3429c79e.29a5f1a6.css

@@ -0,0 +1 @@
+.gpu-list[data-v-0476dc06]{padding:20px}.filter-section[data-v-0476dc06]{margin-bottom:20px}.ml-15[data-v-0476dc06]{margin-left:15px}.pagination[data-v-0476dc06]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;margin-top:15px}.progress-wrapper[data-v-0476dc06],.status-wrapper[data-v-0476dc06]{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-transition:none!important;transition:none!important}.progress-wrapper[data-v-0476dc06]{padding:2px}.progress-wrapper[data-v-0476dc06] .el-progress{line-height:1;-webkit-transition:none!important;transition:none!important}.progress-wrapper[data-v-0476dc06] .el-progress .el-progress__text{font-size:12px!important;color:inherit;-webkit-transition:none!important;transition:none!important}.progress-wrapper[data-v-0476dc06] .el-progress .el-progress-circle{margin:0;-webkit-transition:none!important;transition:none!important}.progress-wrapper[data-v-0476dc06] .el-progress .el-progress-circle__path,.progress-wrapper[data-v-0476dc06] .el-progress .el-progress-circle__track,.progress-wrapper[data-v-0476dc06] .el-progress svg{-webkit-transition:none!important;transition:none!important}

File diff suppressed because it is too large
+ 0 - 0
dist/static/css/chunk-3ab88ac2.f7015c45.css


+ 1 - 0
dist/static/css/chunk-4a670a7f.e09c1a2a.css

@@ -0,0 +1 @@
+.midd-page[data-v-779c8190]{padding:20px}.el-icon-edit[data-v-779c8190]{font-size:14px;color:#409eff}[data-v-779c8190] .model-gen-1{background-color:#e6f3ff!important}[data-v-779c8190] .model-gen-1.el-table__cell{background-color:#e6f3ff!important;color:#333!important}[data-v-779c8190] .model-gen-2{background-color:#f0e6ff!important}[data-v-779c8190] .model-gen-2.el-table__cell{background-color:#f0e6ff!important;color:#333!important}.header[data-v-779c8190]{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;margin:15px 0}.h_left[data-v-779c8190],.header[data-v-779c8190]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.h_left p[data-v-779c8190]{margin-right:45px;margin-top:0}.search-container[data-v-779c8190]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.search-box[data-v-779c8190]{width:350px}.custom-search-input[data-v-779c8190] :deep(.el-input__inner){height:40px;line-height:40px;border-right:none;border-radius:4px 0 0 4px}.custom-search-input[data-v-779c8190] :deep(.el-input-group__append){padding:0;border:none;background-color:transparent}.custom-search-input[data-v-779c8190] :deep(.el-input-group__append .el-button){height:40px;padding:0 20px;border-radius:0 4px 4px 0;margin:0}.custom-search-input[data-v-779c8190] :deep(.el-input__inner:hover){border-color:#dcdfe6}.custom-search-input[data-v-779c8190] :deep(.el-input__inner:focus){border-color:#409eff}

File diff suppressed because it is too large
+ 0 - 0
dist/static/css/chunk-5c6eee35.5e1eb2f5.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/chunk-5d47eef5.172a45be.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/chunk-5f2ff500.df38a7bc.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/chunk-6ec5c8f6.4e41c7ab.css


+ 0 - 0
dist/static/css/chunk-696e880a.775a21e3.css → dist/static/css/chunk-85a6c838.775a21e3.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/chunk-a239f95e.c30800b1.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/chunk-a61249b0.cf8f9f2d.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/chunk-b83b1a34.30cf7b33.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/chunk-c46a82fe.6d7ac802.css


+ 0 - 1
dist/static/css/chunk-dbd45e38.46a88685.css

@@ -1 +0,0 @@
-.gpu-list[data-v-61823c94]{padding:20px}.filter-section[data-v-61823c94]{margin-bottom:20px}.ml-15[data-v-61823c94]{margin-left:15px}.pagination[data-v-61823c94]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;margin-top:15px}

+ 0 - 1
dist/static/css/chunk-f0e12ffc.3401da8f.css

@@ -1 +0,0 @@
-.midd-page[data-v-45cd76d1]{padding:20px}.el-icon-edit[data-v-45cd76d1]{font-size:14px;color:#409eff}[data-v-45cd76d1] .model-gen-1{background-color:#e6f3ff!important}[data-v-45cd76d1] .model-gen-1.el-table__cell{background-color:#e6f3ff!important;color:#333!important}[data-v-45cd76d1] .model-gen-2{background-color:#f0e6ff!important}[data-v-45cd76d1] .model-gen-2.el-table__cell{background-color:#f0e6ff!important;color:#333!important}.header[data-v-45cd76d1]{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:15px 0}.h_left[data-v-45cd76d1],.header[data-v-45cd76d1]{display:-webkit-box;display:-ms-flexbox;display:flex}.h_left p[data-v-45cd76d1]{margin-right:45px;margin-top:0}.search-container[data-v-45cd76d1]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.search-box[data-v-45cd76d1]{width:350px}.custom-search-input[data-v-45cd76d1] :deep(.el-input__inner){height:40px;line-height:40px;border-right:none;border-radius:4px 0 0 4px}.custom-search-input[data-v-45cd76d1] :deep(.el-input-group__append){padding:0;border:none;background-color:transparent}.custom-search-input[data-v-45cd76d1] :deep(.el-input-group__append .el-button){height:40px;padding:0 20px;border-radius:0 4px 4px 0;margin:0}.custom-search-input[data-v-45cd76d1] :deep(.el-input__inner:hover){border-color:#dcdfe6}.custom-search-input[data-v-45cd76d1] :deep(.el-input__inner:focus){border-color:#409eff}

File diff suppressed because it is too large
+ 0 - 0
dist/static/css/chunk-fa78c2d4.f7015c45.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/app.60e751ba.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-0074d5fe.5c548739.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-016e5c0e.8e936c43.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-079de15b.f02245ea.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-0c69682a.47a2a742.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-10bfc27e.1fe82521.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-138f7583.d42376cc.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-240a34fe.7ae7f5bc.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-2bb7cc0a.97525803.js


File diff suppressed because it is too large
+ 2 - 0
dist/static/js/chunk-2d216214.6db767db.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-338eb143.42e3db80.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-3429c79e.cc16357b.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-35a1fd98.d4cfc313.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-388d864f.851b6941.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-3ab88ac2.1f293b16.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-48f27aa5.6cc16cc7.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-4a670a7f.cd9e5300.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-4ac7f82e.17490404.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-4ac7f82e.6188aaa1.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-534f5a65.6cf360c8.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-5c6eee35.99b57c03.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-5d47eef5.0350fcf8.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-5f2ff500.a8624792.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-6ec5c8f6.063b6a0d.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-6f0044a0.8c7340af.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-708604c0.4534fef5.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-72e66010.791f4cac.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-72e66010.8c872c81.js


File diff suppressed because it is too large
+ 1 - 1
dist/static/js/chunk-85a6c838.c1bbaf69.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-9235c1ae.81ac9858.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-9235c1ae.b7d96db4.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-a239f95e.dd37555f.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-a61249b0.2d618739.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-b83b1a34.3883aeb1.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-c0d178b4.dc121bb2.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-c46a82fe.626ca9aa.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-cda0aa98.7cfab00f.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-dbd45e38.b383ae3a.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-e08ed888.b7a2af8a.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-f0e12ffc.a2e53f2c.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-fa78c2d4.82c9c341.js


+ 11 - 0
src/api/document.js

@@ -152,3 +152,14 @@ export function searchlistDoc(data) {
     data
   })
 }
+
+
+/* 导出pdf */
+
+export function exportToPDF(data) {
+  return request({
+    url: 'document/exportToPDF',
+    method: 'post',
+    data
+  })
+}

+ 19 - 0
src/api/knowledge.js

@@ -361,6 +361,14 @@ export function configDelete(data) {
       method: 'get',
     })
   } 
+  /* 文献处理 */
+  export function literResult(data) {
+    return request({
+      url: `tasks/literResult/?literature_id=${data}`,
+      method: 'get',
+    })
+  } 
+
   /* 获取解析结果  */
   
   export function getDetail(data) {
@@ -742,4 +750,15 @@ export function projectTemUpdate(data) {
     method: 'post',
     data
   })
+}
+
+
+/* task/clear/ */
+
+export function endClear(data) {
+  return request({
+    url: 'task/clear/',
+    method: 'post',
+    data
+  })
 }

+ 535 - 16
src/views/dashboard/admin/chart.vue

@@ -38,7 +38,7 @@
                       </div>
                     </div> -->
 
-                    <div class="col-xl-8">
+                    <div class="col-xl-6">
                       <div class="card">
                         <div class="card-header">
                           <div class="row">
@@ -81,13 +81,175 @@
                           </div>
                           <div
                             ref="siteVisitorChart"
-                            style="height: 285px; width: 100%"
+                            style="height: 245px; width: 100%"
                           ></div>
                         </div>
                       </div>
                     </div>
-                    <!--  -->
-                    <div class="col-xl-4">
+                    <div class="col-xl-3">
+                      <div class="row">
+                        <!-- GPU温度 -->
+                        <div class="col-xl-12 col-md-6">
+                          <div class="card">
+                            <div class="card-body">
+                              <div
+                                class="row"
+                                style="display: flex; align-items: center"
+                              >
+                                <div class="col-auto">
+                                  <h6>温度监控</h6>
+                                </div>
+                              </div>
+                              <div class="row">
+                                <!-- CPU温度 -->
+                                <div class="col-6">
+                                  <h2 class="mb-0" style="margin-top: 20px !important">
+                                    {{ cpuTemperature }}°C
+                                  </h2>
+                                  <span>CPU温度</span>
+                                  <div class="temperature-select-wrapper" style="margin-top: 15px">
+                                    <select
+                                      class="temperature-select"
+                                      :value="Math.round(cpuTemperature / temperatureData.cpu.critical)"
+                                      disabled
+                                    >
+                                      <option v-for="n in 24" :key="`cpu-${n}`" :value="n"></option>
+                                    </select>
+                                    <div
+                                      class="temperature-progress"
+                                      :style="{
+                                        width: `${(cpuTemperature / temperatureData.cpu.critical) * 100}%`,
+                                        backgroundColor: getTemperatureColor(cpuTemperature, 'cpu'),
+                                      }"
+                                    ></div>
+                                  </div>
+                                </div>
+                                <!-- GPU温度 -->
+                                <div class="col-6">
+                                  <h2 class="mb-0" style="margin-top: 20px !important">
+                                    {{ gpuTemperature }}°C
+                                  </h2>
+                                  <span>GPU温度</span>
+                                  <div class="temperature-select-wrapper" style="margin-top: 15px">
+                                    <select
+                                      class="temperature-select"
+                                      :value="Math.round(gpuTemperature / temperatureData.gpu.critical)"
+                                      disabled
+                                    >
+                                      <option v-for="n in 24" :key="`gpu-${n}`" :value="n"></option>
+                                    </select>
+                                    <div
+                                      class="temperature-progress"
+                                      :style="{
+                                        width: `${(gpuTemperature / temperatureData.gpu.critical) * 100}%`,
+                                        backgroundColor: getTemperatureColor(gpuTemperature, 'gpu'),
+                                      }"
+                                    ></div>
+                                  </div>
+                                </div>
+                              </div>
+                            </div>
+                          </div>
+                        </div>
+                        <!-- 磁盘信息 -->
+                        <div class="col-xl-12 col-md-6">
+                          <div class="card">
+                            <div class="card-body">
+                              <div class="row">
+                                <div class="col-6">
+                                  <h6>磁盘信息</h6>
+                                </div>
+                              </div>
+                              <div class="row">
+                                <div class="col-12">
+                                  <div
+                                    ref="diskChart"
+                                    style="height: 110px"
+                                  ></div>
+                                </div>
+                              </div>
+                            </div>
+                          </div>
+                        </div>
+
+                        <!--  <div class="col-xl-12 col-md-6">
+                          <div class="card">
+                            <div class="card-body">
+                              <h6>Traffic tracker</h6>
+                              <div class="row mt-2">
+                                <div class="col-6">
+                                  <span class="d-block text-uppercase"
+                                    >Inbound</span
+                                  >
+                                  <h3 class="mt-1">180 GB</h3>
+                                  <div
+                                    ref="transactions1"
+                                    style="
+                                      height: 50px;
+                                      width: 100%;
+                                      margin: 0 auto;
+                                    "
+                                  ></div>
+                                </div>
+                                <div class="col-6">
+                                  <span class="d-block text-uppercase"
+                                    >Outbound</span
+                                  >
+                                  <h3 class="mt-1">597.1 GB</h3>
+                                  <div
+                                    ref="transactions2"
+                                    style="
+                                      height: 50px;
+                                      width: 100%;
+                                      margin: 0 auto;
+                                    "
+                                  ></div>
+                                </div>
+                              </div>
+                            </div>
+                          </div>
+                        </div>
+                        <div class="col-xl-12 col-md-6">
+                          <div class="card">
+                            <div class="card-body">
+                              <div class="row d-flex align-items-center">
+                                <div class="col-6 p-r-0">
+                                  <span class="d-block mb-1"
+                                    ><i
+                                      class="fas fa-circle f-10 m-r-5"
+                                      style="color: #a367dc"
+                                    ></i
+                                    >Desktop [66.6%]</span
+                                  >
+                                  <span class="d-block mb-1"
+                                    ><i
+                                      class="fas fa-circle f-10 m-r-5"
+                                      style="color: #67b7dc"
+                                    ></i
+                                    >Mobile [29.7%]</span
+                                  >
+                                  <span class="d-block"
+                                    ><i
+                                      class="fas fa-circle f-10 m-r-5"
+                                      style="color: #6771dc"
+                                    ></i
+                                    >Tablet [38.6%]</span
+                                  >
+                                </div>
+                                <div class="col-6">
+                                  <div
+                                    ref="deviceChart"
+                                    id="device-chart"
+                                    style="height: 140px"
+                                  ></div>
+                                </div>
+                              </div>
+                            </div>
+                          </div>
+                        </div> -->
+                      </div>
+                    </div>
+                    <div class="col-xl-3">
                       <div class="row">
                         <!-- 支持分析卡片 -->
                         <div class="col-xl-12 col-md-6">
@@ -134,10 +296,10 @@
                                   </h6>
                                 </div>
                                 <div class="col">
-                                  <!-- 支持工单完成图表 -->
+                                  <!-- 支持工单完成图表 -->
                                   <div
                                     ref="hdComplitedTicket"
-                                    style="height: 130px; width: 100%"
+                                    style="height: 100px; width: 100%"
                                   ></div>
                                 </div>
                               </div>
@@ -241,7 +403,7 @@
                                   <!-- 设备占比饼图 -->
                                   <div
                                     ref="chartPercent"
-                                    style="height: 131px"
+                                    style="height: 100px"
                                   ></div>
                                 </div>
                               </div>
@@ -446,7 +608,10 @@ export default {
   },
   data() {
     return {
-      charts: {}, // 存储图表实例
+      charts: {
+        diskChart: null,
+        // 其他图表...
+      },
       chartData: {},
       currentPercentage: {},
       cpuValue: 0,
@@ -461,6 +626,20 @@ export default {
       docList: {},
       chartUpdateInterval: null, // 添加新的数据属性用于存储定时器
       isPageVisible: !document.hidden, // 添加新的数据属性
+      cpuTemperature: 0,
+      gpuTemperature: 0,
+      temperatureData: {
+        cpu: {
+          current: 0,
+          high: 95,    // 默认CPU高温阈值
+          critical: 100 // 默认CPU临界温度
+        },
+        gpu: {
+          current: 0,
+          high: 85,    // 默认GPU高温阈值
+          critical: 90  // 默认GPU临界温度
+        }
+      }
     };
   },
   watch: {
@@ -479,7 +658,7 @@ export default {
         if (newValue) {
           // 页面变为可见时
           console.log("Page became visible");
-           this.initSiteVisitorChart();
+          this.initSiteVisitorChart();
         } else {
           // 页面变为不可见时
           console.log("Page became hidden");
@@ -502,6 +681,8 @@ export default {
     this.initSiteVisitorChart(); // 添加这行
     this.initTransactionCharts();
     this.initDeviceChart(); // 添加这行
+    this.initDiskChart();
+ 
   },
 
   // 修改生命周期钩子
@@ -568,7 +749,7 @@ export default {
         try {
           const data = JSON.parse(event.data);
           // 检查数据结构是否完整
-          console.log("wsData",data);
+          /* console.log("gpuTemperature", this.gpuTemperature); */
           if (
             data &&
             data.data &&
@@ -576,12 +757,16 @@ export default {
             data.data.system.cpu &&
             data.data.system.cpu.memory
           ) {
-            
             // 更新图表数据
             this.chartData = data;
             this.cpuValue = data.data.system.cpu.total_usage;
             this.GpuValue = data.data.system.gpu.devices[0]?.power || 0;
+            // 更新 GPU 温度
+           /*  this.gpuTemperature =
+              data.data.system.gpu.devices[0]?.temperature || 0; */
+
             this.currentPercentage = data.data.system.cpu.memory;
+            this.handleWebSocketMessage(data)
           } else {
             console.warn("Received incomplete data structure:", data);
           }
@@ -593,6 +778,10 @@ export default {
       // 连接关闭回调
       this.ws.onclose = () => {
         console.log("WebSocket连接关闭");
+        // 可以添加重连逻辑
+        setTimeout(() => {
+          this.initWebSocket();
+        }, 3000);
       };
 
       // 连接错误回调
@@ -601,6 +790,14 @@ export default {
       };
     },
 
+    // 添加一个用于检查 WebSocket 连接状态的方法
+    checkWebSocketConnection() {
+      if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
+        console.log("WebSocket disconnected, attempting to reconnect...");
+        this.initWebSocket();
+      }
+    },
+
     // 初始化支持工单完成率图表
     initHdComplitedTicket() {
       const chart = am4core.create(
@@ -610,7 +807,7 @@ export default {
       chart.logo.disabled = true;
       chart.innerRadius = am4core.percent(82);
 
-      // 修改主配置
+      // 修改主配置
       const axis = chart.xAxes.push(new am4charts.ValueAxis());
       axis.min = 0;
       axis.max = 100;
@@ -705,7 +902,7 @@ export default {
 
       chart.padding(0, 0, 0, 0);
 
-      // 保存表实例和定时器
+      // 保存表实例和定时器
       this.charts.hdComplitedTicket = {
         chart: chart,
         interval: interval,
@@ -935,7 +1132,7 @@ export default {
       gpuBullet.fill = am4core.color("#19BCBF");
       gpuBullet.isMeasured = false;
 
-      // 更新两个系列圆点位置
+      // 更新两个系列圆点位置
       cpuSeries.events.on("validated", () => {
         cpuBullet.moveTo(cpuSeries.dataItems.last.point);
         cpuBullet.validatePosition();
@@ -1248,7 +1445,7 @@ export default {
       return colors[type.toLowerCase()] || "#666666";
     },
 
-    // 计算化率
+    // 计算化率
     getChangePercentage(type) {
       const currentCount = this.fileTypeCounts[type] || 0;
       const previousCount = this.previousCounts[type] || currentCount;
@@ -1305,6 +1502,220 @@ export default {
         return merged;
       }, {});
     },
+
+    // 处理WebSocket消息的方法修改
+    handleWebSocketMessage(data) {
+      try {
+        if (data?.data?.system?.temperature) {
+          this.updateTemperatures(data.data.system.temperature);
+        }
+      } catch (error) {
+        console.error("Error processing WebSocket message:", error);
+      }
+    },
+
+    updateTemperatures(temperatureData) {
+      // 更新CPU温度
+      if (temperatureData.cpu && Array.isArray(temperatureData.cpu)) {
+        // 获取Package温度作为主要CPU温度
+        const packageTemp = temperatureData.cpu.find(temp => temp.label === 'Package id 0');
+        if (packageTemp) {
+          this.temperatureData.cpu = {
+            current: packageTemp.current,
+            high: packageTemp.high || this.temperatureData.cpu.high,
+            critical: packageTemp.critical || this.temperatureData.cpu.critical
+          };
+          this.cpuTemperature = packageTemp.current;
+        }
+
+        // 记录最高核心温度用于告警
+        const maxCoreTemp = Math.max(
+          ...temperatureData.cpu
+            .filter(temp => temp.label.startsWith('Core'))
+            .map(temp => temp.current)
+        );
+        if (maxCoreTemp > this.temperatureData.cpu.high) {
+          console.warn(`CPU temperature warning: ${maxCoreTemp}°C`);
+        }
+      }
+
+      // 更新GPU温度
+      if (temperatureData.gpu && temperatureData.gpu.length > 0) {
+        const gpuTemp = temperatureData.gpu[0];
+        this.temperatureData.gpu.current = gpuTemp.temperature;
+        this.gpuTemperature = gpuTemp.temperature;
+        
+        if (gpuTemp.temperature > this.temperatureData.gpu.high) {
+          console.warn(`GPU temperature warning: ${gpuTemp.temperature}°C`);
+        }
+      }
+    },
+
+    getTemperatureColor(temp, type = 'cpu') {
+      const thresholds = this.temperatureData[type];
+      const percentage = (temp / thresholds.critical) * 100;
+
+      if (percentage >= 90) return "#FF425C";     // 危险温度 - 红色
+      if (percentage >= 70) return "#FFA726";     // 警告温度 - 橙色
+      return "#19BCBF";                           // 正常温度 - 蓝色
+    },
+
+    // 初始化磁盘图表
+    initDiskChart() {
+      try {
+        // 创建环形图实例
+        const chart = am4core.create(this.$refs.diskChart, am4charts.PieChart);
+        if (!chart) return;
+
+        // 禁用 logo
+        if (chart.logo) {
+          chart.logo.disabled = true;
+        }
+
+        // 设置内半径创建环形效果
+        chart.innerRadius = am4core.percent(65);
+
+        // 添加数据
+        chart.data = this.formatDiskData();
+
+        // 创建饼图系列
+        const series = chart.series.push(new am4charts.PieSeries());
+        if (series) {
+          // 配置数据字段
+          series.dataFields.value = "used";
+          series.dataFields.category = "diskName";
+
+          // 禁用标签和刻度
+          series.labels.template.disabled = true;
+          series.ticks.template.disabled = true;
+
+          // 配置切片样式
+          if (series.slices.template) {
+            series.slices.template.strokeWidth = 2;
+            series.slices.template.strokeOpacity = 1;
+            series.slices.template.stroke = am4core.color("#fff");
+
+            // 设置切片颜色
+            series.slices.template.adapter.add("fill", (fill, target) => {
+              const dataItem = target.dataItem;
+              if (dataItem) {
+                const percentUsed = (dataItem.values.value.value / dataItem.dataContext.total) * 100;
+                if (percentUsed > 80) return am4core.color("#FF425C"); // 危险
+                if (percentUsed > 60) return am4core.color("#FFA726"); // 警告
+                return am4core.color("#19BCBF"); // 正常
+              }
+              return fill;
+            });
+
+            // 配置悬浮提示
+            series.slices.template.tooltipHTML = `
+              <div style="padding: 10px;">
+                <div style="margin-bottom: 5px;color:#333;"><strong>{diskName}</strong></div>
+                <div style="color: #666;">总容量: {total.formatNumber('#.##')} GB</div>
+                <div style="color: #FF425C;">已使用: {used.formatNumber('#.##')} GB</div>
+                <div style="color: #19BCBF;">可用空间: {free.formatNumber('#.##')} GB</div>
+                <div style="color: #666;">使用率: {percent.formatNumber('#.##')}%</div>
+              </div>
+            `;
+
+            // 设置悬浮提示样式
+            if (series.tooltip) {
+              series.tooltip.getFillFromObject = false;
+              series.tooltip.pointerOrientation = "vertical";
+              series.tooltip.dy = -5;
+              series.tooltip.dx = 0;
+
+              if (series.tooltip.background) {
+                series.tooltip.background.fill = am4core.color("#ffffff");
+                series.tooltip.background.stroke = am4core.color("#19BCBF");
+                series.tooltip.background.strokeWidth = 1;
+                series.tooltip.background.cornerRadius = 4;
+              }
+            }
+          }
+
+          // 添加中心标签
+          const label = chart.seriesContainer.createChild(am4core.Label);
+          label.text = "{percent.formatNumber('#.#')}%";
+          label.horizontalCenter = "middle";
+          label.verticalCenter = "middle";
+          label.fontSize = 20;
+          label.fontWeight = "600";
+
+          // 更新中心标签的值
+          series.events.on("validated", () => {
+            const total = series.dataItems.getIndex(0).dataContext.total;
+            const used = series.dataItems.getIndex(0).dataContext.used;
+            const percent = (used / total) * 100;
+            label.text = `${percent.toFixed(1)}%`;
+          });
+        }
+
+        // 保存图表实例
+        this.charts.diskChart = chart;
+
+        // 设置自动更新
+        this.startDiskDataInterval();
+      } catch (error) {
+        console.error("初始化磁盘图表失败:", error);
+      }
+    },
+
+    // 格式化磁盘数据
+    formatDiskData() {
+      if (!this.chartData?.data?.system?.cpu?.disk?.partitions) {
+        return [];
+      }
+
+      const diskNameMap = {
+        C: "系统盘",
+        D: "数据盘",
+        E: "扩展盘",
+      };
+
+      return this.chartData.data.system.cpu.disk.partitions
+        .filter(partition => partition.mountpoint === "/")
+        .map(partition => {
+          const driveLetter = partition.device.replace(":\\", "");
+          const diskName = diskNameMap[driveLetter] || `${driveLetter}盘`;
+          return {
+            device: driveLetter,
+            diskName: diskName,
+            used: partition.used,
+            free: partition.free,
+            total: partition.total,
+            percent: partition.percent
+          };
+        });
+    },
+
+    // 启动磁盘数据更新定时器
+    startDiskDataInterval() {
+      if (this.diskUpdateInterval) {
+        clearInterval(this.diskUpdateInterval);
+      }
+
+      this.diskUpdateInterval = setInterval(() => {
+        if (this.charts.diskChart) {
+          this.charts.diskChart.data = this.formatDiskData();
+        }
+      }, 2000); // 每2秒更新一次
+    },
+
+   /*  // 在 WebSocket 消息处理中添加磁盘数据更新
+    handleWebSocketMessage(event) {
+      try {
+        const data = JSON.parse(event.data);
+        if (data?.data?.system?.cpu?.disk) {
+          this.chartData = data;
+          if (this.charts.diskChart) {
+            this.charts.diskChart.data = this.formatDiskData();
+          }
+        }
+      } catch (error) {
+        console.error("Error processing WebSocket message:", error);
+      }
+    }, */
   },
   // 修改beforeDestroy钩子
   beforeDestroy() {
@@ -1346,7 +1757,7 @@ export default {
     border-radius: 2px;
     box-shadow: 0 0px 0 1px #e2e5e8;
     border: none;
-    margin-bottom: 24px;
+    margin-bottom: 17px;
     background: #fff;
 
     .card-body {
@@ -1465,5 +1876,113 @@ export default {
     }
   }
 }
+
+.progress {
+  background-color: #f0f0f0;
+  border-radius: 3px;
+  overflow: hidden;
+}
+
+.progress-bar {
+  transition: width 0.3s ease;
+}
+
+.temperature-select-wrapper {
+  position: relative;
+  width: 100%;
+  height: 20px;
+
+  .temperature-select {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    appearance: none;
+    background: transparent;
+    border: none;
+    pointer-events: none;
+    z-index: 1;
+
+    &::-ms-expand {
+      display: none;
+    }
+
+    option {
+      background: transparent;
+    }
+  }
+
+  .temperature-progress {
+    position: absolute;
+    top: 0;
+    left: 0;
+    height: 100%;
+    background-color: #19bcbf;
+    transition: width 0.3s ease;
+    border-radius: 3px;
+
+    &::after {
+      content: "";
+      position: absolute;
+      top: 0;
+      right: 0;
+      width: 100%;
+      height: 100%;
+      background: repeating-linear-gradient(
+        90deg,
+        currentColor,
+        currentColor 4px,
+        transparent 4px,
+        transparent 8px
+      );
+      opacity: 0.2;
+    }
+  }
+}
+
+// 添加条纹背景
+.temperature-select-wrapper::before {
+  content: "";
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: repeating-linear-gradient(
+    90deg,
+    #e0e0e0,
+    #e0e0e0 4px,
+    #f0f0f0 4px,
+    #f0f0f0 8px
+  );
+  border-radius: 3px;
+}
+
+// 更新温度进度条样式
+.temperature-select-wrapper {
+  margin-bottom: 10px;
+  
+  .temperature-progress {
+    transition: all 0.3s ease;
+    
+    &::after {
+      opacity: 0.15;
+    }
+  }
+}
+
+// 添加新的温度显示样式
+.col-6 {
+  h2 {
+    font-size: 24px;
+    font-weight: 600;
+  }
+  
+  span {
+    color: #666;
+    font-size: 14px;
+  }
+}
 </style>
 <style src="./css/bootstrap.min.css"  scoped></style>

+ 389 - 53
src/views/knowledgeMenu/category/knowledgeSet.vue

@@ -64,24 +64,59 @@
         element-loading-text="加载中..."
       >
         <div class="batch-actions" style="margin: 10px 0">
-          <el-button
-            type="primary"
-            @click="batchAnalysis"
+          <el-dropdown
+            @command="handleBatchCommand"
             :disabled="!selectedRows.length"
-            >批量解析</el-button
           >
-          <el-button
-            type="primary"
-            @click="batchModifyFolder"
-            :disabled="!selectedRows.length"
-            >批量修改目录</el-button
-          >
-          <el-button
-            type="primary"
-            @click="batchDelect"
-            :disabled="!selectedRows.length"
-            >批量删除</el-button
+            <el-button type="primary" style="color: #fff">
+              批量操作
+              <i data-feather="chevron-down" class="el-icon--right icons"></i>
+            </el-button>
+            <el-dropdown-menu slot="dropdown">
+              <el-dropdown-item command="analysis">
+                <i data-feather="play" class="icons"></i> 批量解析
+              </el-dropdown-item>
+              <el-dropdown-item command="modifyFolder">
+                <i data-feather="folder" class="icons"></i> 批量修改目录
+              </el-dropdown-item>
+              <el-dropdown-item command="delete">
+                <i data-feather="trash-2" class="icons"></i> 批量删除
+              </el-dropdown-item>
+            </el-dropdown-menu>
+          </el-dropdown>
+          <el-button type="danger" @click="endAnalysis()">
+            <i data-feather="stop-circle" class="icons"></i>
+            终止所有任务
+          </el-button>
+        </div>
+        <div class="selection-control" v-if="selectedRows.length > 0">
+          <el-alert
+            type="info"
+            show-icon
+            :closable="false"
+            style="margin-bottom: 10px"
           >
+            <template v-if="!isAllDataSelected">
+              <!-- <span>已选择 {{ selectedRows.length }} 项</span> -->
+              <span
+                type="text"
+                style="cursor: pointer; color: #409eff; margin-left: 10px"
+                @click="handleSelectAllData"
+              >
+                选择全部{{ recordCount }}条数据
+              </span>
+            </template>
+            <template v-else>
+              <span>已选择全部{{ recordCount }}条数据</span>
+              <span
+                type="text"
+                style="cursor: pointer; color: #409eff; margin-left: 10px"
+                @click="handleCancelAllSelection"
+              >
+                取消全选
+              </span>
+            </template>
+          </el-alert>
         </div>
         <el-table
           ref="dataTable"
@@ -91,8 +126,13 @@
           empty-text="暂无数据"
           @selection-change="handleSelectionChange"
           @sort-change="handleSortChange"
+          :row-key="getRowKey"
         >
-          <el-table-column type="selection" width="55"></el-table-column>
+          <el-table-column
+            type="selection"
+            width="55"
+            :reserve-selection="true"
+          ></el-table-column>
           <el-table-column prop="id" label="ID" align="center" width="80" />
           <el-table-column prop="name" label="文件名称" sortable width="350">
             <template #default="scope">
@@ -110,9 +150,41 @@
           />
           <el-table-column prop="run" label="解析状态" align="center">
             <template #default="scope">
-              <el-tag :type="getStatusType(scope.row.run)" size="small">
-                {{ getStatusText(scope.row.run) }}
-              </el-tag>
+              <el-tooltip
+                effect="dark"
+                placement="top"
+                :disabled="
+                  Number(scope.row.run) !== 1 &&
+                  Number(scope.row.run) !== 4
+                "
+              >
+                <template #content>
+                  <div style="padding: 5px">
+                    <div style="margin-top: 5px; font-size: 12px">
+                      {{ scope.row.progress_msg || "正在解析中..." }}
+                    </div>
+                  </div>
+                </template>
+                <div class="status-wrapper">
+                  <template v-if="Number(scope.row.run) === 1">
+                    <div class="progress-wrapper">
+                      <el-progress
+                        type="circle"
+                        :percentage="Math.floor(scope.row.progress) || 0"
+                        :width="35"
+                        :stroke-width="4"
+                        :format="percentFormat"
+                       
+                      ></el-progress><!--  :status="getProgressStatus(scope.row.progress)" -->
+                    </div>
+                  </template>
+                  <template v-else>
+                    <el-tag :type="getStatusType(scope.row.run)" size="small">
+                      {{ getStatusText(scope.row.run) }}
+                    </el-tag>
+                  </template>
+                </div>
+              </el-tooltip>
             </template>
           </el-table-column>
           <el-table-column
@@ -176,7 +248,7 @@
                       effect="dark"
                       :content="
                         scope.row.run == 1 || scope.row.run == 5
-                          ? `当前状态:${getStatusText(scope.row.run)/* scope.row.progress */} 解析说明:${scope.row.progress_msg}`
+                          ? `解析中`
                           : '解析'
                       "
                       placement="top"
@@ -412,6 +484,7 @@ import {
   getdocpro,
   analysisPro,
   resultTask,
+  endClear,
 } from "@/api/knowledge";
 export default {
   components: {
@@ -455,7 +528,7 @@ export default {
       },
       wordRules: {
         new_name: [
-          { required: true, message: "请输文件名称", trigger: "blur" },
+          { required: true, message: "请输文件名称", trigger: "blur" },
         ],
       },
       anaDialogVisible: false,
@@ -490,21 +563,51 @@ export default {
           { required: true, message: "请选择目标目录", trigger: "change" },
         ],
       },
+
+      selectedRows: [], // 已选择的行
+      allSelectedRows: new Map(), // 存储所有选中的行
+      isAllDataSelected: false, // 是否选中所有数据
     };
   },
   mounted() {
     this.queryForm.bucket_id = this.$route.query.id;
     this.typeForm.kb_id = this.$route.query.id;
-    this.$nextTick(() => {
+    /* this.$nextTick(() => {
       this.initializeTree();
-    });
+    }); */
     this.typeList();
-    this.search();
+    /* this.search(); */
   },
   beforeDestroy() {
     Object.values(this.analysisStatusCheckers).forEach(clearTimeout);
   },
   methods: {
+    // 获取行的唯一标识
+    getRowKey(row) {
+      return row.id;
+    },
+    /* 功按钮 */
+    handleBatchCommand(command) {
+      switch (command) {
+        case "analysis":
+          this.batchAnalysis();
+          break;
+        case "modifyFolder":
+          this.batchModifyFolder();
+          break;
+        case "delete":
+          this.batchDelect();
+          break;
+      }
+    },
+    getProgressStatus(progress) {
+      // el-progress 只接受 'success'/'exception'/'warning' 这几个值
+      if (progress >= 100) {
+        return "success";
+      }
+      // 如果进度小于100,返回undefined,使用默认样式
+      return undefined;
+    },
     /* 操作栏 */
     handleCommand(command, row) {
       switch (command) {
@@ -525,12 +628,12 @@ export default {
     /* 状态展示 */
     getStatusType(status) {
       const statusMap = {
-        0: "info", // 未解析
+        0: "info",    // 未解析
         1: "warning", // 解析中
         3: "success", // 成功
-        4: "danger", // 失败
-        5: "warning", // 待处理
-        6: "danger", // 文件异常
+        4: "danger",  // 失败
+        5: "info",    // 待解析
+        6: "danger",  // 文件异常
       };
       return statusMap[status] || "info";
     },
@@ -539,9 +642,9 @@ export default {
       const statusMap = {
         0: "未解析",
         1: "解析中",
-        3: "成功",
-        4: "失败",
-        5: "待处理",
+        3: "解析成功",
+        4: "解析失败",
+        5: "待解析",
         6: "文件异常",
       };
       return statusMap[status] || "未知状态";
@@ -691,11 +794,17 @@ export default {
               },
             ];
 
+            // 直接在这里执行一次性的初始化
             this.$nextTick(() => {
-              this.initializeTree();
+              if (this.$refs.folderTree) {
+                this.$refs.folderTree.setCurrentKey("001");
+                // 只在这里调用一次 search
+                this.queryForm.doc_type_id = "";
+                this.search();
+              }
             });
           } else {
-            this.$message.error("获取文件夹列表失败");
+            this.$message.error("获取文件夹列表败");
           }
         })
         .catch((error) => {
@@ -707,14 +816,14 @@ export default {
         });
     },
 
-    initializeTree() {
+    /*  initializeTree() {
       this.$nextTick(() => {
         if (this.$refs.folderTree) {
           this.$refs.folderTree.setCurrentKey(0);
           this.handleNodeClick(this.folders[0]);
         }
       });
-    },
+    }, */
 
     createNewFolder() {
       this.newFolderDialogVisible = true;
@@ -737,15 +846,23 @@ export default {
         }
       });
     },
-
+    // 移除或简化 initializeTree 方法,因为相关逻辑已经到 typeList 中
     initializeTree() {
+      // 可以保留这个方法但不执行 search
       this.$nextTick(() => {
         if (this.$refs.folderTree) {
           this.$refs.folderTree.setCurrentKey("001");
-          this.handleNodeClick(this.folders[0]);
         }
       });
     },
+    /*  initializeTree() {
+      this.$nextTick(() => {
+        if (this.$refs.folderTree) {
+          this.$refs.folderTree.setCurrentKey("001");
+          this.handleNodeClick(this.folders[0]);
+        }
+      });
+    }, */
     checkAuth(path) {
       if (this.roleInfo.is_admin === 1) {
         return true;
@@ -790,9 +907,96 @@ export default {
         return sortOrder === "ascending" ? comparison : -comparison;
       });
     },
-    /* 批量解析 */
-    handleSelectionChange(val) {
-      this.selectedRows = val;
+    /*  处理选择变化*/
+    handleSelectionChange(selection) {
+      if (!this.isAllDataSelected) {
+        // 更新当前页选中状态
+        this.dataList.forEach((row) => {
+          if (selection.find((item) => item.id === row.id)) {
+            this.allSelectedRows.set(row.id, row);
+          } else {
+            this.allSelectedRows.delete(row.id);
+          }
+        });
+
+        this.selectedRows = Array.from(this.allSelectedRows.values());
+      }
+    },
+
+    // 选择全部数据
+    async handleSelectAllData() {
+      try {
+        // 构建查询参数,获取所有数据
+        const params = {
+          ...this.queryForm,
+          page: 1,
+          page_size: this.recordCount,
+        };
+
+        const response = await getBucketContents(params);
+
+        if (response.status === 200) {
+          const allData = response.data.documents;
+
+          // 清空之前的选择
+          this.allSelectedRows.clear();
+
+          // 将所有数据添加到选中集合
+          allData.forEach((item) => {
+            this.allSelectedRows.set(item.id, item);
+          });
+
+          this.isAllDataSelected = true;
+          this.selectedRows = allData;
+
+          // 选中当前页显示的所有行
+          this.$nextTick(() => {
+            if (this.$refs.dataTable) {
+              this.dataList.forEach((row) => {
+                this.$refs.dataTable.toggleRowSelection(row, true);
+              });
+            }
+          });
+
+          this.$message.success(`已选中全部${this.recordCount}条数据`);
+        }
+      } catch (error) {
+        console.error("获取全部数据失败:", error);
+        this.$message.error("选择全部数据失败");
+      }
+    },
+
+    // 取消全选
+    handleCancelAllSelection() {
+      this.clearSelection();
+      this.isAllDataSelected = false;
+      this.$message.info("已取消全部选择");
+    },
+
+    // 修改清除选择方法
+    clearSelection() {
+      if (this.$refs.dataTable) {
+        this.$refs.dataTable.clearSelection();
+      }
+      this.selectedRows = [];
+      this.allSelectedRows.clear();
+      this.isAllDataSelected = false;
+    },
+
+    // 修改分页方法,保持选中状态
+    ChangePage(e) {
+      this.queryForm.page = e;
+      this.search().then(() => {
+        this.$nextTick(() => {
+          if (this.$refs.dataTable) {
+            this.dataList.forEach((row) => {
+              if (this.isAllDataSelected || this.allSelectedRows.has(row.id)) {
+                this.$refs.dataTable.toggleRowSelection(row, true);
+              }
+            });
+          }
+        });
+      });
     },
 
     batchAnalysis() {
@@ -823,7 +1027,7 @@ export default {
             })
             .catch((error) => {
               console.error("批量解析错误:", error);
-              this.$message.error("批量解析过程中出错误");
+              this.$message.error("批量解析过程中出错误");
             })
             .finally(() => {
               this.loading = false;
@@ -897,6 +1101,13 @@ export default {
       a.target = "_blank";
       a.click();
     },
+    /*终止 */
+    endAnalysis() {
+      endClear().then((res) => {
+        if (res.status !== 200) return;
+        this.search();
+      });
+    },
     /* 解析 */
     analysis(row) {
       if (row.run == 1 || row.run == 5) return;
@@ -933,7 +1144,7 @@ export default {
         clearTimeout(this.analysisStatusCheckers[row.id]);
       }
       /* 获取token数 */
-     /*  const checkStatus = () => {
+      /*  const checkStatus = () => {
         getdocpro({ document_id: row.id })
           .then((res) => {
             if (res.status === 200) {
@@ -970,13 +1181,15 @@ export default {
       }; */
       /* 监控任务 */
       const checkStatus = () => {
-         resultTask(row.id)
+        resultTask(row.id)
           .then((res) => {
             if (res.status === 200) {
               const newStatus = Number(res.data.document_status);
-              const newProgress = res.data.progress_msg
+              const newProgress = Number(res.data.progress);
+              const newProgressMsg = res.data.progress_msg;
               this.$set(row, "run", newStatus);
-              this.$set(row, "progress_msg", newProgress);
+              this.$set(row, "progress", newProgress);
+              this.$set(row, "progress_msg", newProgressMsg);
 
               if (newStatus === 3) {
                 this.$message.success("解析成功");
@@ -1188,6 +1401,38 @@ export default {
               start_page: _this.analForm.start_page,
               end_page: _this.analForm.end_page,
             }));
+            // 获取失败状态的文档的失败原因
+            const failedDocs = _this.dataList.filter(
+              (doc) => Number(doc.run) === 4
+            );
+            if (failedDocs.length > 0) {
+              Promise.all(
+                failedDocs.map((doc) =>
+                  resultTask(doc.id)
+                    .then((res) => {
+                      if (res.status === 200) {
+                        // 找到对应的文档并更新其 progress_msg
+                        const docIndex = _this.dataList.findIndex(
+                          (item) => item.id === doc.id
+                        );
+                        if (docIndex !== -1) {
+                          _this.$set(
+                            _this.dataList[docIndex],
+                            "progress_msg",
+                            res.data.progress_msg
+                          );
+                        }
+                      }
+                    })
+                    .catch((error) => {
+                      console.error(
+                        `获取文档 ${doc.id} 的失败原因时出错:`,
+                        error
+                      );
+                    })
+                )
+              );
+            }
             _this.pageTotal = res.data.pagination.total_count;
             _this.recordCount = res.data.pagination.total_count;
             _this.queryForm.pageSize = res.data.pagination.total_size;
@@ -1209,16 +1454,24 @@ export default {
       });
     },
 
-    //修改分页
-    ChangePage(e) {
-      let _this = this;
-      _this.queryForm.page = e;
-      _this.search();
-    },
+    // 处理每页显示数量变化
     handleSizeChange(val) {
       this.queryForm.pageSize = val;
-      this.queryForm.page = 1; // Reset to first page when changing page size
-      this.search();
+      this.queryForm.page = 1;
+      this.search().then(() => {
+        // 恢复选中状态
+        this.$nextTick(() => {
+          this.dataList.forEach((row) => {
+            if (this.pageSelected.has(row.id)) {
+              this.$refs.dataTable.toggleRowSelection(row, true);
+            }
+          });
+        });
+      });
+    },
+    // 添加格式化方法
+    percentFormat(percentage) {
+      return `${percentage}%`;
     },
   },
 };
@@ -1360,6 +1613,89 @@ export default {
 ::v-deep .el-tree-node__expand-icon {
   display: none;
 }
+::v-deep .el-tag {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  height: auto;
+  padding: 5px 10px;
+}
+
+.batch-actions {
+  display: flex;
+  gap: 10px;
+
+  .el-dropdown {
+    /*  margin-right: auto; */
+  }
+  .icons {
+    width: 15px;
+    height: 15px;
+    vertical-align: middle;
+    margin-right: 4px;
+  }
+}
+
+::v-deep .el-dropdown-menu__item {
+  display: flex;
+  align-items: center;
+  padding: 8px 16px;
+  .icons {
+    width: 14px;
+    height: 14px;
+    margin-right: 8px;
+  }
+}
 @import "./components/dataList.scss";
+.status-wrapper {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  transition: none !important;
+}
+
+.progress-wrapper {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  padding: 2px;
+  transition: none !important;
+  
+  ::v-deep .el-progress {
+    line-height: 1;
+    transition: none !important;
+    
+    .el-progress__text {
+      font-size: 12px !important;
+      color: inherit;
+      transition: none !important;
+    }
+    
+    .el-progress-circle {
+      margin: 0;
+      transition: none !important;
+    }
+
+    // 禁用 SVG 动画
+    svg {
+      transition: none !important;
+    }
+
+    // 禁用进度条路径动画
+    .el-progress-circle__track,
+    .el-progress-circle__path {
+      transition: none !important;
+    }
+  }
+}
+
+// 添加选择提示区域样式
+.selection-control {
+  margin-bottom: 10px;
+
+  .el-alert {
+    padding: 8px 16px;
+  }
+}
 </style>
     

+ 27 - 5
src/views/login/aiIndex.vue

@@ -204,11 +204,33 @@ export default {
     this.init();
   },
   methods: {
-    /* 上传文件 */
     async handleFileUpload(event) {
       const files = Array.from(event.target.files);
 
-      for (const file of files) {
+      // 检查当前已上传的图片数量
+      const currentImageCount = this.uploadFiles.filter((file) =>
+        file.type.startsWith("image/")
+      ).length;
+
+      // 计算还能上传多少张图片
+      const remainingSlots = 5 - currentImageCount;
+
+      if (remainingSlots <= 0) {
+        this.$message.warning("最多只能上传5张图片");
+        event.target.value = "";
+        return;
+      }
+
+      // 只处理允许的数量的文件
+      const filesToProcess = files.slice(0, remainingSlots);
+
+      if (files.length > remainingSlots) {
+        this.$message.warning(
+          `已达到上传上限,只能再上传${remainingSlots}张图片`
+        );
+      }
+
+      for (const file of filesToProcess) {
         try {
           // 创建 FormData 对象
           const formData = new FormData();
@@ -226,12 +248,12 @@ export default {
           );
 
           // 获取接口返回的文件URL
-          const fileUrl = response.data.data.fileUrl; // 根据实际接口返回格式调整
+          const fileUrl = response.data.data.fileUrl;
           // 将文件信息添加到 uploadFiles 数组
           this.uploadFiles.push({
             name: file.name,
             type: file.type,
-            preview: fileUrl, // 直接使用接口返回的URL作为预览
+            preview: fileUrl,
             url: fileUrl,
           });
         } catch (error) {
@@ -388,7 +410,7 @@ export default {
         .filter((file) => file.type.startsWith("image/"))
         .map((file) => file.url); // 直接获取URL数组,不需要join
 
-      if (message || imageUrls.length>0) {
+      if (message || imageUrls.length > 0) {
         // 修改判断条件,允许只有图片没有文字的情况
         // Markdown换行处理
         message = message.replace(/(\r\n|\r|\n)/g, "  \n");

+ 12 - 15
src/views/middPage/index.vue

@@ -20,7 +20,7 @@
               type=""
               :style="index !== 0 ? 'margin-left: 5px;' : ''"
             >
-              {{ item }}
+              {{ item.name }}
             </el-tag>
           </template>
           <span v-else style="color: #97a8be">暂无标签</span>
@@ -75,7 +75,7 @@
           </span>
         </template>
       </el-table-column>
-      <el-table-column
+      <!-- <el-table-column
         label="模型生成1"
         prop="generation_1"
         class-name="model-gen-1"
@@ -87,16 +87,11 @@
           ></el-input>
           <span v-else>
             {{ scope.row.generation_1 }}
-            <!--  <i
-              class="el-icon-refresh"
-              @click="openModel1Dialog(scope.row)"
-              style="cursor: pointer; margin-left: 5px"
-            ></i> -->
           </span>
         </template>
-      </el-table-column>
+      </el-table-column> -->
       <el-table-column
-        label="模型生成2"
+        label="模型生成"
         prop="generation_2"
         class-name="model-gen-2"
       >
@@ -253,8 +248,8 @@
       title="配置模型"
       width="40%"
     >
-      <el-form :model="firstForm.configForm" label-width="120px">
-        <el-form-item label="模型1">
+     <el-form :model="firstForm.configForm" label-width="120px">
+         <!-- <el-form-item label="模型1">
           <el-select
             v-model="firstForm.configForm.model_a_config"
             placeholder="请选择应用"
@@ -266,8 +261,8 @@
               :value="item.id"
             ></el-option>
           </el-select>
-        </el-form-item>
-        <el-form-item label="模型2">
+        </el-form-item> -->
+        <el-form-item label="模型">
           <el-select
             v-model="firstForm.configForm.model_b_config"
             placeholder="请选择应用"
@@ -543,7 +538,7 @@ export default {
   mounted() {
     this.doc_identifier = this.$route.query.identifier;
     this.firstForm.currentDocument = this.$route.query.name;
-  /*   this.firstForm.tag = JSON.parse(this.$route.query.tag); */
+    this.firstForm.tag = JSON.parse(this.$route.query.tag);
     this.firstInit();
     this.updateProjectFilters();
   },
@@ -579,7 +574,8 @@ export default {
     /* 配置模型 */
     firstHandleConfig(index, row) {
       this.firstForm.configForm = row;
-      this.firstForm.configForm.model_a_config = row.model_a_config.id;
+      console.log(row);
+      /* this.firstForm.configForm.model_a_config = row.model_a_config.id; */
       this.firstForm.configForm.model_b_config = row.model_b_config.id;
       /* this.firstForm.configForm.id=row.id
       this.firstForm.configForm.project_description = row.description; */
@@ -1016,6 +1012,7 @@ export default {
 }
 .h_left {
   display: flex;
+  align-items: center;
 }
 .h_left p {
   margin-right: 45px;

+ 213 - 59
src/views/middPage/list.vue

@@ -220,7 +220,7 @@
                 v-for="(item, index) in row.tags"
                 :key="index"
                 type=""
-                style="margin-right: 5px;margin-bottom:5px;"
+                style="margin-right: 5px; margin-bottom: 5px"
               >
                 {{ item.name }}
               </el-tag>
@@ -235,9 +235,75 @@
           />
           <el-table-column prop="status" label="处理状态" width="100">
             <template #default="{ row }">
-              <el-tag :type="getStatusType(row.processing_status)">
-                {{ getStatusText(row.processing_status) }}
-              </el-tag>
+              <!--   <el-tooltip
+                effect="dark"
+                placement="top"
+                :disabled="
+                  Number(row.processing_status) !== 1 &&
+                  Number(row.processing_status) !== 5 &&
+                  Number(row.processing_status) !== 4
+                "
+              >
+                <template #content>
+                  <div style="padding: 5px">
+                    <div style="margin-top: 5px; font-size: 12px">
+                      {{ row.progress_msg || "正在处理中..." }}
+                    </div>
+                  </div>
+                </template>
+                <div class="status-wrapper">
+                  <template v-if="Number(row.processing_status) === 1 || Number(row.processing_status) === 5">
+                    <div class="progress-wrapper">
+                      <el-progress
+                        type="circle"
+                        :percentage="Math.floor(row.progress) || 0"
+                        :width="35"
+                        :stroke-width="4"
+                        :format="percentFormat"
+                        
+                      ></el-progress>
+                    </div>
+                  </template>
+                  <template v-else>
+                    <el-tag :type="getStatusType(row.processing_status)">
+                      {{ getStatusText(row.processing_status) }}
+                    </el-tag>
+                  </template>
+                </div>
+              </el-tooltip> -->
+              <el-tooltip
+                effect="dark"
+                placement="top"
+                :disabled="
+                  Number(row.processing_status) !== 1 &&
+                  Number(row.processing_status) !== 5 &&
+                  Number(row.processing_status) !== 4
+                "
+              >
+                <template #content>
+                  <div style="padding: 5px">
+                    <div style="margin-top: 5px; font-size: 12px">
+                      {{ row.progress_msg || "正在处理中..." }}
+                    </div>
+                  </div>
+                </template>
+                <div class="status-wrapper">
+                  <template
+                    v-if="
+                      Number(row.processing_status) === 1 ||
+                      Number(row.processing_status) === 5
+                    "
+                  >
+                    <!-- 移除进度条,改为显示文本 -->
+                    <el-tag type="warning">处理中</el-tag>
+                  </template>
+                  <template v-else>
+                    <el-tag :type="getStatusType(row.processing_status)">
+                      {{ getStatusText(row.processing_status) }}
+                    </el-tag>
+                  </template>
+                </div>
+              </el-tooltip>
             </template>
           </el-table-column>
           <el-table-column label="操作" width="100">
@@ -393,6 +459,7 @@ import {
   process_model_generation,
   process_model_regeneration,
   categories,
+  literResult,
 } from "@/api/knowledge";
 import axios from "axios";
 // 状态映射表
@@ -401,6 +468,7 @@ const STATUS_MAP = {
   1: { text: "处理中", type: "warning" },
   2: { text: "处理完成", type: "success" },
   3: { text: "处理失败", type: "danger" },
+  5: { text: "待处理", type: "warning" },
 };
 
 export default {
@@ -449,6 +517,8 @@ export default {
         1: { text: "处理中", type: "warning" },
         2: { text: "处理完成", type: "success" },
         3: { text: "处理失败", type: "danger" },
+        4: { text: "处理失败", type: "danger" },
+        5: { text: "待处理", type: "warning" },
       },
       multipleSelection: [], // 存储跨页选中的数据
       selectedRows: [], // 当前页选中的行
@@ -536,7 +606,7 @@ export default {
         console.error("导出错误:", error);
       }
     },
-    /* 重复处理 */
+    // 修改重新处理方法
     async handleReprocess(row) {
       try {
         await this.$confirm("确认要重新处理该文献吗?", "提示", {
@@ -546,18 +616,18 @@ export default {
         });
 
         // 调用重新处理的接口
-        const res = await process_model_regeneration([row.id]); // 添加第二个参数表示重新处理
+        const res = await process_model_regeneration([row.id]);
 
         if (res.status === 200) {
           this.$message.success("重新处理任务已提交");
-          await this.fetchGpuList(); // 刷新列表
-        } else {
-          throw new Error(res.message || "重新处理失败");
+          // 更新状态并开始轮询
+          this.$set(row, "processing_status", 1);
+          this.$set(row, "progress", 0);
+          this.startPolling(row.id);
+          await this.fetchGpuList();
         }
       } catch (error) {
-        if (error === "cancel") {
-          return;
-        }
+        if (error === "cancel") return;
         this.$message.error(error.message || "重新处理提交失败");
         console.error("重新处理错误:", error);
       }
@@ -571,13 +641,15 @@ export default {
           type: "warning",
         });
 
-        const res = await process_model_generation([row.id]);
+        const res = await process_model_regeneration([row.id]);
 
         if (res.status === 200) {
-          this.$message.success("处��任务已提交");
-          await this.fetchGpuList(); // 刷新列表
-        } else {
-          throw new Error(res.message || "处理失败");
+          this.$message.success("处理任务已提交");
+          // 更新状态并开始轮询
+          this.$set(row, "processing_status", 1);
+          this.$set(row, "progress", 0);
+          this.startPolling(row.id);
+          await this.fetchGpuList();
         }
       } catch (error) {
         if (error === "cancel") {
@@ -807,41 +879,46 @@ export default {
 
     /* 批量处理文献 */
     async handleBatchProcess() {
-      const selectedIds = this.isAllDataSelected
-        ? await this.getAllDataIds()
-        : Array.from(this.allSelectedRows.keys());
+      try {
+        const selectedIds = this.isAllDataSelected
+          ? await this.getAllDataIds()
+          : Array.from(this.allSelectedRows.keys());
 
-      if (selectedIds.length === 0) {
-        this.$message.warning("请选择需要处理的文献");
-        return;
-      }
+        if (selectedIds.length === 0) {
+          this.$message.warning("请选择需要处理的文献");
+          return;
+        }
 
-      try {
         this.isProcessing = true;
-        const ids = this.selectedRows.map((row) => row.id);
 
-        // 添加确认对话框
         await this.$confirm("确认要批量处理选中的文献吗?", "提示", {
           confirmButtonText: "确定",
           cancelButtonText: "取消",
           type: "warning",
         });
 
-        const res = await process_model_regeneration(ids);//process_model_regeneration
+        const res = await process_model_regeneration(selectedIds);
 
         if (res.status === 200) {
           this.$message.success("批量处理已提交");
-          this.selectedRows = []; // 清空选中
-          this.clearSelection()
+
+          // 更新选中行的状态并启动轮询
+          selectedIds.forEach((id) => {
+            const row = this.gpuList.find((item) => item.id === id);
+            if (row) {
+              this.$set(row, "processing_status", 1);
+              this.$set(row, "progress", 0);
+              this.startPolling(id);
+            }
+          });
+
+          this.selectedRows = [];
+          this.clearSelection();
           this.allSelectedRows.clear();
-          await this.fetchGpuList(); // 刷新列表
-        } else {
-          throw new Error(res.message || "处理失败");
+          await this.fetchGpuList();
         }
       } catch (error) {
-        if (error === "cancel") {
-          return;
-        }
+        if (error === "cancel") return;
         this.$message.error(error.message || "批量处理提交失败");
         console.error("批量处理错误:", error);
       } finally {
@@ -1081,40 +1158,64 @@ export default {
     },
     // 新增:开始轮询
     startPolling(id) {
-      if (this.pollingTimers[id]) return; // 如果已经在轮询,则不重复设置
+      if (this.pollingTimers[id]) return;
 
-      this.pollingTimers[id] = setInterval(async () => {
+      const checkStatus = async () => {
         try {
-          const response = await axios.post(
-            `${process.env.VUE_APP_BASE_API}/literature-data/search/`,
-            {
-              page: this.currentPage,
-              page_size: this.pageSize,
-              doc_type_id: this.selectedType || 36,
-              keyword: this.searchForm.name,
-              tag_names: this.searchForm.id,
-            }
-          );
-
+          const response = await literResult(id);
           if (response.status === 200) {
-            const item = response.data.data.list.find((item) => item.id === id);
-            if (item && item.processing_status !== 1) {
-              // 如果状态不再是"处理中",停止轮询
-              this.stopPolling(id);
-              await this.fetchGpuList(); // 刷新列表
+            const item = this.gpuList.find((item) => item.id === id);
+            if (item) {
+              // 使用接口返回的状态数据
+              const newStatus = Number(
+                response.data.data.literature_info.processing_status
+              );
+
+            /*进度   const newProgress = Number(
+                response.data.data.progress_info.calculated_progress.percentage
+              ); */
+              const newProgressMsg =
+                response.data.data.literature_info.status_description;
+
+              // 更新状态相关数据
+              this.$set(item, "processing_status", newStatus);
+           /*    this.$set(item, "progress", newProgress); */
+              this.$set(item, "progress_msg", newProgressMsg);
+
+              // 根据状态处理结果
+              if (newStatus === 2) {
+                // 处理完成
+                this.$message.success("处理成功");
+                this.stopPolling(id);
+                await this.fetchGpuList();
+              } else if (newStatus === 4) {
+                // 处理失败
+                this.$message.error(newProgressMsg || "处理失败");
+                this.stopPolling(id);
+              } else if (newStatus === 1 || newStatus === 5) {
+                // 继续轮询
+                this.pollingTimers[id] = setTimeout(checkStatus, 5000);
+              }
             }
+          } else {
+            this.$message.error("获取处理状态失败");
+            delete this.pollingTimers[id];
           }
         } catch (error) {
-          console.error("轮询检查状态失败:", error);
-          this.stopPolling(id); // 发生错误时停止轮询
+          console.error("获取处理状态错误:", error);
+          this.$message.error("获取处理状态时出现错误");
+          this.stopPolling(id);
         }
-      }, 10000); // 每分钟检查一次
+      };
+
+      // 立即开始检查
+      checkStatus();
     },
 
     // 新增:停止轮询
     stopPolling(id) {
       if (this.pollingTimers[id]) {
-        clearInterval(this.pollingTimers[id]);
+        clearTimeout(this.pollingTimers[id]);
         delete this.pollingTimers[id];
       }
     },
@@ -1194,6 +1295,19 @@ export default {
         console.error(error); */
       }
     },
+
+    // 获取进度状态
+    getProgressStatus(progress) {
+      if (progress >= 100) {
+        return "success";
+      }
+      return undefined;
+    },
+
+    // 格式化百分比
+    percentFormat(percentage) {
+      return `${percentage}%`;
+    },
   },
   // 在组件销毁时清理所有轮询
   beforeDestroy() {
@@ -1207,7 +1321,7 @@ export default {
 };
 </script>
 
-<style scoped>
+<style lang="scss" scoped>
 .gpu-list {
   padding: 20px;
 }
@@ -1225,4 +1339,44 @@ export default {
   justify-content: flex-end;
   margin-top: 15px;
 }
+
+.status-wrapper {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  transition: none !important;
+}
+
+.progress-wrapper {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  padding: 2px;
+  transition: none !important;
+
+  ::v-deep .el-progress {
+    line-height: 1;
+    transition: none !important;
+
+    .el-progress__text {
+      font-size: 12px !important;
+      color: inherit;
+      transition: none !important;
+    }
+
+    .el-progress-circle {
+      margin: 0;
+      transition: none !important;
+    }
+
+    svg {
+      transition: none !important;
+    }
+
+    .el-progress-circle__track,
+    .el-progress-circle__path {
+      transition: none !important;
+    }
+  }
+}
 </style>

+ 147 - 18
src/views/project/components/dataList.vue

@@ -190,17 +190,21 @@
         <el-table-column prop="id" label="ID" width="80" align="center" />
         <el-table-column prop="title" label="模版名称" align="left" />
         <el-table-column prop="createTime" label="绑定时间" align="center" />
-        <el-table-column label="操作" align="center">
+        <el-table-column label="操作" align="center" width="320">
           <template #default="scope">
-            <el-button type="primary" @click="previewTemplate(scope.row)"
-              >预览</el-button
-            >
-            <el-button type="primary" @click="replaceTemplate(scope.row)"
-              >替换</el-button
-            >
-            <el-button type="success" @click="exportDocument(scope.row)"
-              >导出文档</el-button
-            >
+            <el-button type="primary" @click="previewTemplate(scope.row)">预览</el-button>
+            <el-button type="primary" @click="replaceTemplate(scope.row)">替换</el-button>
+            <el-dropdown style="margin-left: 10px;" trigger="click" @command="(command) => handleExport(command, scope.row)">
+              <el-button type="success">
+                导出文档<i class="el-icon-arrow-down el-icon--right"></i>
+              </el-button>
+              <template #dropdown>
+                <el-dropdown-menu>
+                  <el-dropdown-item command="word">Word格式</el-dropdown-item>
+                  <el-dropdown-item command="pdf">PDF格式</el-dropdown-item>
+                </el-dropdown-menu>
+              </template>
+            </el-dropdown>
           </template>
         </el-table-column>
       </el-table>
@@ -255,13 +259,16 @@ import {
   calculate,
   getphases,
 } from "@/api/project";
-import { searchList, updateDocument, exportDocument } from "@/api/document";
+import { searchList, updateDocument, exportDocument,exportToPDF } from "@/api/document";
 import { searchCustomer } from "@/api/customer";
 import { searchProduct } from "@/api/product";
 /* import {searchTemplate} from "@/api/template" */
 import dataInfo from "./dataInfo.vue";
 import elDragDialog from "@/directive/el-drag-dialog";
 import axios from "axios";
+import jsPDF from "jspdf";
+import html2canvas from "html2canvas";
+
 export default {
   components: {
     dataInfo,
@@ -399,10 +406,10 @@ export default {
           </body>
         </html>`;
 
-        // 处理表格样式
+       /*  // 处理表格样式
         contentData = contentData
           .replaceAll("<table ", `<table style="border-collapse: collapse;" `)
-          .replaceAll("<td>", `<td style="border: 1px solid black;">`);
+          .replaceAll("<td>", `<td style="border: 1px solid black;">`); */
 
         // 调用导出接口
         const res = await exportDocument({
@@ -449,7 +456,7 @@ export default {
       if (!product) return "info";
 
       // 根据不同阶段返回不同的类型
-      // 这里的判断逻辑需要根据实际的产品阶来调整
+      // 这里的判断逻辑需要根据实际的产品阶来调整
       switch (product.status) {
         case 1:
           return "success"; // 已完成
@@ -845,7 +852,7 @@ export default {
     async replaceAll() {
       this.batchReplaceLoading = true;
       try {
-        // 收集所有匹配
+        // 收集所有匹配
         const allLocations = this.matchResults.map((item) => {
           // 清理括号
           return item.replace(/[\[\]【】]/g, "");
@@ -1104,7 +1111,7 @@ export default {
       }
     },
 
-    // 处理全选按点击
+    // 处理全选按点击
     handleSelectAll(selection) {
       const currentPage = this.templateQueryForm.page;
 
@@ -1210,7 +1217,7 @@ export default {
       });
     },
 
-    // 关对话框
+    // 关对话框
     closeTemplateDialog() {
       this.templateDialogVisible = false;
       this.selectedTemplateIds.clear();
@@ -1454,7 +1461,7 @@ export default {
       getphases().then((res) => {
         this.currentPhaseList = res.data.options;
       });
-      /* 获取目前态 */
+      /* 获取目前��态 */
       getstatus().then((res) => {
         this.getstatusList = res.data.options;
       });
@@ -1467,6 +1474,109 @@ export default {
         this.productList = res.data.dataList;
       });
     },
+    // 新增:处理导出命令
+    handleExport(command, row) {
+      switch (command) {
+        case 'word':
+          this.exportDocument(row);
+          break;
+        case 'pdf':
+          this.exportToPDF(row);
+          break;
+      }
+    },
+
+    // 添加新的 exportToPDF 方法
+    async exportToPDF(template) {
+      try {
+        // 解析模版内容
+        const templateData = JSON.parse(template.data || "[]");
+
+        // 创建一个临时的容器来存放内容
+        const contentContainer = document.createElement("div");
+        contentContainer.className = "content";
+
+        // 处理每个模版段落
+        templateData.forEach((item) => {
+          const templateSection = document.createElement("div");
+          templateSection.className = "template-textarea";
+          templateSection.innerHTML = item.content;
+          contentContainer.appendChild(templateSection);
+        });
+
+        // 处理所有输入框
+        contentContainer.querySelectorAll('input[type="text"]').forEach((input) => {
+          const span = document.createElement("span");
+          span.textContent = input.value;
+          input.parentNode.replaceChild(span, input);
+        });
+
+        // 构建HTML内容
+        let contentData = `<!DOCTYPE html>
+        <html>
+          <head>
+            <meta charset="UTF-8">
+            <style>
+              @page {
+                size: A4;
+                margin: 2cm;
+              }
+              body {
+                font-family: Arial, sans-serif;
+                font-size: 12pt;
+                line-height: 1.5;
+              }
+              table {
+                width: 100%;
+                border-collapse: collapse;
+              }
+              td, th {
+                border: 1px solid black;
+                padding: 5px;
+              }
+              .template-textarea {
+                page-break-after: always;
+              }
+              .TOC {
+                display: none !important;
+              }
+            </style>
+          </head>
+          <body>
+            ${contentContainer.innerHTML}
+          </body>
+        </html>`;
+
+     /*    // 处理表格样式
+        contentData = contentData
+          .replaceAll("<table ", `<table style="border-collapse: collapse;" `)
+          .replaceAll("<td>", `<td style="border: 1px solid black;">`); */
+
+        // 调用导出接口,指定导出类型为 PDF
+        const res = await exportToPDF({
+          content: contentData,
+          title: template.title,
+        });
+
+        if (res.status !== 200) {
+          this.$alert(res.errMsg);
+          return;
+        }
+
+        // 处理文件下载
+        const link = document.createElement("a");
+        link.href = res.data.file_path;
+        link.download = res.data.file_name;
+        document.body.appendChild(link);
+        link.click();
+        document.body.removeChild(link);
+
+        this.$message.success("导出成功");
+      } catch (error) {
+        console.error("导出PDF失败:", error);
+        this.$alert("导出PDF时发生错误,请稍后重试。");
+      }
+    },
   },
 };
 </script>
@@ -1509,4 +1619,23 @@ export default {
   color: #f56c6c;
   font-weight: bold;
 }
+
+// 添加PDF导出相关样式
+.content {
+  background: white;
+  
+  .template-textarea {
+    page-break-after: always;
+    
+    table {
+      width: 100%;
+      border-collapse: collapse;
+      
+      td, th {
+        border: 1px solid black;
+        padding: 5px;
+      }
+    }
+  }
+}
 </style>

Some files were not shown because too many files changed in this diff