From 74f94cbb16aae6a16da39f5f38b3ac7daf0b4bbe Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 10 六月 2026 09:40:49 +0800
Subject: [PATCH] feat(knowledgeBase): 添加知识库问答UUID生成兼容性支持

---
 src/views/collaborativeApproval/knowledgeBase/index.vue | 1133 +++++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 873 insertions(+), 260 deletions(-)

diff --git a/src/views/collaborativeApproval/knowledgeBase/index.vue b/src/views/collaborativeApproval/knowledgeBase/index.vue
index 279738e..f50d06b 100644
--- a/src/views/collaborativeApproval/knowledgeBase/index.vue
+++ b/src/views/collaborativeApproval/knowledgeBase/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div class="app-container">
-    <div class="search_form">
+    <div class="search_form" style="margin-bottom: 20px;">
       <div>
         <span class="search_title">鐭ヨ瘑鏍囬锛�</span>
         <el-input
@@ -13,22 +13,24 @@
         />
         <span class="search_title ml10">鐭ヨ瘑绫诲瀷锛�</span>
         <el-select v-model="searchForm.type" clearable @change="handleQuery" style="width: 240px">
-          <el-option label="鍚堝悓鐗规壒" :value="'contract'" />
-          <el-option label="瀹℃壒妗堜緥" :value="'approval'" />
-          <el-option label="瑙e喅鏂规" :value="'solution'" />
-          <el-option label="缁忛獙鎬荤粨" :value="'experience'" />
-          <el-option label="鎿嶄綔鎸囧崡" :value="'guide'" />
+          <el-option
+              v-for="item in knowledgeTypeOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+          />
         </el-select>
         <el-button type="primary" @click="handleQuery" style="margin-left: 10px">
           鎼滅储
         </el-button>
       </div>
       <div>
+        <el-button @click="handleExport" style="margin-right: 10px">瀵煎嚭</el-button>
         <el-button type="primary" @click="openForm('add')">鏂板鐭ヨ瘑</el-button>
         <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
       </div>
     </div>
-    
+
     <div class="table_list">
       <PIMTable
         rowKey="id"
@@ -44,11 +46,13 @@
     </div>
 
     <!-- 鏂板/缂栬緫鐭ヨ瘑寮圭獥 -->
-    <el-dialog
+    <FormDialog
       v-model="dialogVisible"
       :title="dialogTitle"
-      width="800px"
-      :close-on-click-modal="false"
+      :width="'800px'"
+      @close="closeKnowledgeDialog"
+      @confirm="submitForm"
+      @cancel="closeKnowledgeDialog"
     >
       <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
         <el-row :gutter="20">
@@ -60,11 +64,12 @@
           <el-col :span="12">
             <el-form-item label="鐭ヨ瘑绫诲瀷" prop="type">
               <el-select v-model="form.type" placeholder="璇烽�夋嫨鐭ヨ瘑绫诲瀷" style="width: 100%">
-                <el-option label="鍚堝悓鐗规壒" value="contract" />
-                <el-option label="瀹℃壒妗堜緥" value="approval" />
-                <el-option label="瑙e喅鏂规" value="solution" />
-                <el-option label="缁忛獙鎬荤粨" value="experience" />
-                <el-option label="鎿嶄綔鎸囧崡" value="guide" />
+                <el-option
+                    v-for="item in knowledgeTypeOptions"
+                    :key="item.value"
+                    :label="item.label"
+                    :value="item.value"
+                />
               </el-select>
             </el-form-item>
           </el-col>
@@ -112,7 +117,14 @@
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="鍒涘缓浜�" prop="creator">
-              <el-input v-model="form.creator" placeholder="璇疯緭鍏ュ垱寤轰汉" />
+              <el-select v-model="form.creator" placeholder="璇烽�夋嫨鍒涘缓浜�" style="width: 100%" filterable>
+                <el-option
+                  v-for="user in userList"
+                  :key="user.userId"
+                  :label="user.nickName"
+                  :value="user.nickName"
+                />
+              </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -122,20 +134,16 @@
           </el-col>
         </el-row>
       </el-form>
-      <template #footer>
-        <span class="dialog-footer">
-          <el-button @click="dialogVisible = false">鍙栨秷</el-button>
-          <el-button type="primary" @click="submitForm">纭畾</el-button>
-        </span>
-      </template>
-    </el-dialog>
+    </FormDialog>
 
     <!-- 鏌ョ湅鐭ヨ瘑璇︽儏寮圭獥 -->
-    <el-dialog
+    <FormDialog
       v-model="viewDialogVisible"
       title="鐭ヨ瘑璇︽儏"
-      width="900px"
-      :close-on-click-modal="false"
+      :width="'900px'"
+      @close="closeViewDialog"
+      @confirm="handleViewDialogConfirm"
+      @cancel="closeViewDialog"
     >
       <div class="knowledge-detail">
         <el-descriptions :column="2" border>
@@ -180,7 +188,7 @@
           <h4>鍏抽敭瑕佺偣</h4>
           <div class="key-points">
             <el-tag
-              v-for="(point, index) in currentKnowledge.keyPoints.split(',')"
+              v-for="(point, index) in currentKnowledge.keyPoints?.split(',') || []"
               :key="index"
               type="success"
               style="margin-right: 8px; margin-bottom: 8px;"
@@ -216,23 +224,168 @@
           </div>
         </div>
       </div>
+    </FormDialog>
 
-      <template #footer>
-        <span class="dialog-footer">
-          <el-button @click="viewDialogVisible = false">鍏抽棴</el-button>
-          <el-button type="primary" @click="copyKnowledge">澶嶅埗鐭ヨ瘑</el-button>
-          <el-button type="success" @click="markAsFavorite">鏀惰棌</el-button>
-        </span>
-      </template>
-    </el-dialog>
+    <!-- 鏂囦欢绠$悊寮圭獥 -->
+    <FormDialog
+      v-model="filesDialogVisible"
+      title="鏂囦欢绠$悊"
+      :width="'900px'"
+      @close="closeFilesDialog"
+      @confirm="closeFilesDialog"
+      @cancel="closeFilesDialog"
+    >
+      <div class="file-manager">
+        <!-- 鏂囦欢涓婁紶 -->
+        <div class="upload-section">
+          <el-upload
+            :action="uploadUrl"
+            :headers="uploadHeaders"
+            :on-success="handleUploadSuccess"
+            :on-error="handleUploadError"
+            :before-upload="beforeUpload"
+            name="files"
+            multiple
+            :show-file-list="false"
+            accept=".txt,.md,.docx,.xlsx,.xls,.pdf"
+          >
+            <el-button type="primary">涓婁紶鏂囦欢</el-button>
+          </el-upload>
+          <el-button
+            type="success"
+            @click="saveFiles"
+            :disabled="uploadedBlobIds.length === 0"
+            :loading="savingFiles"
+            style="margin-left: 10px"
+          >
+            淇濆瓨鏂囦欢鍏宠仈
+          </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>
+
+        <!-- 鏂囦欢鍒楄〃涓庡悜閲忓寲鐘舵�� -->
+        <el-table :data="fileList" style="margin-top: 20px" border>
+          <el-table-column prop="fileName" label="鏂囦欢鍚�" show-overflow-tooltip />
+          <el-table-column prop="fileType" label="鏂囦欢绫诲瀷" width="100" />
+          <el-table-column label="鍚戦噺鍖栫姸鎬�" width="120">
+            <template #default="{ row }">
+              <el-tag :type="getStatusType(row.vectorStatus)">
+                {{ getStatusText(row.vectorStatus) }}
+              </el-tag>
+            </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 }">
+              <el-button
+                v-if="row.vectorStatus === 3"
+                type="text"
+                @click="reprocessFile(row)"
+              >
+                閲嶆柊澶勭悊
+              </el-button>
+              <el-button type="text" @click="deleteFile(row)" style="color: #f56c6c">
+                鍒犻櫎
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </FormDialog>
+
+    <!-- 鐭ヨ瘑搴撻棶绛斿脊绐� -->
+    <FormDialog
+      v-model="chatDialogVisible"
+      title="鐭ヨ瘑搴撻棶绛�"
+      :width="'800px'"
+      @close="closeChatDialog"
+      @confirm="closeChatDialog"
+      @cancel="closeChatDialog"
+    >
+      <div class="knowledge-chat">
+        <div class="chat-header">
+          <el-tag type="success">褰撳墠鐭ヨ瘑搴�: {{ currentKnowledgeBase?.title }}</el-tag>
+        </div>
+
+        <!-- 瀵硅瘽鍖哄煙 -->
+        <div class="chat-messages" ref="chatMessagesRef">
+          <div
+            v-for="(msg, index) in messages"
+            :key="index"
+            :class="['message', msg.role]"
+          >
+            <div class="message-role">{{ msg.role === 'user' ? '鎴�' : 'AI鍔╂墜' }}</div>
+            <div class="message-content">{{ msg.content }}</div>
+          </div>
+          <div v-if="chatLoading" class="message assistant">
+            <div class="message-role">AI鍔╂墜</div>
+            <div class="message-content typing">姝e湪鎬濊�冧腑...</div>
+          </div>
+        </div>
+
+        <!-- 杈撳叆妗� -->
+        <div class="chat-input">
+          <el-input
+            v-model="inputQuestion"
+            placeholder="璇疯緭鍏ラ棶棰�,鎸夊洖杞﹀彂閫�(Ctrl+Enter蹇嵎鍙戦��)"
+            @keyup.enter="sendMessage"
+            :disabled="chatLoading"
+          >
+            <template #append>
+              <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>
   </div>
 </template>
 
 <script setup>
-import { Search } from "@element-plus/icons-vue";
-import { onMounted, ref, reactive, toRefs } from "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";
+import FormDialog from '@/components/Dialog/FormDialog.vue';
+import {
+  listKnowledgeBase,
+  delKnowledgeBase,
+  addKnowledgeBase,
+  updateKnowledgeBase,
+  getVectorStatus,
+  reprocessVector,
+  saveKnowledgeBaseFiles,
+  deleteKnowledgeBaseFile,
+  knowledgeChat
+} from "@/api/collaborativeApproval/knowledgeBase.js";
+import useUserStore from '@/store/modules/user';
+import { userListNoPageByTenantId } from '@/api/system/user.js';
+import { getToken } from "@/utils/auth";
 
 // 琛ㄥ崟楠岃瘉瑙勫垯
 const rules = {
@@ -259,7 +412,7 @@
   tableLoading: false,
   page: {
     current: 1,
-    size: 100,
+    size: 20,
     total: 0,
   },
   tableData: [],
@@ -268,7 +421,7 @@
     title: "",
     type: "",
     scenario: "",
-    efficiency: "medium",
+    efficiency: "",
     problem: "",
     solution: "",
     keyPoints: "",
@@ -279,25 +432,56 @@
   dialogTitle: "",
   dialogType: "add",
   viewDialogVisible: false,
-  currentKnowledge: {}
+  currentKnowledge: {},
+  filesDialogVisible: false,
+  currentKnowledgeBase: null,
+  fileList: [],
+  uploadedBlobIds: [],
+  savingFiles: false,
+  vectorStatusTimer: null, // 鍚戦噺鍖栫姸鎬佽疆璇㈠畾鏃跺櫒
+  chatDialogVisible: false,
+  messages: [],
+  inputQuestion: "",
+  chatLoading: false,
+  memoryId: ""
 });
 
-const { 
-  searchForm, 
-  tableLoading, 
-  page, 
-  tableData, 
+const {
+  searchForm,
+  tableLoading,
+  page,
+  tableData,
   selectedIds,
   form,
   dialogVisible,
   dialogTitle,
   dialogType,
   viewDialogVisible,
-  currentKnowledge
+  currentKnowledge,
+  filesDialogVisible,
+  currentKnowledgeBase,
+  fileList,
+  uploadedBlobIds,
+  savingFiles,
+  vectorStatusTimer,
+  chatDialogVisible,
+  messages,
+  inputQuestion,
+  chatLoading,
+  memoryId
 } = toRefs(data);
 
 // 琛ㄥ崟寮曠敤
 const formRef = ref();
+// 鐢ㄦ埛鐩稿叧
+const userStore = useUserStore();
+const userList = ref([]);
+// 鑱婂ぉ娑堟伅瀹瑰櫒寮曠敤
+const chatMessagesRef = ref();
+
+// 鏂囦欢涓婁紶鐩稿叧
+const uploadUrl = import.meta.env.VITE_APP_BASE_API + "/common/upload";
+const uploadHeaders = { Authorization: "Bearer " + getToken() };
 
 // 琛ㄦ牸鍒楅厤缃�
 const tableColumn = ref([
@@ -311,24 +495,10 @@
     prop: "type",
     dataType: "tag",
     formatData: (params) => {
-      const typeMap = {
-        contract: "鍚堝悓鐗规壒",
-        approval: "瀹℃壒妗堜緥",
-        solution: "瑙e喅鏂规",
-        experience: "缁忛獙鎬荤粨",
-        guide: "鎿嶄綔鎸囧崡"
-      };
-      return typeMap[params] || params;
+      return getKnowledgeTypeLabel(params);
     },
     formatType: (params) => {
-      const typeMap = {
-        contract: "success",
-        approval: "warning",
-        solution: "primary",
-        experience: "info",
-        guide: "danger"
-      };
-      return typeMap[params] || "info";
+      return getKnowledgeTypeTagType(params);
     }
   },
   {
@@ -357,6 +527,18 @@
       };
       return typeMap[params] || "info";
     }
+  },
+  {
+    label: "鏂囦欢鏁伴噺",
+    prop: "fileCount",
+    width: 100,
+    align: "center"
+  },
+  {
+    label: "鍒囩墖鏁伴噺",
+    prop: "totalChunkCount",
+    width: 100,
+    align: "center"
   },
   {
     label: "浣跨敤娆℃暟",
@@ -389,7 +571,21 @@
         }
       },
       {
-        name: "鏌ョ湅",
+        name: "鏂囦欢",
+        type: "text",
+        clickFun: (row) => {
+          openFilesDialog(row);
+        }
+      },
+      {
+        name: "闂瓟",
+        type: "text",
+        clickFun: (row) => {
+          openChatDialog(row);
+        }
+      },
+      {
+        name: "璇︽儏",
         type: "text",
         clickFun: (row) => {
           viewKnowledge(row);
@@ -399,110 +595,14 @@
   }
 ]);
 
-// 妯℃嫙鏁版嵁
-let mockData = [
-  {
-    id: "1",
-    title: "鐗规畩鍚堝悓瀹℃壒娴佺▼浼樺寲鏂规",
-    type: "contract",
-    scenario: "澶ч鍚堝悓蹇�熷鎵�",
-    efficiency: "high",
-    problem: "澶ч鍚堝悓瀹℃壒娴佺▼澶嶆潅锛屽鎵规椂闂撮暱锛屽奖鍝嶄笟鍔¤繘灞�",
-    solution: "寤虹珛缁胯壊閫氶亾锛屽绗﹀悎鏉′欢鐨勫悎鍚岄噰鐢ㄧ畝鍖栧鎵规祦绋嬶紝鐢遍儴闂ㄨ礋璐d汉鐩存帴瀹℃壒锛屽钩鍧囧鎵规椂闂翠粠3澶╃缉鐭嚦1澶�",
-    keyPoints: "缁胯壊閫氶亾鏉′欢,绠�鍖栨祦绋�,瀹℃壒鏉冮檺,鏃堕棿鎺у埗",
-    creator: "闄堝織寮�",
-    usageCount: 15,
-    createTime: "2025-01-15 10:30:00"
-  },
-  {
-    id: "2",
-    title: "璺ㄩ儴闂ㄥ崗浣滃鎵圭粡楠屾�荤粨",
-    type: "experience",
-    scenario: "澶氶儴闂ㄥ崗浣滈」鐩�",
-    efficiency: "medium",
-    problem: "璺ㄩ儴闂ㄩ」鐩鎵规椂锛屽悇閮ㄩ棬鎰忚涓嶇粺涓�锛屽鎵硅繘搴︾紦鎱�",
-    solution: "寤虹珛椤圭洰鍗忚皟鏈哄埗锛屾寚瀹氶」鐩礋璐d汉锛屽畾鏈熷彫寮�鍗忚皟浼氳锛岀粺涓�鍚勬柟鎰忚鍚庡啀杩涜瀹℃壒",
-    keyPoints: "椤圭洰鍗忚皟,瀹氭湡浼氳,缁熶竴鎰忚,璐熻矗浜哄埗搴�",
-    creator: "鏉庝富绠�",
-    usageCount: 8,
-    createTime: "2025-01-14 15:20:00"
-  },
-  {
-    id: "3",
-    title: "绱ф�ラ噰璐鎵规搷浣滄寚鍗�",
-    type: "guide",
-    scenario: "绱ф�ラ噰璐渶姹�",
-    efficiency: "high",
-    problem: "绱ф�ラ噰璐椂瀹℃壒娴佺▼澶嶆潅锛屾棤娉曟弧瓒崇揣鎬ラ渶姹�",
-    solution: "鍒跺畾绱ф�ラ噰璐鎵规爣鍑嗭紝鏄庣‘绱ф�ョ▼搴﹀垎绾э紝涓嶅悓绾у埆閲囩敤涓嶅悓瀹℃壒娴佺▼锛岀‘淇濈揣鎬ラ渶姹傚緱鍒板強鏃跺鐞�",
-    keyPoints: "绱ф�ュ垎绾�,鏍囧噯鍒跺畾,娴佺▼绠�鍖�,鍙婃椂澶勭悊",
-    creator: "鐜嬩笓鍛�",
-    usageCount: 12,
-    createTime: "2025-01-13 09:15:00"
+// 鐩戝惉瀵硅瘽妗嗘墦寮�锛岃幏鍙栫敤鎴峰垪琛�
+watch(dialogVisible, (newVal) => {
+  if (newVal) {
+    userListNoPageByTenantId().then((res) => {
+      userList.value = res.data || [];
+    });
   }
-];
-
-// 鐭ヨ瘑鏍囬妯℃澘
-const titleTemplates = [
-  "{type}瀹℃壒娴佺▼浼樺寲鏂规",
-  "{scenario}澶勭悊缁忛獙鎬荤粨",
-  "{type}鐗规畩鎯呭喌澶勭悊鎸囧崡",
-  "{scenario}蹇�熷鎵规柟妗�",
-  "{type}鏍囧噯鍖栨搷浣滄祦绋�",
-  "{scenario}闂瑙e喅鏂规",
-  "{type}鏈�浣冲疄璺垫�荤粨",
-  "{scenario}鏁堢巼鎻愬崌鏂规"
-];
-
-// 鐭ヨ瘑绫诲瀷閰嶇疆
-const knowledgeTypes = [
-  { type: "contract", label: "鍚堝悓鐗规壒", efficiency: "high" },
-  { type: "approval", label: "瀹℃壒妗堜緥", efficiency: "medium" },
-  { type: "solution", label: "瑙e喅鏂规", efficiency: "high" },
-  { type: "experience", label: "缁忛獙鎬荤粨", efficiency: "medium" },
-  { type: "guide", label: "鎿嶄綔鎸囧崡", efficiency: "low" }
-];
-
-// 鍦烘櫙鍒楄〃
-const scenarios = ["澶ч鍚堝悓瀹℃壒", "璺ㄩ儴闂ㄥ崗浣�", "绱ф�ラ噰璐�", "鐗规畩鐢宠", "娴佺▼浼樺寲", "闂澶勭悊", "鏍囧噯鍖栧缓璁�", "鏁堢巼鎻愬崌"];
-
-// 鑷姩鐢熸垚鏂版暟鎹�
-const generateNewData = () => {
-  const newId = (mockData.length + 1).toString();
-  const now = new Date();
-  const randomType = knowledgeTypes[Math.floor(Math.random() * knowledgeTypes.length)];
-  const randomScenario = scenarios[Math.floor(Math.random() * scenarios.length)];
-  
-  // 鐢熸垚闅忔満鏍囬
-  let title = titleTemplates[Math.floor(Math.random() * titleTemplates.length)];
-  title = title
-    .replace('{type}', randomType.label)
-    .replace('{scenario}', randomScenario);
-  
-  const newKnowledge = {
-    id: newId,
-    title: title,
-    type: randomType.type,
-    scenario: randomScenario,
-    efficiency: randomType.efficiency,
-    problem: `鍦�${randomScenario}杩囩▼涓亣鍒扮殑闂鎻忚堪...`,
-    solution: `閽堝${randomScenario}鐨勮В鍐虫柟妗堝拰鎿嶄綔姝ラ...`,
-    keyPoints: "鍏抽敭瑕佺偣1,鍏抽敭瑕佺偣2,鍏抽敭瑕佺偣3,鍏抽敭瑕佺偣4",
-          creator: ["闄堝織寮�", "鍒橀泤濠�", "鐜嬪缓鍥�", "璧典附鍗�"][Math.floor(Math.random() * 4)],
-    usageCount: Math.floor(Math.random() * 20) + 1,
-    createTime: now.toLocaleString()
-  };
-  
-  // 娣诲姞鍒版暟鎹紑澶�
-  mockData.unshift(newKnowledge);
-  
-  // 淇濇寔鏁版嵁閲忓湪鍚堢悊鑼冨洿鍐咃紙鏈�澶氫繚鐣�30鏉★級
-  if (mockData.length > 30) {
-    mockData = mockData.slice(0, 30);
-  }
-  
-  console.log(`[${new Date().toLocaleString()}] 鑷姩鐢熸垚鏂扮煡璇�: ${title}`);
-};
+});
 
 // 鐢熷懡鍛ㄦ湡
 onMounted(() => {
@@ -513,7 +613,6 @@
 // 寮�濮嬭嚜鍔ㄥ埛鏂�
 const startAutoRefresh = () => {
   setInterval(() => {
-    generateNewData();
     getList();
   }, 600000); // 10鍒嗛挓鍒锋柊涓�娆� (10 * 60 * 1000 = 600000ms)
 };
@@ -526,31 +625,43 @@
 
 const getList = () => {
   tableLoading.value = true;
-  
-  setTimeout(() => {
-    let filteredData = [...mockData];
-    
-    if (searchForm.value.title) {
-      filteredData = filteredData.filter(item => 
-        item.title.toLowerCase().includes(searchForm.value.title.toLowerCase())
-      );
-    }
-    
-    if (searchForm.value.type) {
-      filteredData = filteredData.filter(item => item.type === searchForm.value.type);
-    }
-    
-    tableData.value = filteredData;
-    page.value.total = filteredData.length;
+
+  // 鉁� GET璇锋眰浣跨敤params浼犲弬
+  listKnowledgeBase({
+    current: page.value.current,
+    size: page.value.size,
+    title: searchForm.value.title,
+    type: searchForm.value.type
+  })
+  .then(res => {
     tableLoading.value = false;
-  }, 500);
+    page.value.total = res.data.total;
+
+    // 濡傛灉褰撳墠椤垫暟瓒呰繃鎬婚〉鏁�,閲嶇疆鍒扮1椤靛苟閲嶆柊鏌ヨ
+    const maxPage = Math.ceil(res.data.total / page.value.size) || 1;
+    if (page.value.current > maxPage && maxPage > 0) {
+      page.value.current = 1;
+      return getList();
+    }
+
+    tableData.value = res.data.records;
+  })
+  .catch(err => {
+    tableLoading.value = false;
+    console.error("鏌ヨ鐭ヨ瘑搴撳垪琛ㄥけ璐�:", err);
+  });
 };
 
 // 鍒嗛〉澶勭悊
 const pagination = (obj) => {
+  const oldSize = page.value.size;
   page.value.current = obj.page;
   page.value.size = obj.limit;
-  handleQuery();
+  // 濡傛灉 size 鏀瑰彉浜嗭紝閲嶇疆鍒扮1椤碉紝閬垮厤褰撳墠椤佃秴鍑鸿寖鍥�
+  if (oldSize !== obj.limit) {
+    page.value.current = 1;
+  }
+  getList();
 };
 
 // 閫夋嫨鍙樺寲澶勭悊
@@ -563,21 +674,22 @@
   dialogType.value = type;
   if (type === "add") {
     dialogTitle.value = "鏂板鐭ヨ瘑";
-    // 閲嶇疆琛ㄥ崟
+    // 閲嶇疆琛ㄥ崟锛岄粯璁ゅ垱寤轰汉涓哄綋鍓嶇敤鎴�
     Object.assign(form.value, {
       title: "",
       type: "",
       scenario: "",
-      efficiency: "medium",
+      efficiency: "",
       problem: "",
       solution: "",
       keyPoints: "",
-      creator: "",
+      creator: userStore.nickName || "",
       usageCount: 0
     });
   } else if (type === "edit" && row) {
     dialogTitle.value = "缂栬緫鐭ヨ瘑";
     Object.assign(form.value, {
+      id: row.id,
       title: row.title,
       type: row.type,
       scenario: row.scenario,
@@ -612,14 +724,7 @@
 
 // 鑾峰彇绫诲瀷鏍囩鏂囨湰
 const getTypeLabel = (type) => {
-  const typeMap = {
-    contract: "鍚堝悓鐗规壒",
-    approval: "瀹℃壒妗堜緥",
-    solution: "瑙e喅鏂规",
-    experience: "缁忛獙鎬荤粨",
-    guide: "鎿嶄綔鎸囧崡"
-  };
-  return typeMap[type] || type;
+  return getKnowledgeTypeLabel(type);
 };
 
 // 鑾峰彇鏁堢巼鏍囩绫诲瀷
@@ -665,15 +770,15 @@
 // 澶嶅埗鐭ヨ瘑
 const copyKnowledge = () => {
   const knowledgeText = `
-鐭ヨ瘑鏍囬锛�${currentKnowledge.value.title}
-鐭ヨ瘑绫诲瀷锛�${getTypeLabel(currentKnowledge.value.type)}
-閫傜敤鍦烘櫙锛�${currentKnowledge.value.scenario}
-闂鎻忚堪锛�${currentKnowledge.value.problem}
-瑙e喅鏂规锛�${currentKnowledge.value.solution}
-鍏抽敭瑕佺偣锛�${currentKnowledge.value.keyPoints}
-鍒涘缓浜猴細${currentKnowledge.value.creator}
+    鐭ヨ瘑鏍囬锛�${currentKnowledge.value.title}
+    鐭ヨ瘑绫诲瀷锛�${getTypeLabel(currentKnowledge.value.type)}
+    閫傜敤鍦烘櫙锛�${currentKnowledge.value.scenario}
+    闂鎻忚堪锛�${currentKnowledge.value.problem}
+    瑙e喅鏂规锛�${currentKnowledge.value.solution}
+    鍏抽敭瑕佺偣锛�${currentKnowledge.value.keyPoints}
+    鍒涘缓浜猴細${currentKnowledge.value.creator}
   `.trim();
-  
+
   // 澶嶅埗鍒板壀璐存澘
   navigator.clipboard.writeText(knowledgeText).then(() => {
     ElMessage.success("鐭ヨ瘑鍐呭宸插鍒跺埌鍓创鏉�");
@@ -682,62 +787,85 @@
   });
 };
 
-// 鏀惰棌鐭ヨ瘑
-const markAsFavorite = () => {
-  // 澧炲姞浣跨敤娆℃暟
-  const index = mockData.findIndex(item => item.id === currentKnowledge.value.id);
-  if (index !== -1) {
-    mockData[index].usageCount += 1;
-    currentKnowledge.value.usageCount += 1;
+// 鍏抽棴鐭ヨ瘑琛ㄥ崟瀵硅瘽妗�
+const closeKnowledgeDialog = () => {
+  // 娓呯┖琛ㄥ崟鏁版嵁锛岄粯璁ゅ垱寤轰汉涓哄綋鍓嶇敤鎴�
+  Object.assign(form.value, {
+    id: undefined,
+    title: "",
+    type: "",
+    scenario: "",
+    efficiency: "",
+    problem: "",
+    solution: "",
+    keyPoints: "",
+    creator: userStore.nickName || "",
+    usageCount: 0
+  });
+  // 娓呴櫎琛ㄥ崟楠岃瘉鐘舵��
+  if (formRef.value) {
+    formRef.value.clearValidate();
   }
-  
-  ElMessage.success("宸叉敹钘忥紝浣跨敤娆℃暟+1");
+  dialogVisible.value = false;
+};
+
+// 鍏抽棴鏌ョ湅璇︽儏瀵硅瘽妗�
+const closeViewDialog = () => {
+  viewDialogVisible.value = false;
+};
+
+// 澶勭悊鏌ョ湅璇︽儏瀵硅瘽妗嗙‘璁わ紙鎵ц澶嶅埗鎿嶄綔锛�
+const handleViewDialogConfirm = () => {
+  copyKnowledge();
+  closeViewDialog();
 };
 
 // 鎻愪氦鐭ヨ瘑琛ㄥ崟
 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") {
       // 鏂板鐭ヨ瘑
-      const newKnowledge = {
-        id: (mockData.length + 1).toString(),
-        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,
-        createTime: new Date().toLocaleString()
-      };
-      
-      mockData.unshift(newKnowledge);
-      ElMessage.success("鐭ヨ瘑鍒涘缓鎴愬姛");
+      addKnowledgeBase(formData).then(res => {
+        if(res.code == 200){
+          ElMessage.success("娣诲姞鎴愬姛");
+          closeKnowledgeDialog();
+          getList();
+        }
+      }).catch(err => {
+        console.error("娣诲姞鐭ヨ瘑搴撳け璐�:", err);
+        ElMessage.error(err.msg || "娣诲姞澶辫触");
+      });
     } else {
-      // 缂栬緫鐭ヨ瘑
-      const index = mockData.findIndex(item => item.id === selectedIds.value[0]);
-      if (index !== -1) {
-        Object.assign(mockData[index], {
-          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
-        });
-        ElMessage.success("鐭ヨ瘑鏇存柊鎴愬姛");
-      }
+      // 鏇存柊鐭ヨ瘑 - 娣诲姞id鍙傛暟
+      updateKnowledgeBase({
+        id: form.value.id,
+        ...formData
+      }).then(res => {
+        if(res.code == 200){
+          ElMessage.success("鏇存柊鎴愬姛");
+          closeKnowledgeDialog();
+          getList();
+        }
+      }).catch(err => {
+        console.error("鏇存柊鐭ヨ瘑搴撳け璐�:", err);
+        ElMessage.error(err.msg || "鏇存柊澶辫触");
+      });
     }
-    
-    dialogVisible.value = false;
-    getList();
   } catch (error) {
     console.error("琛ㄥ崟楠岃瘉澶辫触:", error);
   }
@@ -749,26 +877,402 @@
     ElMessage.warning("璇烽�夋嫨瑕佸垹闄ょ殑鐭ヨ瘑");
     return;
   }
-  
-  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎", {
+
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄�,鏄惁纭鍒犻櫎?", "鍒犻櫎", {
     confirmButtonText: "纭",
     cancelButtonText: "鍙栨秷",
     type: "warning",
   }).then(() => {
-    // 浠巑ockData涓垹闄ら�変腑鐨勯」
-    selectedIds.value.forEach(id => {
-      const index = mockData.findIndex(item => item.id === id);
-      if (index !== -1) {
-        mockData.splice(index, 1);
+    // 鉁� 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 || "鍒犻櫎澶辫触");
     });
-    
-    ElMessage.success("鍒犻櫎鎴愬姛");
-    selectedIds.value = [];
-    getList();
   }).catch(() => {
     // 鐢ㄦ埛鍙栨秷
   });
+};
+
+// 瀵煎嚭
+const { proxy } = getCurrentInstance()
+const { knowledge_type } = proxy.useDict("knowledge_type")
+
+// 瀛楀吀宸ュ叿
+const knowledgeTypeOptions = computed(() => knowledge_type?.value || [])
+const getKnowledgeTypeLabel = (val) => {
+  const item = knowledgeTypeOptions.value.find(i => String(i.value) === String(val))
+  return item ? item.label : val
+}
+const getKnowledgeTypeTagType = (val) => {
+  const item = knowledgeTypeOptions.value.find(i => String(i.value) === String(val))
+  return item?.elTagType || "info"
+}
+const handleExport = () => {
+  proxy.download('/knowledgeBase/export', { ...searchForm.value }, '鐭ヨ瘑搴�.xlsx')
+}
+
+// ============ 鏂囦欢绠$悊鐩稿叧 ============
+
+// 鎵撳紑鏂囦欢绠$悊寮圭獥
+const openFilesDialog = (row) => {
+  currentKnowledgeBase.value = row;
+  filesDialogVisible.value = true;
+  loadFileList();
+};
+
+// 鍔犺浇鏂囦欢鍒楄〃
+const loadFileList = async () => {
+  if (!currentKnowledgeBase.value?.id) return;
+
+  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;
+  }
+};
+
+// 涓婁紶鍓嶆牎楠�
+const beforeUpload = (file) => {
+  const allowedTypes = ['.txt', '.md', '.docx', '.xlsx', '.xls', '.pdf'];
+  const fileName = file.name.toLowerCase();
+  const isAllowed = allowedTypes.some(type => fileName.endsWith(type));
+
+  if (!isAllowed) {
+    ElMessage.error('鍙敮鎸� txt銆乵d銆乨ocx銆亁lsx銆亁ls銆乸df 鏍煎紡鐨勬枃浠�');
+    return false;
+  }
+
+  const isLt50M = file.size / 1024 / 1024 < 50;
+  if (!isLt50M) {
+    ElMessage.error('鏂囦欢澶у皬涓嶈兘瓒呰繃 50MB');
+    return false;
+  }
+
+  return true;
+};
+
+// 涓婁紶鎴愬姛
+const handleUploadSuccess = (response, file) => {
+  console.log("涓婁紶鍝嶅簲:", response);  // 璋冭瘯鏃ュ織
+
+  if (response.code === 200) {
+    // 鉁� 鍚庣杩斿洖鐨勬槸 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 || "涓婁紶澶辫触");
+  }
+};
+
+// 涓婁紶澶辫触
+const handleUploadError = (error, file) => {
+  ElMessage.error(`鏂囦欢 ${file.name} 涓婁紶澶辫触`);
+};
+
+// 淇濆瓨鏂囦欢鍏宠仈
+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,  // 鐭ヨ瘑搴揑D
+      storageBlobIds: uploadedBlobIds.value             // 鏂囦欢blob ID鏁扮粍
+    });
+
+    ElMessage.success("鏂囦欢鍏宠仈淇濆瓨鎴愬姛,姝e湪鍚庡彴澶勭悊鍚戦噺鍖�");
+    uploadedBlobIds.value = [];
+
+    // 寤惰繜鍒锋柊鏂囦欢鍒楄〃,缁欏悗鍙板鐞嗘椂闂�
+    setTimeout(() => {
+      loadFileList();
+    }, 1000);
+  } catch (error) {
+    console.error("淇濆瓨鏂囦欢鍏宠仈澶辫触:", error);
+    ElMessage.error("淇濆瓨鏂囦欢鍏宠仈澶辫触");
+  } finally {
+    savingFiles.value = false;
+  }
+};
+
+// 閲嶆柊澶勭悊鍚戦噺鍖栫殑鏂囦欢
+const reprocessFile = async (row) => {
+  try {
+    await reprocessVector(row.id);
+    ElMessage.success("宸查噸鏂版彁浜ゅ悜閲忓寲浠诲姟");
+    // 寤惰繜鍒锋柊
+    setTimeout(() => {
+      loadFileList();
+    }, 1000);
+  } catch (error) {
+    console.error("閲嶆柊澶勭悊澶辫触:", error);
+    ElMessage.error("閲嶆柊澶勭悊澶辫触");
+  }
+};
+
+// 娓呯┖寰呬繚瀛樼殑鏂囦欢鍒楄〃
+const clearUploadedFiles = () => {
+  uploadedBlobIds.value = [];
+  ElMessage.success("宸叉竻绌哄緟淇濆瓨鏂囦欢鍒楄〃");
+};
+
+// 鍒犻櫎鏂囦欢
+const deleteFile = async (row) => {
+  try {
+    await ElMessageBox.confirm(
+      "纭畾瑕佸垹闄よ鏂囦欢鍚�?鍒犻櫎鍚庡皢鏃犳硶鎭㈠鍚戦噺鏁版嵁",
+      "鍒犻櫎纭",
+      {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        type: "warning"
+      }
+    );
+
+    // 鉁� DELETE璇锋眰浣跨敤data浼犻�扞D鏁扮粍
+    await deleteKnowledgeBaseFile([row.id]);  // 娉ㄦ剰: row.id鏄悜閲忚褰旾D,涓嶆槸storageBlobId
+    ElMessage.success("鍒犻櫎鎴愬姛");
+    loadFileList();
+  } catch (error) {
+    if (error !== 'cancel') {
+      console.error("鍒犻櫎鏂囦欢澶辫触:", error);
+      ElMessage.error("鍒犻櫎鏂囦欢澶辫触");
+    }
+  }
+};
+
+// 鐘舵�佹枃鏈槧灏�
+const getStatusText = (status) => {
+  const map = {
+    0: '寰呭鐞�',
+    1: '澶勭悊涓�',
+    2: '宸插畬鎴�',
+    3: '澶辫触'
+  };
+  return map[status] || '鏈煡';
+};
+
+// 鐘舵�佹爣绛剧被鍨嬫槧灏�
+const getStatusType = (status) => {
+  const map = {
+    0: 'info',
+    1: 'warning',
+    2: 'success',
+    3: 'danger'
+  };
+  return map[status] || 'info';
+};
+
+// 鍏抽棴鏂囦欢绠$悊寮圭獥
+const closeFilesDialog = () => {
+  filesDialogVisible.value = false;
+  currentKnowledgeBase.value = null;
+  fileList.value = [];
+  uploadedBlobIds.value = [];
+  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 = generateUUID();
+  messages.value = [];
+  inputQuestion.value = "";
+};
+
+// 鍙戦�佹秷鎭�
+const sendMessage = async () => {
+  // 鍙傛暟鏍¢獙
+  if (!inputQuestion.value.trim()) {
+    ElMessage.warning("璇疯緭鍏ラ棶棰�");
+    return;
+  }
+
+  if (!currentKnowledgeBase.value?.id) {
+    ElMessage.error("鐭ヨ瘑搴撲俊鎭紓甯�");
+    return;
+  }
+
+  const question = inputQuestion.value.trim();
+
+  // 娣诲姞鐢ㄦ埛娑堟伅
+  messages.value.push({
+    role: 'user',
+    content: question
+  });
+
+  inputQuestion.value = "";
+  chatLoading.value = true;
+
+  // 婊氬姩鍒板簳閮�
+  await nextTick();
+  scrollToBottom();
+
+  try {
+    // 鉁� 娴佸紡璇锋眰浣跨敤Fetch API
+    const response = await knowledgeChat({
+      knowledgeBaseId: currentKnowledgeBase.value.id,  // 鐭ヨ瘑搴揑D
+      memoryId: memoryId.value,                         // 浼氳瘽ID
+      question: question                                // 鐢ㄦ埛闂
+    });
+
+    if (!response.ok) {
+      const errorText = await response.text();
+      throw new Error(errorText || '璇锋眰澶辫触');
+    }
+
+    // 鉁� 鍚庣杩斿洖 text/stream;charset=utf-8
+    const reader = response.body.getReader();
+    const decoder = new TextDecoder();
+    let aiContent = '';
+
+    messages.value.push({ role: 'assistant', content: '' });
+
+    while (true) {
+      const { done, value } = await reader.read();
+      if (done) break;
+
+      const text = decoder.decode(value, { stream: true });  // 鉁� 娣诲姞stream閫夐」
+      aiContent += text;
+      messages.value[messages.value.length - 1].content = aiContent;
+
+      // 婊氬姩鍒板簳閮�
+      await nextTick();
+      scrollToBottom();
+    }
+
+    // 濡傛灉AI杩斿洖绌哄唴瀹�,鏄剧ず鎻愮ず
+    if (!aiContent.trim()) {
+      messages.value[messages.value.length - 1].content = '鎶辨瓑,鐭ヨ瘑搴撲腑鏈壘鍒扮浉鍏冲唴瀹�,璇峰皾璇曞叾浠栭棶棰樸��';
+    }
+  } catch (error) {
+    console.error("闂瓟璇锋眰澶辫触:", error);
+    ElMessage.error("闂瓟璇锋眰澶辫触,璇风◢鍚庨噸璇�");
+    messages.value.push({
+      role: 'assistant',
+      content: '鎶辨瓑,鍙戠敓浜嗛敊璇�,璇风◢鍚庨噸璇�'
+    });
+  } finally {
+    chatLoading.value = false;
+  }
+};
+
+// 娓呯┖瀵硅瘽
+const clearMessages = () => {
+  ElMessageBox.confirm(
+    "纭畾瑕佹竻绌烘墍鏈夊璇濊褰曞悧?",
+    "娓呯┖纭",
+    {
+      confirmButtonText: "纭畾",
+      cancelButtonText: "鍙栨秷",
+      type: "warning"
+    }
+  ).then(() => {
+    messages.value = [];
+    memoryId.value = generateUUID(); // 閲嶆柊鐢熸垚浼氳瘽ID
+    ElMessage.success("瀵硅瘽宸叉竻绌�");
+  }).catch(() => {
+    // 鐢ㄦ埛鍙栨秷
+  });
+};
+
+// 婊氬姩鍒板簳閮�
+const scrollToBottom = () => {
+  if (chatMessagesRef.value) {
+    chatMessagesRef.value.scrollTop = chatMessagesRef.value.scrollHeight;
+  }
+};
+
+// 鍏抽棴闂瓟寮圭獥
+const closeChatDialog = () => {
+  chatDialogVisible.value = false;
+  currentKnowledgeBase.value = null;
+  messages.value = [];
+  inputQuestion.value = "";
 };
 </script>
 
@@ -845,4 +1349,113 @@
   font-size: 14px;
   color: #909399;
 }
+
+/* 鏂囦欢绠$悊鏍峰紡 */
+.file-manager {
+  padding: 20px 0;
+}
+
+.upload-section {
+  display: flex;
+  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;
+  flex-direction: column;
+  height: 500px;
+}
+
+.chat-header {
+  margin-bottom: 16px;
+}
+
+.chat-messages {
+  flex: 1;
+  overflow-y: auto;
+  padding: 16px;
+  background: #f5f7fa;
+  border-radius: 8px;
+  margin-bottom: 16px;
+}
+
+.message {
+  margin-bottom: 16px;
+  max-width: 80%;
+}
+
+.message.user {
+  margin-left: auto;
+  text-align: right;
+}
+
+.message.assistant {
+  margin-right: auto;
+}
+
+.message-role {
+  font-size: 12px;
+  color: #909399;
+  margin-bottom: 4px;
+}
+
+.message-content {
+  display: inline-block;
+  padding: 10px 14px;
+  border-radius: 8px;
+  line-height: 1.6;
+  word-wrap: break-word;
+  white-space: pre-wrap;
+}
+
+.message.user .message-content {
+  background: #409eff;
+  color: white;
+}
+
+.message.assistant .message-content {
+  background: white;
+  color: #303133;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.typing {
+  animation: typing 1.5s infinite;
+}
+
+@keyframes typing {
+  0%, 50%, 100% {
+    opacity: 1;
+  }
+  25%, 75% {
+    opacity: 0.5;
+  }
+}
+
+.chat-input {
+  margin-top: auto;
+}
+
+.chat-actions {
+  margin-top: 8px;
+  text-align: right;
+}
+
 </style>

--
Gitblit v1.9.3