Browse Source

批量处理模版替换

yangg 8 months ago
parent
commit
5903276cdf
64 changed files with 1162 additions and 328 deletions
  1. 0 0
      dist/index.html
  2. 0 0
      dist/static/css/app.e87649e2.css
  3. 1 0
      dist/static/css/chunk-079de15b.a39facf0.css
  4. 1 0
      dist/static/css/chunk-0da0f431.21513b0f.css
  5. 0 1
      dist/static/css/chunk-386d37cb.86b22fbc.css
  6. 0 0
      dist/static/css/chunk-4dfd855c.8ef77f1c.css
  7. 1 0
      dist/static/css/chunk-6f0044a0.2ee72984.css
  8. 0 0
      dist/static/css/chunk-7b511d03.918f8f21.css
  9. 0 1
      dist/static/css/chunk-7f7cce74.65cd4a82.css
  10. 0 1
      dist/static/css/chunk-9f092188.de981e17.css
  11. 0 0
      dist/static/js/app.2303a276.js
  12. 0 0
      dist/static/js/app.fb10f0f7.js
  13. 0 0
      dist/static/js/chunk-016e5c0e.da3a9f11.js
  14. 0 0
      dist/static/js/chunk-01f26467.fee2d0bc.js
  15. 0 0
      dist/static/js/chunk-04ba33be.9be2dc44.js
  16. 0 0
      dist/static/js/chunk-079de15b.17a47518.js
  17. 0 0
      dist/static/js/chunk-09f78c22.8742a933.js
  18. 0 0
      dist/static/js/chunk-0a1f2758.9e573037.js
  19. 0 0
      dist/static/js/chunk-0da0f431.d7dbb6b6.js
  20. 0 0
      dist/static/js/chunk-0ec56e2a.de9328a9.js
  21. 0 0
      dist/static/js/chunk-10bfc27e.7b3728e7.js
  22. 0 0
      dist/static/js/chunk-11ff1a32.fffd4532.js
  23. 0 0
      dist/static/js/chunk-138f7583.842a6e15.js
  24. 0 0
      dist/static/js/chunk-254ac533.0042cf24.js
  25. 0 0
      dist/static/js/chunk-276e7119.d514fbb8.js
  26. 0 0
      dist/static/js/chunk-2d0d3705.6e4a9a9c.js
  27. 0 0
      dist/static/js/chunk-35464144.87555f07.js
  28. 0 0
      dist/static/js/chunk-386d37cb.d794a615.js
  29. 0 0
      dist/static/js/chunk-3ab88ac2.57409d35.js
  30. 0 0
      dist/static/js/chunk-3d8a6649.e1ea14d6.js
  31. 0 0
      dist/static/js/chunk-44eee83d.c7a0dd6d.js
  32. 0 0
      dist/static/js/chunk-4ac7f82e.7468e419.js
  33. 0 0
      dist/static/js/chunk-4dfd855c.119178eb.js
  34. 0 0
      dist/static/js/chunk-52f685c2.861d0efb.js
  35. 0 0
      dist/static/js/chunk-5a3bdf57.b83cc3e1.js
  36. 0 0
      dist/static/js/chunk-5bc2c8fb.91c0d6f4.js
  37. 0 0
      dist/static/js/chunk-5c6eee35.13506a27.js
  38. 0 0
      dist/static/js/chunk-6111b966.ccb6f3cf.js
  39. 0 0
      dist/static/js/chunk-632c3578.1cd48d3d.js
  40. 0 0
      dist/static/js/chunk-683feb49.57361db1.js
  41. 0 0
      dist/static/js/chunk-6a80e4ca.5c8531cc.js
  42. 0 0
      dist/static/js/chunk-6ddf6871.6c624768.js
  43. 0 0
      dist/static/js/chunk-6f0044a0.31767bd2.js
  44. 0 0
      dist/static/js/chunk-708604c0.0d58b88c.js
  45. 0 0
      dist/static/js/chunk-708c45dc.f5615ac7.js
  46. 0 0
      dist/static/js/chunk-77a58a9f.15d0cb62.js
  47. 0 0
      dist/static/js/chunk-77bc8fb9.6e2dcd55.js
  48. 0 0
      dist/static/js/chunk-7a88741c.29036f89.js
  49. 0 0
      dist/static/js/chunk-7b511d03.573ae1d6.js
  50. 0 0
      dist/static/js/chunk-7f7cce74.c2d1769d.js
  51. 0 0
      dist/static/js/chunk-9235c1ae.1549c27b.js
  52. 0 0
      dist/static/js/chunk-9f092188.8c495226.js
  53. 0 0
      dist/static/js/chunk-e90c2844.43fda0ca.js
  54. 0 0
      dist/static/js/chunk-ec3f0ab6.95ae04ed.js
  55. 0 0
      dist/static/js/chunk-ec55d346.ed339112.js
  56. 0 0
      dist/static/js/chunk-f49247ee.1aeabedc.js
  57. 0 0
      dist/static/js/chunk-fa78c2d4.43c18551.js
  58. 0 0
      dist/static/js/chunk-libs.5e769589.js
  59. 4 1
      package.json
  60. 24 20
      src/components/FilePreview/index.vue
  61. 58 58
      src/views/appConfig/index.vue
  62. 55 41
      src/views/knowledgeMenu/category/infoList.vue
  63. 348 23
      src/views/project/ProjectInput.vue
  64. 670 182
      src/views/project/components/dataList.vue

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/app.e87649e2.css


+ 1 - 0
dist/static/css/chunk-079de15b.a39facf0.css

@@ -0,0 +1 @@
+.header[data-v-7e826c04]{margin-left:20px}.header h2[data-v-7e826c04]{margin-bottom:0}.center[data-v-7e826c04]{margin:10px}.center[data-v-7e826c04] .el-form--inline .el-form-item{display:block}.center[data-v-7e826c04] .el-input-number--medium{width:150px}.footer[data-v-7e826c04]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;margin:0 100px 20px}[data-v-7e826c04] .avatar-uploader .el-upload{border:1px dashed #d9d9d9;border-radius:6px;cursor:pointer;position:relative;overflow:hidden}.avatar-uploader .el-upload[data-v-7e826c04]:hover{border-color:#409eff}.avatar-uploader-icon[data-v-7e826c04]{font-size:28px;color:#8c939d;width:100px;height:100px;line-height:100px;text-align:center}.avatar[data-v-7e826c04]{width:100px;height:100px;display:block}.hint[data-v-7e826c04]{font-size:12px;color:#c0c4cc}

+ 1 - 0
dist/static/css/chunk-0da0f431.21513b0f.css

@@ -0,0 +1 @@
+.editor-area ::v-deep .cke_top{display:block}.project-input-container{padding:20px}.pagination-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.editor-area .cke_top{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:6px 8px!important}.editor-area .cke_top,.editor-area .cke_top .cke_toolgroup{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.editor-area .cke_top .cke_toolgroup{margin:0 2px;display:-webkit-box;display:-ms-flexbox;display:flex}.editor-area .cke_top .cke_toolbar{float:none!important;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.cke_chrome{width:100%!important}

+ 0 - 1
dist/static/css/chunk-386d37cb.86b22fbc.css

@@ -1 +0,0 @@
-.project-search[data-v-568e32be]{display:-webkit-box;display:-ms-flexbox;display:flex;padding:10px;font-size:12px}.listClass[data-v-568e32be]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.excel-table[data-v-568e32be]{width:100%;overflow-y:auto}.excel-table table[data-v-568e32be]{border-collapse:collapse;width:100%;margin-bottom:20px}.excel-table td[data-v-568e32be],.excel-table th[data-v-568e32be]{border:1px solid #ddd;padding:8px;text-align:left;white-space:nowrap}.excel-table th[data-v-568e32be]{background-color:#f2f2f2;font-weight:700;position:sticky;top:0;z-index:1}.excel-table tr[data-v-568e32be]:nth-child(2n){background-color:#f9f9f9}.no-data[data-v-568e32be]{font-size:18px;color:#909399;text-align:center;margin-top:50px}.pagination[data-v-568e32be]{position:fixed;bottom:0;right:51%}.movable-dialog[data-v-568e32be]{position:absolute!important}[data-v-568e32be] .el-dialog__header{cursor:move}

+ 0 - 0
dist/static/css/chunk-ec3f0ab6.7672182a.css → dist/static/css/chunk-4dfd855c.8ef77f1c.css


+ 1 - 0
dist/static/css/chunk-6f0044a0.2ee72984.css

@@ -0,0 +1 @@
+.project-search[data-v-39a9cf3e]{display:-webkit-box;display:-ms-flexbox;display:flex;padding:10px;font-size:12px}.listClass[data-v-39a9cf3e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.excel-table[data-v-39a9cf3e]{width:100%;overflow-y:auto}.excel-table table[data-v-39a9cf3e]{border-collapse:collapse;width:100%;margin-bottom:20px}.excel-table td[data-v-39a9cf3e],.excel-table th[data-v-39a9cf3e]{border:1px solid #ddd;padding:8px;text-align:left;white-space:nowrap}.excel-table th[data-v-39a9cf3e]{background-color:#f2f2f2;font-weight:700;position:sticky;top:0;z-index:1}.excel-table tr[data-v-39a9cf3e]:nth-child(2n){background-color:#f9f9f9}.no-data[data-v-39a9cf3e]{font-size:18px;color:#909399;text-align:center;margin-top:50px}.pagination[data-v-39a9cf3e]{position:fixed;bottom:0;right:51%}.movable-dialog[data-v-39a9cf3e]{position:absolute!important}[data-v-39a9cf3e] .el-dialog__header{cursor:move}

+ 0 - 0
dist/static/css/chunk-727cb4e9.6f8877c6.css → dist/static/css/chunk-7b511d03.918f8f21.css


+ 0 - 1
dist/static/css/chunk-7f7cce74.65cd4a82.css

@@ -1 +0,0 @@
-.header[data-v-37483169]{margin-left:20px}.header h2[data-v-37483169]{margin-bottom:0}.center[data-v-37483169]{margin:10px}.center[data-v-37483169] .el-form--inline .el-form-item{display:block}.center[data-v-37483169] .el-input-number--medium{width:150px}.footer[data-v-37483169]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;margin:0 100px 20px}[data-v-37483169] .avatar-uploader .el-upload{border:1px dashed #d9d9d9;border-radius:6px;cursor:pointer;position:relative;overflow:hidden}.avatar-uploader .el-upload[data-v-37483169]:hover{border-color:#409eff}.avatar-uploader-icon[data-v-37483169]{font-size:28px;color:#8c939d;width:100px;height:100px;line-height:100px;text-align:center}.avatar[data-v-37483169]{width:100px;height:100px;display:block}.hint[data-v-37483169]{font-size:12px;color:#c0c4cc}

+ 0 - 1
dist/static/css/chunk-9f092188.de981e17.css

@@ -1 +0,0 @@
-.project-input-container{padding:20px}.pagination-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}

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


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


+ 0 - 0
dist/static/js/chunk-016e5c0e.ca18d88f.js → dist/static/js/chunk-016e5c0e.da3a9f11.js


+ 0 - 0
dist/static/js/chunk-01f26467.e90a9006.js → dist/static/js/chunk-01f26467.fee2d0bc.js


+ 0 - 0
dist/static/js/chunk-04ba33be.d32915c6.js → dist/static/js/chunk-04ba33be.9be2dc44.js


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


+ 0 - 0
dist/static/js/chunk-09f78c22.fe0059e3.js → dist/static/js/chunk-09f78c22.8742a933.js


+ 0 - 0
dist/static/js/chunk-0a1f2758.13a763e7.js → dist/static/js/chunk-0a1f2758.9e573037.js


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


+ 0 - 0
dist/static/js/chunk-0ec56e2a.7dd43bdb.js → dist/static/js/chunk-0ec56e2a.de9328a9.js


+ 0 - 0
dist/static/js/chunk-10bfc27e.22203d9f.js → dist/static/js/chunk-10bfc27e.7b3728e7.js


+ 0 - 0
dist/static/js/chunk-11ff1a32.8826a9db.js → dist/static/js/chunk-11ff1a32.fffd4532.js


+ 0 - 0
dist/static/js/chunk-138f7583.8e34047a.js → dist/static/js/chunk-138f7583.842a6e15.js


+ 0 - 0
dist/static/js/chunk-254ac533.30f5dec3.js → dist/static/js/chunk-254ac533.0042cf24.js


+ 0 - 0
dist/static/js/chunk-276e7119.2b5512a9.js → dist/static/js/chunk-276e7119.d514fbb8.js


+ 0 - 0
dist/static/js/chunk-2d0d3705.eff0d350.js → dist/static/js/chunk-2d0d3705.6e4a9a9c.js


+ 0 - 0
dist/static/js/chunk-35464144.6682967e.js → dist/static/js/chunk-35464144.87555f07.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-386d37cb.d794a615.js


+ 0 - 0
dist/static/js/chunk-3ab88ac2.e1447fa0.js → dist/static/js/chunk-3ab88ac2.57409d35.js


+ 0 - 0
dist/static/js/chunk-3d8a6649.8b554330.js → dist/static/js/chunk-3d8a6649.e1ea14d6.js


+ 0 - 0
dist/static/js/chunk-44eee83d.2b2237a9.js → dist/static/js/chunk-44eee83d.c7a0dd6d.js


+ 0 - 0
dist/static/js/chunk-4ac7f82e.63c45bb6.js → dist/static/js/chunk-4ac7f82e.7468e419.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-4dfd855c.119178eb.js


+ 0 - 0
dist/static/js/chunk-52f685c2.826bce96.js → dist/static/js/chunk-52f685c2.861d0efb.js


+ 0 - 0
dist/static/js/chunk-5a3bdf57.64103f8a.js → dist/static/js/chunk-5a3bdf57.b83cc3e1.js


+ 0 - 0
dist/static/js/chunk-5bc2c8fb.ed74d8da.js → dist/static/js/chunk-5bc2c8fb.91c0d6f4.js


+ 0 - 0
dist/static/js/chunk-5c6eee35.76a71000.js → dist/static/js/chunk-5c6eee35.13506a27.js


+ 0 - 0
dist/static/js/chunk-6111b966.3a35e3d4.js → dist/static/js/chunk-6111b966.ccb6f3cf.js


+ 0 - 0
dist/static/js/chunk-632c3578.5d0f633e.js → dist/static/js/chunk-632c3578.1cd48d3d.js


+ 0 - 0
dist/static/js/chunk-683feb49.490e12ab.js → dist/static/js/chunk-683feb49.57361db1.js


+ 0 - 0
dist/static/js/chunk-6a80e4ca.b6f04299.js → dist/static/js/chunk-6a80e4ca.5c8531cc.js


+ 0 - 0
dist/static/js/chunk-6ddf6871.43e70104.js → dist/static/js/chunk-6ddf6871.6c624768.js


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


+ 0 - 0
dist/static/js/chunk-708604c0.2bde8970.js → dist/static/js/chunk-708604c0.0d58b88c.js


+ 0 - 0
dist/static/js/chunk-708c45dc.cb1b9e42.js → dist/static/js/chunk-708c45dc.f5615ac7.js


+ 0 - 0
dist/static/js/chunk-77a58a9f.b132b26c.js → dist/static/js/chunk-77a58a9f.15d0cb62.js


+ 0 - 0
dist/static/js/chunk-77bc8fb9.da1cc9dc.js → dist/static/js/chunk-77bc8fb9.6e2dcd55.js


+ 0 - 0
dist/static/js/chunk-7a88741c.1e9e85c2.js → dist/static/js/chunk-7a88741c.29036f89.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-7b511d03.573ae1d6.js


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


+ 0 - 0
dist/static/js/chunk-9235c1ae.32a7f7e3.js → dist/static/js/chunk-9235c1ae.1549c27b.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-9f092188.8c495226.js


+ 0 - 0
dist/static/js/chunk-e90c2844.71e1b202.js → dist/static/js/chunk-e90c2844.43fda0ca.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-ec3f0ab6.95ae04ed.js


+ 0 - 0
dist/static/js/chunk-ec55d346.945622de.js → dist/static/js/chunk-ec55d346.ed339112.js


+ 0 - 0
dist/static/js/chunk-f49247ee.41e4380e.js → dist/static/js/chunk-f49247ee.1aeabedc.js


+ 0 - 0
dist/static/js/chunk-fa78c2d4.b75ee132.js → dist/static/js/chunk-fa78c2d4.43c18551.js


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


+ 4 - 1
package.json

@@ -20,6 +20,7 @@
     "@handsontable-pro/vue": "^3.1.1",
     "@handsontable/vue": "^14.1.0",
     "@jiaminghi/data-view": "^2.10.0",
+    "@tinymce/tinymce-vue": "^3.2.8",
     "axios": "0.18.1",
     "ckeditor4": "^4.23.0",
     "ckeditor4-vue": "^3.0.0",
@@ -59,15 +60,17 @@
     "path-to-regexp": "2.4.0",
     "pizzip": "^3.1.6",
     "qrcode": "^1.4.4",
+    "quill-better-table": "^1.2.10",
     "screenfull": "4.2.0",
     "script-loader": "0.7.2",
     "sortablejs": "1.8.4",
-    "tinymce": "^5.1.0",
+    "tinymce": "^5.10.9",
     "vant": "^2.12.30",
     "vue": "2.6.10",
     "vue-class-component": "^7.2.6",
     "vue-count-to": "1.0.13",
     "vue-property-decorator": "^9.1.2",
+    "vue-quill-editor": "^3.0.6",
     "vue-router": "^3.5.3",
     "vue-splitpane": "1.0.4",
     "vuedraggable": "^2.24.3",

+ 24 - 20
src/components/FilePreview/index.vue

@@ -100,9 +100,9 @@ export default {
       immediate: true,
       handler(newValue) {
         /* this.internalFileUrl = newValue; */
-        if (this.isWord) {
+        /* if (this.isWord) {
           this.loadWordContent();
-        }
+        } */
       },
     },
   },
@@ -120,15 +120,16 @@ export default {
       return ["xls", "xlsx"].includes(this.fileType);
     },
     isOffice() {
-      return [ "ppt", "pptx"].includes(this.fileType);
+      return ["ppt", "pptx"].includes(this.fileType);
     },
   },
   mounted() {
+    console.log(this.isExcel);
     if (this.fileType === "txt") {
       this.loadTextContent();
     } else if (this.isWord) {
       this.loadWordContent();
-    } else if (this.isExcel) {
+    } else if (this.$route.query.type=='xlsx') {
       this.loadExcelContent();
     }
   },
@@ -138,16 +139,16 @@ export default {
       this.wordLoadingError = false;
       try {
         // 获取文档 URL
-        if (this.type !== "ai") {
+        /* if (this.type !== "ai") { */
           const res = await searchTaskInfo({
             page: 1,
             page_size: 10,
             document_id: this.$route.query.id,
           });
           this.internalFileUrl = res.data.documentUrl;
-        } else {
+      /*   } else {
           this.internalFileUrl = localStorage.getItem("href");
-        }
+        } */
 
         // 使用 fetch 获取文件内容,指定 responseType 为 'arraybuffer'
         const response = await fetch(this.internalFileUrl, {
@@ -186,16 +187,16 @@ export default {
     async loadTextContent() {
       try {
         // 获取文档 URL
-        if (this.type !== "ai") {
+     /*    if (this.type !== "ai") { */
           const res = await searchTaskInfo({
             page: 1,
             page_size: 10,
             document_id: this.$route.query.id,
           });
           this.internalFileUrl = res.data.documentUrl;
-        } else {
+        /* } else {
           this.internalFileUrl = localStorage.getItem("href");
-        }
+        } */
 
         // 获取文本内容
         const response = await fetch(this.internalFileUrl);
@@ -212,19 +213,22 @@ export default {
     },
     async loadExcelContent() {
       try {
+        let url;
         // 获取文档 URL
-        if (this.type !== "ai") {
-          const res = await searchTaskInfo({
-            page: 1,
-            page_size: 10,
-            document_id: this.$route.query.id,
-          });
-          this.internalFileUrl = res.data.documentUrl;
-        } else {
+        /*  if (this.type !== "ai") { */
+        const res = await searchTaskInfo({
+          page: 1,
+          page_size: 10,
+          document_id: this.$route.query.id,
+        });
+        this.internalFileUrl = res.data.documentUrl;
+        url = res.data.documentUrl;
+        /*  } else {
           this.internalFileUrl = localStorage.getItem("href");
-        }
+          url=localStorage.getItem("href")
+        } */
 
-        const response = await fetch(this.internalFileUrl);
+        const response = await fetch(url);
         const blob = await response.blob();
 
         // 使用 LuckyExcel 加载文件

+ 58 - 58
src/views/appConfig/index.vue

@@ -131,7 +131,7 @@
               >
                 <el-option label="全部" value="all"></el-option>
                 <el-option
-                  v-for="(doc) in documentList"
+                  v-for="doc in documentList"
                   :label="doc.name"
                   :value="doc.id"
                   :key="`doc-${doc.id}`"
@@ -582,7 +582,7 @@
               >
                 <el-option label="全部" value="all"></el-option>
                 <el-option
-                  v-for="(doc) in editDocumentList"
+                  v-for="doc in editDocumentList"
                   :label="doc.name"
                   :value="doc.id"
                   :key="`edit-doc-${doc.id}`"
@@ -1840,70 +1840,35 @@ export default {
             );
             if (!parsedVariables) return;
             convertedForm.custom_variables = parsedVariables;
-
-            // 根据 radio 值处理文档和目录数据
+            // 根据radio值处理文档和目录
             if (convertedForm.radio === "1") {
-              // 目录模式:只提交目录数据,清空文档数据
-              convertedForm.documents = [];
-              // 如果选择了目录,则使用新选择的目录
-              if (this.editForm.document_directories) {
+              // 目录模式处理保持不变
+              if (
+                !this.editForm.document_directories ||
+                this.editForm.document_directories === "001"
+              ) {
+                convertedForm.document_directories = [];
+              } else {
                 convertedForm.document_directories = this.safeGetNamesByIds(
                   [this.editForm.document_directories],
                   this.editDirectoryList
                 );
-              } else {
-                // 如果没有选择新目录,保留原有目录
-                convertedForm.document_directories =
-                  this.editForm.tempDirectories;
               }
+              // 目录模式下清空文档选择
+              convertedForm.documents = [];
             } else {
-              // 文档模式:只提交文档数据,清空目录数据
+              // 文档模式
+              // 清空目录选择
               convertedForm.document_directories = [];
 
-              // 处理文档选择
-              if (convertedForm.documents.includes("all")) {
-                convertedForm.documents = ["全部"]; // 全选时传 "全部"
+              // 处理文档选择 - 如果为空则直接传空数组
+              if (!this.editForm.documents.length) {
+                convertedForm.documents = [];
               } else {
-                // 获取当前选中的文档ID列表
-                const currentSelectedIds = new Set(convertedForm.documents);
-
-                // 获取原有未删除的文档
-                const originalDocs = this.editForm.tempDocuments.filter(
-                  (doc) =>
-                    !doc.startsWith("temp_") && !currentSelectedIds.has(doc)
-                );
-
-                // 合并原有文档和新选择的文档
-                const allSelectedDocs = new Set([
-                  ...originalDocs,
-                  ...convertedForm.documents,
-                ]);
-
                 // 转换文档 ID 为名称
-                convertedForm.documents = Array.from(allSelectedDocs)
-                  .map((docId) => {
-                    // 如果是原有文档名称,直接使用
-                    if (typeof docId === "string" && !docId.match(/^[0-9]+$/)) {
-                      return docId;
-                    }
-                    // 否则查找文档名称
-                    const doc = this.editDocumentList.find(
-                      (d) => d.id === docId
-                    );
-                    return doc ? doc.name : null;
-                  })
-                  .filter((name) => name !== null); // 过滤掉未找到的文档
-
-                // 如果文档数量超过限制,保留前10个
-                if (convertedForm.documents.length > 10) {
-                  convertedForm.documents = convertedForm.documents.slice(
-                    0,
-                    10
-                  );
-                  this.$message.warning(
-                    "已超出最大文档数量限制,仅保留前10个文档"
-                  );
-                }
+                convertedForm.documents = this.editDocumentList
+                  .filter((doc) => this.editForm.documents.includes(doc.id))
+                  .map((doc) => doc.name);
               }
             }
 
@@ -2111,7 +2076,7 @@ export default {
     handleDocumentChange(selectedValues) {
       if (selectedValues.includes("all")) {
         // 如果选择了"全部",则清空其他选项
-        this.AIform.documents = ["all"];
+        this.AIform.documents = [];
       } else {
         // 如果没有选择"全部",则限制最多选择10个文档
         if (selectedValues.length > 10) {
@@ -2162,7 +2127,7 @@ export default {
               this.documentList
             ); */
             // 处理文档选择
-            if (
+            /*  if (
               convertedForm.documents.includes("all") ||
               convertedForm.documents.length === 0
             ) {
@@ -2178,7 +2143,42 @@ export default {
             convertedForm.document_directories = this.safeGetNamesByIds(
               this.AIform.document_directories,
               this.directoryList
-            );
+            ); */
+            // 根据radio值处理文档和目录
+            if (this.radio === "1") {
+              // 目录模式
+              // 如果选择了"全部"或未选择,则传空数组
+              if (
+                !this.AIform.document_directories ||
+                this.AIform.document_directories === "001"
+              ) {
+                convertedForm.document_directories = [];
+              } else {
+                convertedForm.document_directories = this.safeGetNamesByIds(
+                  [this.AIform.document_directories],
+                  this.directoryList
+                );
+              }
+              // 目录模式下清空文档选择
+              convertedForm.documents = [];
+            } else {
+              // 文档模式
+              // 清空目录选择
+              convertedForm.document_directories = [];
+
+              // 处理文档选择
+              if (
+                !this.AIform.documents.length ||
+                this.AIform.documents.includes("all")
+              ) {
+                convertedForm.documents = [];
+              } else {
+                convertedForm.documents = this.safeGetNamesByIds(
+                  this.AIform.documents,
+                  this.documentList
+                );
+              }
+            }
             /* if (convertedForm.document_directories.length === 0) {
               convertedForm.document_directories = ["全部"];
             } */

+ 55 - 41
src/views/knowledgeMenu/category/infoList.vue

@@ -6,7 +6,6 @@
         height: calc(100vh - 30px);
         overflow: auto;
         position: relative;
-        
       "
       v-if="dataList.length !== 0"
     >
@@ -15,7 +14,12 @@
           :src="item.url"
           alt=""
           @click="openImagePreview(item.url)"
-          style="width: 150px; height: 150px; padding: 10px 10px 10px 0;cursor: pointer;"
+          style="
+            width: 150px;
+            height: 150px;
+            padding: 10px 10px 10px 0;
+            cursor: pointer;
+          "
         />
         <div v-html="item.content"></div>
       </div>
@@ -58,7 +62,7 @@
     </div> -->
     <div style="width: 50%">
       <!-- 文件预览组件 -->
-      <file-preview :file-url="documentUrl" :file-type="type" />
+      <file-preview :file-url="documentUrl" :file-type="type" :type="type" />
     </div>
   </div>
   <div v-else>
@@ -151,57 +155,67 @@ export default {
   },
   methods: {
     makeDialogDraggable() {
-      const dialogHeaderEl = document.querySelector(
-        ".movable-dialog .el-dialog__header"
-      );
-      const dragDom = document.querySelector(".movable-dialog");
+      this.$nextTick(() => {
+        const dialogHeaderEl = document.querySelector(
+          ".movable-dialog .el-dialog__header"
+        );
+        const dragDom = document.querySelector(".movable-dialog");
 
-      dialogHeaderEl.style.cursor = "move";
-      dragDom.style.position = "absolute";
+        // 如果元素不存在则直接返回
+        if (!dialogHeaderEl || !dragDom) {
+          return;
+        }
 
-      // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
-      const sty =
-        dragDom.currentStyle || window.getComputedStyle(dragDom, null);
+        dialogHeaderEl.style.cursor = "move";
+        dragDom.style.position = "absolute";
 
-      dialogHeaderEl.onmousedown = (e) => {
-        // 鼠标按下,计算当前元素距离可视区的距离
-        const disX = e.clientX - dialogHeaderEl.offsetLeft;
-        const disY = e.clientY - dialogHeaderEl.offsetTop;
+        // 获取原有属性
+        const sty =
+          dragDom.currentStyle || window.getComputedStyle(dragDom, null);
 
-        // 获取到的值带px 正则匹配替换
-        let styL, styT;
+        dialogHeaderEl.onmousedown = (e) => {
+          // 鼠标按下,计算当前元素距离可视区的距离
+          const disX = e.clientX - dialogHeaderEl.offsetLeft;
+          const disY = e.clientY - dialogHeaderEl.offsetTop;
 
-        // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
-        if (sty.left.includes("%")) {
-          styL =
-            +document.body.clientWidth * (+sty.left.replace(/\%/g, "") / 100);
-          styT =
-            +document.body.clientHeight * (+sty.top.replace(/\%/g, "") / 100);
-        } else {
-          styL = +sty.left.replace(/\px/g, "");
-          styT = +sty.top.replace(/\px/g, "");
-        }
+          // 获取到的值带px 正则匹配替换
+          let styL, styT;
+
+          // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
+          if (sty.left.includes("%")) {
+            styL =
+              +document.body.clientWidth * (+sty.left.replace(/\%/g, "") / 100);
+            styT =
+              +document.body.clientHeight * (+sty.top.replace(/\%/g, "") / 100);
+          } else {
+            styL = +sty.left.replace(/\px/g, "");
+            styT = +sty.top.replace(/\px/g, "");
+          }
 
-        document.onmousemove = function (e) {
-          // 通过事件委托,计算移动的距离
-          const l = e.clientX - disX;
-          const t = e.clientY - disY;
+          document.onmousemove = function (e) {
+            // 通过事件委托,计算移动的距离
+            const l = e.clientX - disX;
+            const t = e.clientY - disY;
 
-          // 移动当前元素
-          dragDom.style.left = `${l + styL}px`;
-          dragDom.style.top = `${t + styT}px`;
-        };
+            // 移动当前元素
+            dragDom.style.left = `${l + styL}px`;
+            dragDom.style.top = `${t + styT}px`;
+          };
 
-        document.onmouseup = function (e) {
-          document.onmousemove = null;
-          document.onmouseup = null;
+          document.onmouseup = function (e) {
+            document.onmousemove = null;
+            document.onmouseup = null;
+          };
         };
-      };
+      });
     },
     openImagePreview(url) {
       this.previewImageUrl = url;
       this.imagePreviewVisible = true;
-      this.$nextTick(this.makeDialogDraggable);
+      // 改为在 dialog 打开后执行
+      this.$nextTick(() => {
+        setTimeout(this.makeDialogDraggable, 100); // 添加小延时确保 DOM 已完全渲染
+      });
     },
     /* 分页 */
     handleCurrentChange(page) {

+ 348 - 23
src/views/project/ProjectInput.vue

@@ -60,19 +60,48 @@
               />
             </el-select>
           </el-form-item>
+          <!-- 添加时间范围选择器 -->
+          <el-form-item label="创建时间">
+            <el-date-picker
+              v-model="gsprSearchForm.dateRange"
+              type="daterange"
+              range-separator="至"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              value-format="yyyy-MM-dd"
+              :picker-options="pickerOptions"
+            />
+          </el-form-item>
+          <!-- 添加内容状态筛选 -->
+          <el-form-item label="内容状态">
+            <el-select
+              v-model="gsprSearchForm.hasContent"
+              placeholder="请选择"
+              clearable
+            >
+              <el-option label="有内容" :value="true" />
+              <el-option label="无内容" :value="false" />
+            </el-select>
+          </el-form-item>
           <el-form-item>
             <el-button type="primary" @click="handleGsprSearch">搜索</el-button>
             <el-button @click="handleGsprReset">重置</el-button>
           </el-form-item>
         </el-form>
       </div>
-
+      <div>
+        <el-button
+            type="primary"
+            >导出输入项目</el-button
+          >
+      </div>
       <el-table
         :data="gsprTableData"
         style="width: 100%"
         :default-sort="{ prop: sort_field, order: sort_order }"
         @sort-change="handleSortChange"
       >
+        <el-table-column prop="sort" label="排序" sortable="custom" width="80" />
         <el-table-column prop="name" label="项目名称" sortable="custom" />
         <el-table-column prop="tech_report_location" label="技术报告位置" />
         <el-table-column prop="department" label="部门" sortable="custom" />
@@ -88,6 +117,7 @@
             </div>
           </template>
         </el-table-column>
+        <el-table-column prop="" label="难度" sortable="custom" />
         <el-table-column label="操作" width="200">
           <template slot-scope="scope">
             <el-button type="primary" @click="handleEditGspr(scope.row)"
@@ -141,14 +171,16 @@
               />
             </el-select>
           </el-form-item>
-          <el-form-item label="内容" prop="content">
-            <el-input
-              type="textarea"
-              v-model="gsprForm.content"
-              :rows="4"
-              placeholder="请输入内容"
-            />
-          </el-form-item>
+          <!--  <el-form-item label="内容" prop="content">
+            <div class="editor-area sticky-editor">
+              <ckeditor
+                ref="editor"
+                v-model="gsprForm.content"
+                :config="editorConfig"
+                :editorUrl="editorUrl"
+              ></ckeditor>
+            </div>
+          </el-form-item> -->
         </el-form>
         <div slot="footer">
           <el-button @click="gsprDialogVisible = false">取消</el-button>
@@ -159,18 +191,24 @@
       <el-dialog
         title="编辑内容"
         :visible.sync="contentDialogVisible"
-        width="600px"
+        width="80%"
       >
-        <el-form :model="contentForm" ref="contentForm">
-          <el-form-item label="内容" prop="content">
-            <el-input
+        <!--  <el-form :model="contentForm" ref="contentForm">
+          <el-form-item label="内容" prop="content"> -->
+        <!-- <el-inputwidth="600px"
               type="textarea"
               v-model="contentForm.content"
               :rows="4"
               placeholder="请输入内容"
-            />
-          </el-form-item>
-        </el-form>
+            /> -->
+        <ckeditor
+          ref="editor"
+          v-model="contentForm.content"
+          :config="editorConfig"
+          :editorUrl="editorUrl"
+        ></ckeditor>
+        <!--   </el-form-item>
+        </el-form> -->
         <div slot="footer">
           <el-button @click="contentDialogVisible = false">取消</el-button>
           <el-button type="primary" @click="handleContentSubmit"
@@ -239,8 +277,11 @@ import {
 } from "@/api/knowledge";
 import { searchProject } from "@/api/project";
 import { mapState } from "vuex";
-
+import CKEditor from "ckeditor4-vue";
 export default {
+  compnents: {
+    ckeditor: CKEditor.component,
+  },
   data() {
     // 自定义验证规则
     const validateDeleteConfirm = (rule, value, callback) => {
@@ -251,6 +292,28 @@ export default {
       }
     };
     return {
+      pickerOptions: {
+        shortcuts: [
+          {
+            text: "最近一周",
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+              picker.$emit("pick", [start, end]);
+            },
+          },
+          {
+            text: "最近一个月",
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setMonth(start.getMonth() - 1);
+              picker.$emit("pick", [start, end]);
+            },
+          },
+        ],
+      },
       selectedProjectId: null,
       projectOptions: [],
       gsprTableData: [],
@@ -258,6 +321,8 @@ export default {
         keyword: "",
         department: "",
         project_id: null,
+        dateRange: [], // 添加时间范围
+        hasContent: null, // 添加内容状态
       },
       gsprPageForm: {
         page: 1,
@@ -312,6 +377,11 @@ export default {
           { validator: validateDeleteConfirm, trigger: "blur" },
         ],
       },
+      editorUrl: "/ckeditor/ckeditor.js",
+      editorConfig: {
+        language: "zh-cn",
+        height: "300px",
+      },
     };
   },
   mounted() {
@@ -348,26 +418,178 @@ export default {
       console.log(this.gsprForm);
       this.gsprDialogVisible = true;
     },
-    /* 编辑内容 */
+    // 修改编辑内容显示方法
     handleEditContent(row) {
       const selectedProject = this.projectOptions.find(
         (p) => p.id === this.selectedProjectId
       );
+
+      // 处理content内容,将文本格式转换为HTML并清理空样式
+      const processedContent = this.cleanEmptyStyles(
+        this.convertTextToHtml(row.content)
+      );
+
       this.contentForm = {
         project: selectedProject.id,
         project_name: selectedProject.name,
         id: row.id,
         tech_report_location: row.tech_report_location,
-        content: row.content,
+        content: processedContent,
         name: row.name,
         department: row.department,
       };
       this.contentDialogVisible = true;
     },
+
+    // 修改回显方法,解析样式
+    convertTextToHtml(text) {
+      if (!text) return "";
+
+      let html = text;
+
+      // 处理表格标记(包含边框样式)
+      html = html.replace(
+        /\[表格\|style=(.*?)\|class=(.*?)\]([\s\S]*?)(?=\[|$)/g,
+        (match, tableStyle, tableClass, tableContent) => {
+          const rows = tableContent.trim().split("\n");
+          let tableHtml = `<table style="${tableStyle}" class="${tableClass}">`;
+
+          rows.forEach((row) => {
+            tableHtml += "<tr>";
+            const cells = row.split("|").map((cell) => {
+              const cellMatch = cell.match(
+                /(.*?)(?:\[style=(.*?)\|class=(.*?)\])?$/
+              );
+              if (cellMatch) {
+                const [_, content, style = "", className = ""] = cellMatch;
+                return `<td style="${style}" class="${className}">${content.trim()}</td>`;
+              }
+              return `<td>${cell.trim()}</td>`;
+            });
+            tableHtml += cells.join("") + "</tr>";
+          });
+
+          tableHtml += "</table>";
+          return tableHtml;
+        }
+      );
+
+      // 2. 处理图片标记(保持不变)
+      html = html.replace(
+        /\[图片:(.*?)\|style=(.*?)\|class=(.*?)\]/g,
+        (match, src, style, className) => {
+          return `<img src="${src}" alt="图片" style="${style}" class="${className}">`;
+        }
+      );
+
+      // 3. 处理文本样式(保持不变)
+      html = html.replace(
+        /\[文本:(.*?)\|style=(.*?)\|class=(.*?)\]/g,
+        (match, content, style, className) => {
+          return `<span style="${style}" class="${className}">${content}</span>`;
+        }
+      );
+
+      // 4. 处理换行
+      html = html.replace(/\n/g, "<br>");
+
+      return html;
+    },
+
+    // 添加辅助方法:清理空样式属性
+    cleanEmptyStyles(html) {
+      return html
+        .replace(/style=""/g, "")
+        .replace(/class=""/g, "")
+        .replace(/\s+>/g, ">");
+    },
     /*  */
     async handleContentSubmit() {
       try {
-        await projectUpdate(this.contentForm);
+        // 创建一个函数来处理富文本内容,保留样式
+        const processContent = (htmlContent) => {
+          const tempDiv = document.createElement("div");
+          tempDiv.innerHTML = htmlContent;
+
+          // 处理图片:保留样式属性
+          const images = tempDiv.getElementsByTagName("img");
+          Array.from(images).forEach((img) => {
+            const style = img.getAttribute("style") || "";
+            const className = img.getAttribute("class") || "";
+            const imgPlaceholder = `[图片:${img.src}|style=${style}|class=${className}]`;
+            img.replaceWith(document.createTextNode(imgPlaceholder));
+          });
+
+          // 处理表格:保留完整的样式属性,包括边框
+          const tables = tempDiv.getElementsByTagName("table");
+          Array.from(tables).forEach((table) => {
+            const tableStyle = table.getAttribute("style") || "";
+            const tableClass = table.getAttribute("class") || "";
+            const tableBorder = table.getAttribute("border") || "";
+
+            const rows = Array.from(table.rows).map((row) => {
+              return Array.from(row.cells)
+                .map((cell) => {
+                  const cellStyle = cell.getAttribute("style") || "";
+                  const cellClass = cell.getAttribute("class") || "";
+                  const cellBorder = cell.getAttribute("border") || "";
+                  const content = cell.textContent.trim();
+
+                  // 合并所有样式属性
+                  const cellStyles = [
+                    cellStyle,
+                    cellBorder ? `border: ${cellBorder}px solid #000;` : "",
+                  ]
+                    .filter(Boolean)
+                    .join(" ");
+
+                  return `${content}${
+                    cellStyles || cellClass
+                      ? `[style=${cellStyles}|class=${cellClass}]`
+                      : ""
+                  }`;
+                })
+                .join("|");
+            });
+
+            // 合并表格的样式属性
+            const tableStyles = [
+              tableStyle,
+              tableBorder ? `border: ${tableBorder}px solid #000;` : "",
+            ]
+              .filter(Boolean)
+              .join(" ");
+
+            const tablePlaceholder = `[表格|style=${tableStyles}|class=${tableClass}]\n${rows.join(
+              "\n"
+            )}`;
+            table.replaceWith(document.createTextNode(tablePlaceholder));
+          });
+
+          // 处理文本样式
+          const styledSpans = tempDiv.getElementsByTagName("span");
+          Array.from(styledSpans).forEach((span) => {
+            const style = span.getAttribute("style") || "";
+            const className = span.getAttribute("class") || "";
+            if (style || className) {
+              const content = span.textContent;
+              span.replaceWith(
+                document.createTextNode(
+                  `[文本:${content}|style=${style}|class=${className}]`
+                )
+              );
+            }
+          });
+
+          return tempDiv.textContent || tempDiv.innerText;
+        };
+
+        const submitData = {
+          ...this.contentForm,
+          content: processContent(this.contentForm.content),
+        };
+
+        await projectUpdate(submitData);
         this.$message.success("内容更新成功");
         this.contentDialogVisible = false;
         this.fetchGsprData();
@@ -375,6 +597,60 @@ export default {
         this.$message.error("内容更新失败");
       }
     },
+
+    // 同样修改handleGsprSubmit方法
+    async handleGsprSubmit() {
+      try {
+        await this.$refs.gsprForm.validate();
+
+        // 处理富文本内容
+        const processContent = (htmlContent) => {
+          const tempDiv = document.createElement("div");
+          tempDiv.innerHTML = htmlContent;
+
+          // 处理图片
+          const images = tempDiv.getElementsByTagName("img");
+          Array.from(images).forEach((img) => {
+            const imgPlaceholder = `[图片:${img.src}]`;
+            img.replaceWith(document.createTextNode(imgPlaceholder));
+          });
+
+          // 处理表格
+          const tables = tempDiv.getElementsByTagName("table");
+          Array.from(tables).forEach((table) => {
+            const rows = Array.from(table.rows).map((row) =>
+              Array.from(row.cells)
+                .map((cell) => cell.textContent.trim())
+                .join(" | ")
+            );
+            const tablePlaceholder = "[表格]\n" + rows.join("\n");
+            table.replaceWith(document.createTextNode(tablePlaceholder));
+          });
+
+          return tempDiv.textContent || tempDiv.innerText;
+        };
+
+        // 创建新对象避免修改原始数据
+        const submitData = {
+          ...this.gsprForm,
+          content: processContent(this.gsprForm.content),
+        };
+
+        if (this.gsprForm.id) {
+          await projectUpdate(submitData);
+        } else {
+          await projectAdd(submitData);
+        }
+
+        this.$message.success(this.gsprForm.id ? "更新成功" : "创建成功");
+        this.gsprDialogVisible = false;
+        this.fetchGsprData();
+      } catch (error) {
+        if (error !== false) {
+          this.$message.error("保存失败");
+        }
+      }
+    },
     /*  */
     async handleGsprSubmit() {
       try {
@@ -561,8 +837,8 @@ export default {
           });
         });
     },
-      // 确认删除
-      confirmDelete() {
+    // 确认删除
+    confirmDelete() {
       this.$refs.deleteForm.validate(async (valid) => {
         if (!valid) {
           return false;
@@ -616,7 +892,12 @@ export default {
           project_id: this.selectedProjectId,
           ...this.gsprPageForm,
           ...this.gsprSearchForm,
+          // 处理日期范围
+          start_date: this.gsprSearchForm.dateRange?.[0] || null,
+          end_date: this.gsprSearchForm.dateRange?.[1] || null,
         };
+        // 删除原始dateRange参数
+        delete params.dateRange;
         const response = await projectList(params);
         if (response.status === 200) {
           this.gsprTableData = response.data.list;
@@ -652,6 +933,8 @@ export default {
         keyword: "",
         department: "",
         project_id: this.selectedProjectId,
+        dateRange: [], // 重置时间范围
+        hasContent: null, // 重置内容状态
       };
       this.handleGsprSearch();
     },
@@ -669,12 +952,54 @@ export default {
   },
 };
 </script>
-<style >
+<style lang="scss" >
+.project-input-container {
+  padding: 20px;
+}
+.pagination-container {
+  display: flex;
+  justify-content: flex-end;
+}
+.editor-area {
+  ::v-deep .cke_top {
+    display: block; // Hide the original toolbar
+  }
+}
 .project-input-container {
   padding: 20px;
 }
+
 .pagination-container {
   display: flex;
   justify-content: flex-end;
 }
+
+/* 添加编辑器工具栏样式 */
+.editor-area {
+  .cke_top {
+    display: flex !important;
+    justify-content: space-between;
+    align-items: center;
+    padding: 6px 8px !important;
+
+    /* 工具栏组样式 */
+    .cke_toolgroup {
+      margin: 0 2px;
+      display: flex;
+      align-items: center;
+    }
+
+    /* 工具栏按钮样式 */
+    .cke_toolbar {
+      float: none !important;
+      display: inline-flex;
+      align-items: center;
+    }
+  }
+}
+
+/* 如果需要调整编辑器容器宽度 */
+.cke_chrome {
+  width: 100% !important;
+}
 </style>

+ 670 - 182
src/views/project/components/dataList.vue

@@ -12,9 +12,11 @@
           <span>{{ getCategoryName(scope.row.categoryId) }}</span>
         </template>
       </el-table-column>
-      <!-- <el-table-column prop="customer.name" label="所属客户" align="left" min-width="180"/> -->
+      <!--  -->
       <el-table-column prop="name" label="项目名称" align="left" />
       <el-table-column prop="createTime" label="创建时间" align="center" />
+      <el-table-column prop="updateTime" label="更新时间" align="center" />
+      <el-table-column prop="" label="完成度" align="center" />
       <el-table-column
         prop="statusName"
         label="项目状态"
@@ -22,8 +24,12 @@
         width="180"
       >
         <template #default="scope">
-          <div v-if="scope.row.status == 5">启用</div>
-          <div v-if="scope.row.status == 6">停用</div>
+          <el-tag
+            :type="scope.row.status === 5 ? 'success' : 'danger'"
+            effect="plain"
+          >
+            {{ scope.row.status === 5 ? "启用" : "停用" }}
+          </el-tag>
         </template>
       </el-table-column>
       <el-table-column label="操作" align="center" fixed="right">
@@ -149,7 +155,13 @@
       width="50%"
       append-to-body
     >
-      <el-table :data="boundTemplateList" style="width: 100%">
+      <el-table
+        :data="boundTemplateList"
+        style="width: 100%"
+        @selection-change="handleBoundTemplateSelect"
+        ref="boundTemplateTable"
+      >
+        <el-table-column type="selection" width="55"></el-table-column>
         <el-table-column prop="id" label="ID" width="80" align="center" />
         <el-table-column prop="title" label="模版名称" align="left" />
         <el-table-column prop="create_time" label="绑定时间" align="center" />
@@ -164,6 +176,16 @@
           </template>
         </el-table-column>
       </el-table>
+      <div class="dialog-footer" style="margin-top: 20px; text-align: right">
+        <el-button
+          type="primary"
+          @click="batchReplace"
+          :loading="batchReplaceLoading"
+          :disabled="selectedBoundTemplates.length === 0"
+        >
+          批量替换
+        </el-button>
+      </div>
     </el-dialog>
     <el-dialog
       title=""
@@ -265,6 +287,8 @@ export default {
       docAttr: {},
       templateLoading: false, // 添加模版加载状态
       boundTemplateLoading: false, // 添加已绑定模版加载状态
+      selectedBoundTemplates: [], // 新增:已选择的绑定模版
+      batchReplaceLoading: false, // 新增:批量替换loading状态
     };
   },
   mounted() {
@@ -337,50 +361,84 @@ export default {
         this.selTemplate(this.currentData); */
       /* }); */
     },
+    // 新增:处理已绑定模版的选择
+    handleBoundTemplateSelect(selection) {
+      this.selectedBoundTemplates = selection;
+    },
+
+    // 新增:批量替换方法
+    async batchReplace() {
+      if (this.selectedBoundTemplates.length === 0) {
+        this.$message.warning("请选择需要替换的模版");
+        return;
+      }
+
+      this.batchReplaceLoading = true;
+      try {
+        // 依次处理每个选中的模版
+        for (const template of this.selectedBoundTemplates) {
+          this.docAttr = template;
+          const TemList = JSON.parse(template.data);
+          await this.searchEx(TemList);
+
+          if (this.matchResults.length > 0) {
+            await this.replaceAll();
+          }
+        }
+
+        this.$message.success("批量替换完成");
+        this.boundTemplatesDialogVisible = false;
+      } catch (error) {
+        console.error("批量替换失败:", error);
+        this.$message.error("批量替换过程中发生错误");
+      } finally {
+        this.batchReplaceLoading = false;
+      }
+    },
 
     searchEx(val) {
-      let allMatches = [];
-      this.TemList = val;
-      this.TemList.forEach((el) => {
-        // 创建临时 div 来解析 HTML 内容
-        const tempDiv = document.createElement("div");
-        tempDiv.innerHTML = el.content;
-        const plainText = tempDiv.textContent || tempDiv.innerText;
-
-        // 分别匹配中文括号和英文括号
-        const patterns = [
-          /【([A-Z]{1,4}[0-9]{0,2})-([A-Z]{1,4}[0-9]{0,2})-([0-9]{2})-([0-9]{2,3})】/g,
-          /\[([A-Z]{1,4}[0-9]{0,2})-([A-Z]{1,4}[0-9]{0,2})-([0-9]{2})-([0-9]{2,3})\]/g,
-        ];
-
-        patterns.forEach((pattern) => {
-          let match;
-          while ((match = pattern.exec(plainText)) !== null) {
-            const fullMatch = match[0];
-            const segments = [match[1], match[2], match[3], match[4]];
-
-            // 验证每个段落的格式
-            const isValid = segments.every((segment) => segment.length > 0);
-
-            if (isValid) {
-              allMatches.push(fullMatch);
+      return new Promise((resolve) => {
+        let allMatches = [];
+        this.TemList = val;
+        this.TemList.forEach((el) => {
+          // 创建临时 div 来解析 HTML 内容
+          const tempDiv = document.createElement("div");
+          tempDiv.innerHTML = el.content;
+          const plainText = tempDiv.textContent || tempDiv.innerText;
+
+          // 分别匹配中文括号和英文括号
+          const patterns = [
+            /【([A-Z]{1,4}[0-9]{0,2})-([A-Z]{1,4}[0-9]{0,2})-([0-9]{2})-([0-9]{2,3})】/g,
+            /\[([A-Z]{1,4}[0-9]{0,2})-([A-Z]{1,4}[0-9]{0,2})-([0-9]{2})-([0-9]{2,3})\]/g,
+          ];
+
+          patterns.forEach((pattern) => {
+            let match;
+            while ((match = pattern.exec(plainText)) !== null) {
+              const fullMatch = match[0];
+              const segments = [match[1], match[2], match[3], match[4]];
+
+              // 验证每个段落的格式
+              const isValid = segments.every((segment) => segment.length > 0);
+
+              if (isValid) {
+                allMatches.push(fullMatch);
+              }
             }
-          }
+          });
         });
-      });
 
-      this.matchResults = [...new Set(allMatches)];
-      console.log("匹配结果:", this.matchResults);
-
-      // 调试用:打印每个匹配的详细信息
-      this.matchResults.forEach((match) => {
-        console.log("找到匹配:", match);
-        // 根据括号类型选择不同的切片方式
-        const content = match.startsWith("【")
-          ? match.slice(1, -1)
-          : match.slice(1, -1);
-        const parts = content.split("-");
-        console.log("分段:", parts);
+        this.matchResults = [...new Set(allMatches)];
+
+        // 调试用:打印每个匹配的详细信息
+        this.matchResults.forEach((match) => {
+          // 根据括号类型选择不同的切片方式
+          const content = match.startsWith("【")
+            ? match.slice(1, -1)
+            : match.slice(1, -1);
+          const parts = content.split("-");
+        });
+        resolve();
       });
     },
 
@@ -422,76 +480,142 @@ export default {
       return params;
     },
 
-    // 单个替换
-    replaceItem(item) {
-      // 去掉方括号
-      const cleanItem = item.replace(/[\[\]]/g, "");
-      this.$confirm(`确认替换 ${item}?`, "提示", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning",
-      })
-        .then(async () => {
-          try {
-            const params = this.formatRequestParams(cleanItem);
-            const response = await axios.post(
-              `${process.env.VUE_APP_BASE_API}/project-raw-data/batch-content`,
-              params,
-              {
-                headers: {
-                  "Content-Type": "application/json",
-                },
-              }
-            );
+    // 添加表格内容处理方法
+    /*  processTableContent(content, searchItem, replacement) {
+      // 创建临时div解析HTML内容
+      const tempDiv = document.createElement("div");
+      tempDiv.innerHTML = content;
 
-            if (response.status === 200 && response.data) {
-              console.log(response.data.data);
-              // 修改获取替换值的逻辑
-              const replacementValue =
-                response.data.data.input_item_contents[0]?.content;
-
-              if (replacementValue) {
-                this.TemList.forEach((el, index) => {
-                  this.$set(
-                    this.TemList[index],
-                    "content",
-                    el.content.replace(
-                      new RegExp(this.escapeRegExp(item), "g"),
-                      replacementValue
-                    )
-                  );
-                });
-
-                this.matchResults = this.matchResults.filter(
-                  (match) => match !== item
-                );
-                this.onUpload();
-                this.$message.success("替换成功");
-                //this.$emit("close"); // 成功后触发关闭事件
-              } else {
-                this.$message.warning("未获取到替换内容");
-              }
+      // 处理表格内容
+      const tables = tempDiv.getElementsByTagName("table");
+      Array.from(tables).forEach((table) => {
+        const cells = table.getElementsByTagName("td");
+        Array.from(cells).forEach((cell) => {
+          if (cell.textContent.includes(searchItem)) {
+            // 保存原有的样式和类名
+            const cellStyle = cell.getAttribute("style") || "";
+            const cellClass = cell.getAttribute("class") || "";
+
+            // 处理替换内容
+            const processedReplacement = this.parseContent(replacement);
+
+            // 如果替换内容包含表格或图片,需要特殊处理
+            if (this.containsTableOrImage(processedReplacement)) {
+              cell.innerHTML = processedReplacement;
             } else {
-              this.$message.error("获取替换内容失败");
+              // 普通文本替换,保持原有样式
+              cell.innerHTML = cell.innerHTML.replace(
+                new RegExp(this.escapeRegExp(searchItem), "g"),
+                processedReplacement
+              );
             }
-          } catch (error) {
-            console.error("替换失败:", error);
-            this.$message.error(error.response?.data?.message || "替换失败");
+
+            // 恢复样式和类名
+            if (cellStyle) cell.setAttribute("style", cellStyle);
+            if (cellClass) cell.setAttribute("class", cellClass);
           }
-        })
-        .catch(() => {
-          // 取消操作
         });
+      });
+
+      // 处理普通文本内容
+      const textNodes = this.getTextNodes(tempDiv);
+      textNodes.forEach((node) => {
+        if (node.textContent.includes(searchItem)) {
+          const processedReplacement = this.parseContent(replacement);
+          const span = document.createElement("span");
+          span.innerHTML = node.textContent.replace(
+            new RegExp(this.escapeRegExp(searchItem), "g"),
+            processedReplacement
+          );
+          node.parentNode.replaceChild(span, node);
+        }
+      });
+
+      return tempDiv.innerHTML;
+    }, */
+
+    // 解析内容,处理特殊标记
+    parseContent(content) {
+      if (!content) return "";
+
+      let parsed = content;
+
+      // 处理图片标记
+      parsed = parsed.replace(
+        /\[图片:(.*?)\|style=(.*?)\|class=(.*?)\]/g,
+        (match, src, style, className) => {
+          return `<img src="${src}" alt="图片" style="${style}" class="${className}">`;
+        }
+      );
+
+      // 处理表格标记
+      parsed = parsed.replace(
+        /\[表格\|style=(.*?)\|class=(.*?)\]\n([\s\S]*?)(?=\[|$)/g,
+        (match, tableStyle, tableClass, tableContent) => {
+          const rows = tableContent.trim().split("\n");
+          let tableHtml = `<table style="${tableStyle}" class="${tableClass}">`;
+
+          rows.forEach((row) => {
+            tableHtml += "<tr>";
+            const cells = row.split(" | ").map((cell) => {
+              const [content, ...styleInfo] = cell.split("[style=");
+              if (styleInfo.length) {
+                const [style, className] = styleInfo[0]
+                  .slice(0, -1)
+                  .split("|class=");
+                return `<td style="${style}" class="${className}">${content}</td>`;
+              }
+              return `<td>${content}</td>`;
+            });
+            tableHtml += cells.join("") + "</tr>";
+          });
+
+          tableHtml += "</table>";
+          return tableHtml;
+        }
+      );
+
+      // 处理文本样式
+      parsed = parsed.replace(
+        /\[文本:(.*?)\|style=(.*?)\|class=(.*?)\]/g,
+        (match, content, style, className) => {
+          return `<span style="${style}" class="${className}">${content}</span>`;
+        }
+      );
+
+      return parsed;
+    },
+
+    // 检查内容是否包含表格或图片
+    containsTableOrImage(content) {
+      return content.includes("<table") || content.includes("<img");
+    },
+
+    // 获取所有文本节点
+    getTextNodes(node) {
+      const textNodes = [];
+      const walk = document.createTreeWalker(
+        node,
+        NodeFilter.SHOW_TEXT,
+        null,
+        false
+      );
+      let currentNode;
+      while ((currentNode = walk.nextNode())) {
+        textNodes.push(currentNode);
+      }
+      return textNodes;
     },
+
     /*更新  */
     onUpload() {
       let _this = this;
       if (_this.TemList.length <= 0) {
-        _this.$alert("增加组件");
+        _this.$message.error("增加组件");
         return;
       }
       if (_this.docAttr.title == "") {
-        _this.$alert("请填写模版标题");
+        _this.$message.error("请填写模版标题");
         return;
       }
       _this.docAttr.links = JSON.stringify(_this.docAttr.linkProduct);
@@ -504,100 +628,464 @@ export default {
       updateDocument(_this.docAttr).then((res) => {
         if (res.status != 200) return; //更新文档
         _this.docAttr.id = res.data;
-        _this.$alert("模版更新成功");
-        _this.searchArticle();
+        _this.$message.success("模版更新成功");
       });
     },
-    /*批量替换 */
-    replaceAll() {
-      this.loadingAll = true;
+    // 修改 convertTextToHtml 方法
+    /* convertTextToHtml(text) {
+      if (!text) return "";
 
-      this.$confirm(
-        `确认批量替换 ${this.matchResults.length} 项内容?`,
-        "提示",
-        {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning",
-        }
-      )
-        .then(async () => {
-          try {
-            // 清理所有项的方括号
-            const cleanItems = this.matchResults.map((item) =>
-              item.replace(/[\[\]]/g, "")
-            );
-            const params = this.formatRequestParams(cleanItems);
-            const response = await axios.post(
-              `${process.env.VUE_APP_BASE_API}/project-raw-data/batch-content`,
-              params,
-              {
-                headers: {
-                  "Content-Type": "application/json",
-                },
-              }
-            );
+      let html = text;
 
-            if (response.status === 200 && response.data) {
-              // 修改这里,使用与单个替换相同的数据结构
-              const replacementValues =
-                response.data.data.input_item_contents?.map(
-                  (item) => item.content
-                );
-              // 添加验证:检查是否所有值都为 null
-              if (replacementValues.every((value) => value === null)) {
-                this.$message.warning("所有替换内容均无效,请检查数据");
-                return;
-              }
+      // 修改表格处理逻辑
+      html = html.replace(
+        /\[表格\|style=(.*?)\|class=(.*?)\]([\s\S]*?)(?=\[|$)/g,
+        (match, tableStyle, tableClass, tableContent) => {
+          // 移除多余的空行
+          const rows = tableContent
+            .trim()
+            .split("\n")
+            .filter((row) => row.trim());
+          let tableHtml = `<table style="${tableStyle}" class="${tableClass}">`;
 
-              // 添加验证:检查是否存在 null 值
-              const nullCount = replacementValues.filter(
-                (value) => value === null
-              ).length;
-              if (nullCount > 0) {
-                this.$message.warning(
-                  `${nullCount} 项内容无法替换,请检查数据`
-                );
-                return;
-              }
-              if (replacementValues.length > 0) {
-                this.TemList.forEach((el, index) => {
-                  let updatedContent = el.content;
-                  this.matchResults.forEach((item, idx) => {
-                    const replacementValue = replacementValues[idx];
-                    if (replacementValue) {
-                      updatedContent = updatedContent.replace(
-                        new RegExp(this.escapeRegExp(item), "g"),
-                        replacementValue
-                      );
-                    }
-                  });
-                  this.$set(this.TemList[index], "content", updatedContent);
-                });
-                this.onUpload();
-                this.matchResults = [];
-                this.$message.success("批量替换成功");
-                // this.$emit("close"); // 成功后触发关闭事件
+          // 处理表头行
+          if (rows.length > 0) {
+            const headerCells = rows[0].split("|").map((cell) => cell.trim());
+            tableHtml += "<tr>";
+            headerCells.forEach((cell) => {
+              tableHtml += `<th>${cell}</th>`;
+            });
+            tableHtml += "</tr>";
+          }
+
+          // 处理数据行
+          for (let i = 1; i < rows.length; i++) {
+            const cells = rows[i].split("|").map((cell) => cell.trim());
+            tableHtml += "<tr>";
+            cells.forEach((cell) => {
+              // 检查单元格是否包含空格分隔的值
+              const [content, value] = cell.split(/\s+/);
+              if (value) {
+                // 如果有值,创建带有两列的单元格
+                tableHtml += `
+                <td>
+                  <div style="display: flex; justify-content: space-between;">
+                    <span>${content}</span>
+                    <span style="color: #666;">${value}</span>
+                  </div>
+                </td>`;
               } else {
-                this.$message.warning("未获取到替换内容");
+                // 如果只有内容,创建普通单元格
+                tableHtml += `<td>${content}</td>`;
               }
+            });
+            tableHtml += "</tr>";
+          }
+
+          tableHtml += "</table>";
+          return tableHtml;
+        }
+      );
+
+      // 保持原有的图片和文本处理逻辑不变
+      html = html.replace(
+        /\[图片:(.*?)\|style=(.*?)\|class=(.*?)\]/g,
+        (match, src, style, className) => {
+          return `<img src="${src}" alt="图片" style="${style}" class="${className}">`;
+        }
+      );
+
+      html = html.replace(
+        /\[文本:(.*?)\|style=(.*?)\|class=(.*?)\]/g,
+        (match, content, style, className) => {
+          return `<span style="${style}" class="${className}">${content}</span>`;
+        }
+      );
+
+      return html;
+    }, */
+
+    // 添加统一的内容处理方法
+    async processAndReplaceContent(content, originalMatch) {
+      try {
+        const params = this.formatRequestParams(originalMatch);
+        const response = await axios.post(
+          `${process.env.VUE_APP_BASE_API}/project-raw-data/batch-content`,
+          params,
+          {
+            headers: {
+              "Content-Type": "application/json",
+            },
+          }
+        );
+
+        if (response.status === 200 && response.data) {
+          const replacementContent =
+            response.data.data.matched_data[0]?.content;
+          if (replacementContent) {
+            // 处理富文本内容
+            this.TemList.forEach((el, index) => {
+              const processedContent = this.processTableContent(
+                el.content,
+                originalMatch,
+                replacementContent
+              );
+              this.$set(this.TemList[index], "content", processedContent);
+            });
+            return true;
+          }
+        }
+        return false;
+      } catch (error) {
+        console.error("处理内容失败:", error);
+        return false;
+      }
+    },
+
+    // 修改单个替换方法
+    async replaceItem(item) {
+      try {
+        const success = await this.processAndReplaceContent(this.TemList, item);
+        if (success) {
+          this.matchResults = this.matchResults.filter(
+            (match) => match !== item
+          );
+          this.onUpload();
+          this.$message.success("替换成功");
+        } else {
+          this.$message.warning("未获取到替换内容");
+        }
+      } catch (error) {
+        console.error("替换失败:", error);
+        this.$message.error(error.response?.data?.message || "替换失败");
+      }
+    },
+
+    // 修改批量替换方法
+    async replaceAll() {
+      this.batchReplaceLoading = true;
+      try {
+        // 收集所有匹配项
+        const allLocations = this.matchResults.map((item) => {
+          // 清理括号
+          return item.replace(/[\[\]【】]/g, "");
+        });
+
+        // 格式化所有位置的请求参数
+        const params = {
+          template_location: [],
+          middle_layer_location: [],
+          tech_report_location: [],
+          other_location: [],
+        };
+
+        // 遍历所有位置并分类
+        allLocations.forEach((location) => {
+          // 为每种类型创建对应长度的数组
+          const type = this.getDocumentType(location);
+          Object.keys(params).forEach((key) => {
+            if (type === key) {
+              params[key].push(location);
             } else {
-              this.$message.error("获取替换内容失败");
+              params[key].push("");
             }
-          } catch (error) {
-            console.error("批量替换失败:", error);
-            this.$message.error(
-              error.response?.data?.message || "批量替换失败"
-            );
+          });
+        });
+
+        // 发送单个批量请求
+        const response = await axios.post(
+          `${process.env.VUE_APP_BASE_API}/project-raw-data/batch-content`,
+          params,
+          {
+            headers: {
+              "Content-Type": "application/json",
+            },
           }
-        })
-        .catch(() => {
-          // 取消操作
-        })
-        .finally(() => {
-          this.loadingAll = false;
+        );
+
+        if (response.status === 200 && response.data) {
+          const replacementContents = response.data.data.matched_data;
+
+          if (replacementContents && replacementContents.length > 0) {
+            // 更新所有内容
+            this.TemList.forEach((el, index) => {
+              let updatedContent = el.content;
+
+              // 遍历所有替换内容和对应的匹配项
+              this.matchResults.forEach((item, idx) => {
+                const replacement = replacementContents[idx]?.content;
+                if (replacement) {
+                  // 处理表格和其他内容
+                  updatedContent = this.processTableContent(
+                    updatedContent,
+                    item,
+                    replacement
+                  );
+                }
+              });
+
+              // 更新内容
+              this.$set(this.TemList[index], "content", updatedContent);
+            });
+
+            // 更新文档
+            await this.onUpload();
+            this.matchResults = [];
+            this.$message.success("批量替换成功");
+            this.replaceVisible = false;
+          } else {
+            this.$message.warning("未获取到替换内容");
+          }
+        }
+      } catch (error) {
+        console.error("批量替换失败:", error);
+        this.$message.error(error.response?.data?.message || "批量替换失败");
+      } finally {
+        this.batchReplaceLoading = false;
+      }
+    },
+
+    // 辅助方法:获取文档类型
+    getDocumentType(code) {
+      if (code.includes("-RP-")) return "template_location";
+      if (code.includes("-IR-")) return "middle_layer_location";
+      if (code.includes("-WE-")) return "tech_report_location";
+      return "other_location";
+    },
+
+    // 修改处理表格内容的方法,添加对多个替换的支持
+    processTableContent(content, searchItem, replacement) {
+      const tempDiv = document.createElement("div");
+      tempDiv.innerHTML = content;
+
+      // 处理表格内容
+      const tables = tempDiv.getElementsByTagName("table");
+      Array.from(tables).forEach((table) => {
+        // 添加默认表格样式
+        const defaultTableStyle =
+          "border-collapse: collapse; width: 100%; margin: 10px 0;";
+        const defaultCellStyle =
+          "border: 1px solid #dcdfe6; padding: 8px; text-align: left;";
+
+        // 合并现有样式和默认样式
+        const existingStyle = table.getAttribute("style") || "";
+        table.setAttribute("style", `${defaultTableStyle} ${existingStyle}`);
+
+        // 处理所有单元格
+        const cells = table.getElementsByTagName("td");
+        Array.from(cells).forEach((cell) => {
+          const existingCellStyle = cell.getAttribute("style") || "";
+          cell.setAttribute(
+            "style",
+            `${defaultCellStyle} ${existingCellStyle}`
+          );
+
+          if (cell.textContent.includes(searchItem)) {
+            // 保存单元格的类名
+            const cellClass = cell.getAttribute("class") || "";
+
+            // 处理替换内容
+            const processedReplacement = this.parseContent(replacement);
+
+            if (this.containsTableOrImage(processedReplacement)) {
+              cell.innerHTML = processedReplacement;
+            } else {
+              cell.innerHTML = cell.innerHTML.replace(
+                new RegExp(this.escapeRegExp(searchItem), "g"),
+                processedReplacement
+              );
+            }
+
+            // 恢复类名
+            if (cellClass) cell.setAttribute("class", cellClass);
+          }
+        });
+
+        // 处理表头单元格
+        const headerCells = table.getElementsByTagName("th");
+        Array.from(headerCells).forEach((cell) => {
+          const existingHeaderStyle = cell.getAttribute("style") || "";
+          cell.setAttribute(
+            "style",
+            `${defaultCellStyle} background-color: #f5f7fa; font-weight: bold; ${existingHeaderStyle}`
+          );
         });
+      });
+
+      // 处理普通文本内容
+      const textNodes = this.getTextNodes(tempDiv);
+      textNodes.forEach((node) => {
+        if (node.textContent.includes(searchItem)) {
+          const processedReplacement = this.parseContent(replacement);
+          const span = document.createElement("span");
+          span.innerHTML = node.textContent.replace(
+            new RegExp(this.escapeRegExp(searchItem), "g"),
+            processedReplacement
+          );
+          node.parentNode.replaceChild(span, node);
+        }
+      });
+
+      return tempDiv.innerHTML;
+    },
+
+    // 添加样式到 convertTextToHtml 方法
+    convertTextToHtml(text) {
+      if (!text) return "";
+
+      let html = text;
+
+      // 处理特定格式的表格
+      html = html.replace(
+        /\[表格\|style=(.*?)\|class=(.*?)\]([\s\S]*?)(?=\[|$)/g,
+        (match, tableStyle, tableClass, tableContent) => {
+          const rows = tableContent.trim().split("\n");
+          let tableHtml = `<table style="${tableStyle}; border-collapse: collapse;" class="${tableClass}">`;
+
+          rows.forEach((row, index) => {
+            const [label, value] = row.split("|").map((item) => item.trim());
+            if (label) {
+              tableHtml += "<tr>";
+              if (value) {
+                // 如果有值,创建两列的行
+                tableHtml += `
+              <td style="border: 1px solid #000; padding: 8px;">${label}</td>
+              <td style="border: 1px solid #000; padding: 8px;">${value}</td>
+            `;
+              } else {
+                // 如果只有标签,创建单列的行(可能是表头)
+                tableHtml += `
+              <td style="border: 1px solid #000; padding: 8px; font-weight: ${
+                index === 0 ? "bold" : "normal"
+              }">${label}</td>
+            `;
+              }
+              tableHtml += "</tr>";
+            }
+          });
+
+          tableHtml += "</table>";
+          return tableHtml;
+        }
+      );
+
+      // 保持原有的图片和文本处理逻辑不变
+      html = html.replace(
+        /\[图片:(.*?)\|style=(.*?)\|class=(.*?)\]/g,
+        (match, src, style, className) => {
+          return `<img src="${src}" alt="图片" style="${style}" class="${className}">`;
+        }
+      );
+
+      html = html.replace(
+        /\[文本:(.*?)\|style=(.*?)\|class=(.*?)\]/g,
+        (match, content, style, className) => {
+          return `<span style="${style}" class="${className}">${content}</span>`;
+        }
+      );
+
+      return html;
+    },
+
+    /* // 修改替换内容的处理方法
+    async replaceItem(item) {
+      const cleanItem = item.replace(/[\[\]【】]/g, "");
+      try {
+        const params = this.formatRequestParams(cleanItem);
+        const response = await axios.post(
+          `${process.env.VUE_APP_BASE_API}/project-raw-data/batch-content`,
+          params,
+          {
+            headers: {
+              "Content-Type": "application/json",
+            },
+          }
+        );
+
+        if (response.status === 200 && response.data) {
+          const replacementContent =
+            response.data.data.input_item_contents[0]?.content;
+
+          if (replacementContent) {
+            // 处理富文本内容
+            this.TemList.forEach((el, index) => {
+              // 解析表格内容
+              const processedContent = this.processTableContent(
+                el.content,
+                item,
+                replacementContent
+              );
+              this.$set(this.TemList[index], "content", processedContent);
+            });
+
+            this.matchResults = this.matchResults.filter(
+              (match) => match !== item
+            );
+            this.onUpload();
+            this.$message.success("替换成功");
+          } else {
+            this.$message.warning("未获取到替换内容");
+          }
+        }
+      } catch (error) {
+        console.error("替换失败:", error);
+        this.$message.error(error.response?.data?.message || "替换失败");
+      }
     },
+    //批量替换
+    async replaceAll() {
+      this.loadingAll = true;
+      try {
+        const cleanItems = this.matchResults.map((item) =>
+          item.replace(/[\[\]【】]/g, "")
+        );
+        const params = this.formatRequestParams(cleanItems);
+        const response = await axios.post(
+          `${process.env.VUE_APP_BASE_API}/project-raw-data/batch-content`,
+          params,
+          {
+            headers: {
+              "Content-Type": "application/json",
+            },
+          }
+        );
+
+        if (response.status === 200 && response.data) {
+          const replacementContents =
+            response.data.data.input_item_contents?.map((item) => item.content);
+
+          if (replacementContents.length > 0) {
+            this.TemList.forEach((el, index) => {
+              let updatedContent = el.content;
+              this.matchResults.forEach((item, idx) => {
+                console.log(item,idx);
+                const replacementContent = replacementContents[idx];
+                if (replacementContent) {
+                  const regex = new RegExp(this.escapeRegExp(item), "g");
+                  // 使用新添加的 convertTextToHtml 方法
+                  updatedContent = updatedContent.replace(
+                    regex,
+                    this.convertTextToHtml(replacementContent)
+                  );
+                }
+              });
+              this.$set(this.TemList[index], "content", updatedContent);
+            });
+
+            this.onUpload();
+            this.matchResults = [];
+            this.$message.success("批量替换成功");
+          }
+        }
+        return Promise.resolve(); // 确保返回 Promise
+      } catch (error) {
+        console.error("批量替换失败:", error);
+        this.$message.error(error.response?.data?.message || "批量替换失败");
+        return Promise.reject(error);
+      } finally {
+        this.loadingAll = false;
+      }
+    }, */
 
     // 更新 escapeRegExp 方法以支持两种括号类型
     escapeRegExp(string) {

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