From bff1df81388ecbf4e1b5d5e979e0e36713154c0d Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 16 六月 2026 11:17:37 +0800
Subject: [PATCH] pro 1.平遥县盛达铸造厂部署修改

---
 src/views/collaborativeApproval/knowledgeBase/index.vue |  274 ++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 230 insertions(+), 44 deletions(-)

diff --git a/src/views/collaborativeApproval/knowledgeBase/index.vue b/src/views/collaborativeApproval/knowledgeBase/index.vue
index 8d625cf..f50d06b 100644
--- a/src/views/collaborativeApproval/knowledgeBase/index.vue
+++ b/src/views/collaborativeApproval/knowledgeBase/index.vue
@@ -244,6 +244,7 @@
             :on-success="handleUploadSuccess"
             :on-error="handleUploadError"
             :before-upload="beforeUpload"
+            name="files"
             multiple
             :show-file-list="false"
             accept=".txt,.md,.docx,.xlsx,.xls,.pdf"
@@ -259,6 +260,22 @@
           >
             淇濆瓨鏂囦欢鍏宠仈
           </el-button>
+          <el-button
+            v-if="uploadedBlobIds.length > 0"
+            type="text"
+            @click="clearUploadedFiles"
+            style="margin-left: 10px"
+          >
+            娓呯┖寰呬繚瀛樺垪琛�
+          </el-button>
+        </div>
+
+        <!-- 寰呬繚瀛樼殑鏂囦欢鍒楄〃 -->
+        <div v-if="uploadedBlobIds.length > 0" class="uploaded-list">
+          <div class="uploaded-tip">
+            <el-icon style="color: #409eff"><InfoFilled /></el-icon>
+            <span>宸蹭笂浼� {{ uploadedBlobIds.length }} 涓枃浠�,璇风偣鍑�"淇濆瓨鏂囦欢鍏宠仈"鎸夐挳瑙﹀彂鍚戦噺鍖栧鐞�</span>
+          </div>
         </div>
 
         <!-- 鏂囦欢鍒楄〃涓庡悜閲忓寲鐘舵�� -->
@@ -273,6 +290,12 @@
             </template>
           </el-table-column>
           <el-table-column prop="chunkCount" label="鍒囩墖鏁�" width="100" align="center" />
+          <el-table-column label="閿欒淇℃伅" width="200" show-overflow-tooltip>
+            <template #default="{ row }">
+              <span v-if="row.vectorError" style="color: #f56c6c">{{ row.vectorError }}</span>
+              <span v-else style="color: #909399">-</span>
+            </template>
+          </el-table-column>
           <el-table-column prop="createTime" label="涓婁紶鏃堕棿" width="180" />
           <el-table-column label="鎿嶄綔" width="150" align="center">
             <template #default="{ row }">
@@ -326,7 +349,7 @@
         <div class="chat-input">
           <el-input
             v-model="inputQuestion"
-            placeholder="璇疯緭鍏ラ棶棰橈紝鎸夊洖杞﹀彂閫�"
+            placeholder="璇疯緭鍏ラ棶棰�,鎸夊洖杞﹀彂閫�(Ctrl+Enter蹇嵎鍙戦��)"
             @keyup.enter="sendMessage"
             :disabled="chatLoading"
           >
@@ -334,6 +357,9 @@
               <el-button @click="sendMessage" :loading="chatLoading">鍙戦��</el-button>
             </template>
           </el-input>
+          <div class="chat-actions">
+            <el-button type="text" size="small" @click="clearMessages">娓呯┖瀵硅瘽</el-button>
+          </div>
         </div>
       </div>
     </FormDialog>
@@ -341,7 +367,7 @@
 </template>
 
 <script setup>
-import { Search } from "@element-plus/icons-vue";
+import { Search, InfoFilled } from "@element-plus/icons-vue";
 import { onMounted, ref, reactive, toRefs, getCurrentInstance, computed, watch, nextTick } from "vue";
 import { ElMessage, ElMessageBox } from "element-plus";
 import PIMTable from "@/components/PIMTable/PIMTable.vue";
@@ -354,7 +380,7 @@
   getVectorStatus,
   reprocessVector,
   saveKnowledgeBaseFiles,
-  deleteKnowledgeBaseFiles,
+  deleteKnowledgeBaseFile,
   knowledgeChat
 } from "@/api/collaborativeApproval/knowledgeBase.js";
 import useUserStore from '@/store/modules/user';
@@ -412,6 +438,7 @@
   fileList: [],
   uploadedBlobIds: [],
   savingFiles: false,
+  vectorStatusTimer: null, // 鍚戦噺鍖栫姸鎬佽疆璇㈠畾鏃跺櫒
   chatDialogVisible: false,
   messages: [],
   inputQuestion: "",
@@ -436,6 +463,7 @@
   fileList,
   uploadedBlobIds,
   savingFiles,
+  vectorStatusTimer,
   chatDialogVisible,
   messages,
   inputQuestion,
@@ -597,21 +625,31 @@
 
 const getList = () => {
   tableLoading.value = true;
-  listKnowledgeBase({...page.value, ...searchForm.value})
+
+  // 鉁� GET璇锋眰浣跨敤params浼犲弬
+  listKnowledgeBase({
+    current: page.value.current,
+    size: page.value.size,
+    title: searchForm.value.title,
+    type: searchForm.value.type
+  })
   .then(res => {
     tableLoading.value = false;
     page.value.total = res.data.total;
-    // 濡傛灉褰撳墠椤垫暟瓒呰繃鎬婚〉鏁帮紝閲嶇疆鍒扮1椤靛苟閲嶆柊鏌ヨ
+
+    // 濡傛灉褰撳墠椤垫暟瓒呰繃鎬婚〉鏁�,閲嶇疆鍒扮1椤靛苟閲嶆柊鏌ヨ
     const maxPage = Math.ceil(res.data.total / page.value.size) || 1;
     if (page.value.current > maxPage && maxPage > 0) {
       page.value.current = 1;
-      // 閲嶆柊鏌ヨ绗�1椤垫暟鎹�
       return getList();
     }
+
     tableData.value = res.data.records;
-  }).catch(err => {
-    tableLoading.value = false;
   })
+  .catch(err => {
+    tableLoading.value = false;
+    console.error("鏌ヨ鐭ヨ瘑搴撳垪琛ㄥけ璐�:", err);
+  });
 };
 
 // 鍒嗛〉澶勭悊
@@ -786,27 +824,47 @@
 const submitForm = async () => {
   try {
     await formRef.value.validate();
+
+    // 鉁� POST璇锋眰浣跨敤data浼犲弬,鏄庣‘鍙傛暟缁撴瀯
+    const formData = {
+      title: form.value.title,
+      type: form.value.type,
+      scenario: form.value.scenario || "",
+      efficiency: form.value.efficiency || "",
+      problem: form.value.problem,
+      solution: form.value.solution,
+      keyPoints: form.value.keyPoints || "",
+      creator: form.value.creator || "",
+      usageCount: form.value.usageCount || 0
+    };
+
     if (dialogType.value === "add") {
       // 鏂板鐭ヨ瘑
-      addKnowledgeBase({...form.value}).then(res => {
+      addKnowledgeBase(formData).then(res => {
         if(res.code == 200){
           ElMessage.success("娣诲姞鎴愬姛");
           closeKnowledgeDialog();
           getList();
         }
       }).catch(err => {
-        ElMessage.error(err.msg);
-      })
+        console.error("娣诲姞鐭ヨ瘑搴撳け璐�:", err);
+        ElMessage.error(err.msg || "娣诲姞澶辫触");
+      });
     } else {
-      updateKnowledgeBase({...form.value}).then(res => {
+      // 鏇存柊鐭ヨ瘑 - 娣诲姞id鍙傛暟
+      updateKnowledgeBase({
+        id: form.value.id,
+        ...formData
+      }).then(res => {
         if(res.code == 200){
           ElMessage.success("鏇存柊鎴愬姛");
           closeKnowledgeDialog();
           getList();
         }
       }).catch(err => {
-        ElMessage.error(err.msg);
-      })
+        console.error("鏇存柊鐭ヨ瘑搴撳け璐�:", err);
+        ElMessage.error(err.msg || "鏇存柊澶辫触");
+      });
     }
   } catch (error) {
     console.error("琛ㄥ崟楠岃瘉澶辫触:", error);
@@ -820,19 +878,22 @@
     return;
   }
 
-  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎", {
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄�,鏄惁纭鍒犻櫎?", "鍒犻櫎", {
     confirmButtonText: "纭",
     cancelButtonText: "鍙栨秷",
     type: "warning",
   }).then(() => {
-    // console.log(selectedIds.value);
+    // 鉁� DELETE璇锋眰浣跨敤data浼犻�扞D鏁扮粍
     delKnowledgeBase(selectedIds.value).then(res => {
       if(res.code == 200){
         ElMessage.success("鍒犻櫎鎴愬姛");
         selectedIds.value = [];
         getList();
       }
-    })
+    }).catch(err => {
+      console.error("鍒犻櫎鐭ヨ瘑搴撳け璐�:", err);
+      ElMessage.error(err.msg || "鍒犻櫎澶辫触");
+    });
   }).catch(() => {
     // 鐢ㄦ埛鍙栨秷
   });
@@ -872,9 +933,45 @@
   try {
     const res = await getVectorStatus(currentKnowledgeBase.value.id);
     fileList.value = res.data || [];
+
+    // 妫�鏌ユ槸鍚︽湁澶勭悊涓殑鏂囦欢,濡傛灉鏈夊垯鍚姩杞
+    const hasProcessing = res.data.some(item => item.vectorStatus === 1);
+    if (hasProcessing && !vectorStatusTimer.value) {
+      startVectorStatusPolling();
+    } else if (!hasProcessing && vectorStatusTimer.value) {
+      stopVectorStatusPolling();
+    }
   } catch (error) {
     console.error("鍔犺浇鏂囦欢鍒楄〃澶辫触:", error);
     ElMessage.error("鍔犺浇鏂囦欢鍒楄〃澶辫触");
+  }
+};
+
+// 寮�濮嬭疆璇㈠悜閲忓寲鐘舵��
+const startVectorStatusPolling = () => {
+  vectorStatusTimer.value = setInterval(async () => {
+    try {
+      const res = await getVectorStatus(currentKnowledgeBase.value.id);
+      fileList.value = res.data || [];
+
+      // 妫�鏌ユ槸鍚﹁繕鏈夊鐞嗕腑鐨勬枃浠�
+      const hasProcessing = res.data.some(item => item.vectorStatus === 1);
+      if (!hasProcessing) {
+        stopVectorStatusPolling();
+        ElMessage.success("鎵�鏈夋枃浠跺悜閲忓寲澶勭悊瀹屾垚");
+      }
+    } catch (error) {
+      console.error("杞鍚戦噺鍖栫姸鎬佸け璐�:", error);
+      stopVectorStatusPolling();
+    }
+  }, 3000); // 姣�3绉掕疆璇竴娆�
+};
+
+// 鍋滄杞鍚戦噺鍖栫姸鎬�
+const stopVectorStatusPolling = () => {
+  if (vectorStatusTimer.value) {
+    clearInterval(vectorStatusTimer.value);
+    vectorStatusTimer.value = null;
   }
 };
 
@@ -900,9 +997,24 @@
 
 // 涓婁紶鎴愬姛
 const handleUploadSuccess = (response, file) => {
+  console.log("涓婁紶鍝嶅簲:", response);  // 璋冭瘯鏃ュ織
+
   if (response.code === 200) {
-    uploadedBlobIds.value.push(response.data.id);
-    ElMessage.success(`鏂囦欢 ${file.name} 涓婁紶鎴愬姛`);
+    // 鉁� 鍚庣杩斿洖鐨勬槸 List<StorageBlobVO>,鎵�浠ata鏄暟缁�
+    if (Array.isArray(response.data) && response.data.length > 0) {
+      // 鍙栨暟缁勭涓�涓厓绱犵殑id
+      const blobId = response.data[0].id;
+      if (blobId) {
+        uploadedBlobIds.value.push(blobId);
+        ElMessage.success(`鏂囦欢 ${file.name} 涓婁紶鎴愬姛`);
+      } else {
+        console.error("涓婁紶鍝嶅簲涓湭鎵惧埌id:", response.data[0]);
+        ElMessage.error("涓婁紶澶辫触: 鏈幏鍙栧埌鏂囦欢ID");
+      }
+    } else {
+      console.error("涓婁紶鍝嶅簲鏍煎紡閿欒:", response);
+      ElMessage.error("涓婁紶澶辫触: 鍝嶅簲鏍煎紡閿欒");
+    }
   } else {
     ElMessage.error(response.msg || "涓婁紶澶辫触");
   }
@@ -915,22 +1027,30 @@
 
 // 淇濆瓨鏂囦欢鍏宠仈
 const saveFiles = async () => {
+  // 鍙傛暟鏍¢獙
+  if (!currentKnowledgeBase.value?.id) {
+    ElMessage.error("鐭ヨ瘑搴撲俊鎭紓甯�");
+    return;
+  }
+
   if (uploadedBlobIds.value.length === 0) {
     ElMessage.warning("璇峰厛涓婁紶鏂囦欢");
     return;
   }
 
   savingFiles.value = true;
+
   try {
+    // 鉁� POST璇锋眰浣跨敤data浼犲弬,鏄庣‘鍙傛暟缁撴瀯
     await saveKnowledgeBaseFiles({
-      knowledgeBaseId: currentKnowledgeBase.value.id,
-      storageBlobIds: uploadedBlobIds.value
+      knowledgeBaseId: currentKnowledgeBase.value.id,  // 鐭ヨ瘑搴揑D
+      storageBlobIds: uploadedBlobIds.value             // 鏂囦欢blob ID鏁扮粍
     });
 
-    ElMessage.success("鏂囦欢鍏宠仈淇濆瓨鎴愬姛锛屾鍦ㄥ悗鍙板鐞嗗悜閲忓寲");
+    ElMessage.success("鏂囦欢鍏宠仈淇濆瓨鎴愬姛,姝e湪鍚庡彴澶勭悊鍚戦噺鍖�");
     uploadedBlobIds.value = [];
 
-    // 寤惰繜鍒锋柊鏂囦欢鍒楄〃锛岀粰鍚庡彴澶勭悊鏃堕棿
+    // 寤惰繜鍒锋柊鏂囦欢鍒楄〃,缁欏悗鍙板鐞嗘椂闂�
     setTimeout(() => {
       loadFileList();
     }, 1000);
@@ -957,11 +1077,17 @@
   }
 };
 
+// 娓呯┖寰呬繚瀛樼殑鏂囦欢鍒楄〃
+const clearUploadedFiles = () => {
+  uploadedBlobIds.value = [];
+  ElMessage.success("宸叉竻绌哄緟淇濆瓨鏂囦欢鍒楄〃");
+};
+
 // 鍒犻櫎鏂囦欢
 const deleteFile = async (row) => {
   try {
     await ElMessageBox.confirm(
-      "纭畾瑕佸垹闄よ鏂囦欢鍚楋紵鍒犻櫎鍚庡皢鏃犳硶鎭㈠鍚戦噺鏁版嵁",
+      "纭畾瑕佸垹闄よ鏂囦欢鍚�?鍒犻櫎鍚庡皢鏃犳硶鎭㈠鍚戦噺鏁版嵁",
       "鍒犻櫎纭",
       {
         confirmButtonText: "纭畾",
@@ -970,7 +1096,8 @@
       }
     );
 
-    await deleteKnowledgeBaseFiles([row.id]);
+    // 鉁� DELETE璇锋眰浣跨敤data浼犻�扞D鏁扮粍
+    await deleteKnowledgeBaseFile([row.id]);  // 娉ㄦ剰: row.id鏄悜閲忚褰旾D,涓嶆槸storageBlobId
     ElMessage.success("鍒犻櫎鎴愬姛");
     loadFileList();
   } catch (error) {
@@ -1009,24 +1136,44 @@
   currentKnowledgeBase.value = null;
   fileList.value = [];
   uploadedBlobIds.value = [];
-  getList(); // 鍒锋柊涓诲垪琛紝鏇存柊鏂囦欢鏁伴噺
+  stopVectorStatusPolling(); // 鍋滄杞
+  getList(); // 鍒锋柊涓诲垪琛�,鏇存柊鏂囦欢鏁伴噺
 };
 
 // ============ 鐭ヨ瘑搴撻棶绛旂浉鍏� ============
+
+// 鐢熸垚UUID鐨刦allback鏂规
+const generateUUID = () => {
+  if (typeof crypto !== 'undefined' && crypto.randomUUID) {
+    return crypto.randomUUID();
+  }
+  // fallback: 鍏煎涓嶆敮鎸� crypto.randomUUID 鐨勭幆澧�
+  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+    const r = Math.random() * 16 | 0;
+    const v = c === 'x' ? r : (r & 0x3 | 0x8);
+    return v.toString(16);
+  });
+};
 
 // 鎵撳紑闂瓟寮圭獥
 const openChatDialog = (row) => {
   currentKnowledgeBase.value = row;
   chatDialogVisible.value = true;
-  memoryId.value = crypto.randomUUID();
+  memoryId.value = generateUUID();
   messages.value = [];
   inputQuestion.value = "";
 };
 
 // 鍙戦�佹秷鎭�
 const sendMessage = async () => {
+  // 鍙傛暟鏍¢獙
   if (!inputQuestion.value.trim()) {
     ElMessage.warning("璇疯緭鍏ラ棶棰�");
+    return;
+  }
+
+  if (!currentKnowledgeBase.value?.id) {
+    ElMessage.error("鐭ヨ瘑搴撲俊鎭紓甯�");
     return;
   }
 
@@ -1046,25 +1193,19 @@
   scrollToBottom();
 
   try {
-    // 娴佸紡璇锋眰
-    const response = await fetch('/api/ai/knowledge/chat', {
-      method: 'POST',
-      headers: {
-        'Content-Type': 'application/json',
-        'Authorization': 'Bearer ' + getToken()
-      },
-      body: JSON.stringify({
-        knowledgeBaseId: currentKnowledgeBase.value.id,
-        memoryId: memoryId.value,
-        question: question
-      })
+    // 鉁� 娴佸紡璇锋眰浣跨敤Fetch API
+    const response = await knowledgeChat({
+      knowledgeBaseId: currentKnowledgeBase.value.id,  // 鐭ヨ瘑搴揑D
+      memoryId: memoryId.value,                         // 浼氳瘽ID
+      question: question                                // 鐢ㄦ埛闂
     });
 
     if (!response.ok) {
-      throw new Error('璇锋眰澶辫触');
+      const errorText = await response.text();
+      throw new Error(errorText || '璇锋眰澶辫触');
     }
 
-    // 澶勭悊SSE娴佸紡鍝嶅簲
+    // 鉁� 鍚庣杩斿洖 text/stream;charset=utf-8
     const reader = response.body.getReader();
     const decoder = new TextDecoder();
     let aiContent = '';
@@ -1075,7 +1216,7 @@
       const { done, value } = await reader.read();
       if (done) break;
 
-      const text = decoder.decode(value);
+      const text = decoder.decode(value, { stream: true });  // 鉁� 娣诲姞stream閫夐」
       aiContent += text;
       messages.value[messages.value.length - 1].content = aiContent;
 
@@ -1083,16 +1224,40 @@
       await nextTick();
       scrollToBottom();
     }
+
+    // 濡傛灉AI杩斿洖绌哄唴瀹�,鏄剧ず鎻愮ず
+    if (!aiContent.trim()) {
+      messages.value[messages.value.length - 1].content = '鎶辨瓑,鐭ヨ瘑搴撲腑鏈壘鍒扮浉鍏冲唴瀹�,璇峰皾璇曞叾浠栭棶棰樸��';
+    }
   } catch (error) {
     console.error("闂瓟璇锋眰澶辫触:", error);
-    ElMessage.error("闂瓟璇锋眰澶辫触锛岃绋嶅悗閲嶈瘯");
+    ElMessage.error("闂瓟璇锋眰澶辫触,璇风◢鍚庨噸璇�");
     messages.value.push({
       role: 'assistant',
-      content: '鎶辨瓑锛屽彂鐢熶簡閿欒锛岃绋嶅悗閲嶈瘯'
+      content: '鎶辨瓑,鍙戠敓浜嗛敊璇�,璇风◢鍚庨噸璇�'
     });
   } finally {
     chatLoading.value = false;
   }
+};
+
+// 娓呯┖瀵硅瘽
+const clearMessages = () => {
+  ElMessageBox.confirm(
+    "纭畾瑕佹竻绌烘墍鏈夊璇濊褰曞悧?",
+    "娓呯┖纭",
+    {
+      confirmButtonText: "纭畾",
+      cancelButtonText: "鍙栨秷",
+      type: "warning"
+    }
+  ).then(() => {
+    messages.value = [];
+    memoryId.value = generateUUID(); // 閲嶆柊鐢熸垚浼氳瘽ID
+    ElMessage.success("瀵硅瘽宸叉竻绌�");
+  }).catch(() => {
+    // 鐢ㄦ埛鍙栨秷
+  });
 };
 
 // 婊氬姩鍒板簳閮�
@@ -1195,6 +1360,22 @@
   align-items: center;
 }
 
+.uploaded-list {
+  margin-top: 16px;
+  padding: 12px;
+  background: #f0f9ff;
+  border-radius: 6px;
+  border: 1px solid #b3d8ff;
+}
+
+.uploaded-tip {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  color: #409eff;
+  font-size: 14px;
+}
+
 /* 鐭ヨ瘑搴撻棶绛旀牱寮� */
 .knowledge-chat {
   display: flex;
@@ -1272,4 +1453,9 @@
   margin-top: auto;
 }
 
+.chat-actions {
+  margin-top: 8px;
+  text-align: right;
+}
+
 </style>

--
Gitblit v1.9.3