Просмотр исходного кода

[Bugfix 0000]修复AI助手在对话过程中切换其他任务不能对话的问题

wangkeyi 3 недель назад
Родитель
Сommit
e1db397e5f
1 измененных файлов с 116 добавлено и 51 удалено
  1. 116 51
      src/views/ventAI/manageAssistent/components/AiAssistantModal.vue

+ 116 - 51
src/views/ventAI/manageAssistent/components/AiAssistantModal.vue

@@ -94,7 +94,7 @@
             ref="chatInputRef"
             ref="chatInputRef"
             v-model="inputMessage"
             v-model="inputMessage"
             :pendingFile="pendingFile"
             :pendingFile="pendingFile"
-            :loading="loading || !!pendingApprovalSessionId"
+            :loading="loading || !!currentPendingApproval"
             :streaming="streaming"
             :streaming="streaming"
             :contextUsed="contextUsed"
             :contextUsed="contextUsed"
             :contextMax="contextMax"
             :contextMax="contextMax"
@@ -297,8 +297,6 @@
   const contextPercent = ref(0);
   const contextPercent = ref(0);
   const thinkLevel = ref('off');
   const thinkLevel = ref('off');
   const editMode = ref('full');
   const editMode = ref('full');
-  const pendingApprovalSessionId = ref('');
-  const pendingApprovalThreadId = ref('');
   const downloadConfirm = ref<{ url: string; filename: string } | null>(null);
   const downloadConfirm = ref<{ url: string; filename: string } | null>(null);
   const downloadConfirmTaskId = ref('');
   const downloadConfirmTaskId = ref('');
   let downloadConfirmTimer: ReturnType<typeof setTimeout> | null = null;
   let downloadConfirmTimer: ReturnType<typeof setTimeout> | null = null;
@@ -483,14 +481,62 @@
   };
   };
 
 
   const inputMessage = ref('');
   const inputMessage = ref('');
-  const loading = ref(false);
-  const streaming = ref(false);
-  const activeAbortController = ref<AbortController | null>(null);
   const selectedSessions = ref<Array<{ id: string; name: string }>>([]);
   const selectedSessions = ref<Array<{ id: string; name: string }>>([]);
   const selectedSkill = ref<{ name: string; display_name: string } | null>(null);
   const selectedSkill = ref<{ name: string; display_name: string } | null>(null);
 
 
+  // 按任务维度的状态存储
+  const taskAbortControllers = ref<Map<string, AbortController>>(new Map());
+  const taskPendingApprovals = ref<Map<string, { sessionId: string; threadId: string }>>(new Map());
+
+  // loading 和 streaming 改为计算属性,基于当前任务的 isStreaming 状态
+  const loading = computed(() => {
+    const currentTask = taskList.value.find((t) => t.id === currentTaskId.value);
+    return currentTask?.isStreaming ?? false;
+  });
+
+  const streaming = computed(() => {
+    const currentTask = taskList.value.find((t) => t.id === currentTaskId.value);
+    return currentTask?.isStreaming ?? false;
+  });
+
+  // 获取当前任务的待审批状态
+  const currentPendingApproval = computed(() => {
+    return taskPendingApprovals.value.get(currentTaskId.value);
+  });
+
+  // 设置任务的AbortController
+  const setTaskAbortController = (taskId: string, controller: AbortController | null) => {
+    const map = new Map(taskAbortControllers.value);
+    if (controller) {
+      map.set(taskId, controller);
+    } else {
+      map.delete(taskId);
+    }
+    taskAbortControllers.value = map;
+  };
+
+  // 设置任务的审批状态
+  const setTaskPendingApproval = (taskId: string, sessionId: string, threadId: string) => {
+    const map = new Map(taskPendingApprovals.value);
+    map.set(taskId, { sessionId, threadId });
+    taskPendingApprovals.value = map;
+  };
+
+  // 清除任务的审批状态
+  const clearTaskPendingApproval = (taskId: string) => {
+    const map = new Map(taskPendingApprovals.value);
+    map.delete(taskId);
+    taskPendingApprovals.value = map;
+  };
+
+  // 停止指定任务的流式传输
+  const stopTaskStreaming = (taskId: string) => {
+    const controller = taskAbortControllers.value.get(taskId);
+    controller?.abort();
+  };
+
   const stopStreaming = () => {
   const stopStreaming = () => {
-    activeAbortController.value?.abort();
+    stopTaskStreaming(currentTaskId.value);
   };
   };
 
 
   const getCurrentSessionId = (): string => {
   const getCurrentSessionId = (): string => {
@@ -528,8 +574,7 @@
     showFileList.value = false;
     showFileList.value = false;
 
 
     if (newTask.sessionId && !historyLoadedTasks.value.has(taskId)) {
     if (newTask.sessionId && !historyLoadedTasks.value.has(taskId)) {
-      if (streaming.value) return;
-      loading.value = true;
+      if (newTask.isStreaming) return; // 新任务正在流式中,无需加载历史
       try {
       try {
         const res = await getDetail(newTask.sessionId);
         const res = await getDetail(newTask.sessionId);
         const messages = res?.messages || (Array.isArray(res) ? res : res?.data);
         const messages = res?.messages || (Array.isArray(res) ? res : res?.data);
@@ -539,8 +584,6 @@
         historyLoadedTasks.value.add(taskId);
         historyLoadedTasks.value.add(taskId);
       } catch (error) {
       } catch (error) {
         console.error('加载历史会话失败:', error);
         console.error('加载历史会话失败:', error);
-      } finally {
-        loading.value = false;
       }
       }
     }
     }
 
 
@@ -642,7 +685,22 @@
   };
   };
 
 
   const handleApprove = async () => {
   const handleApprove = async () => {
-    const sessionId = pendingApprovalSessionId.value || getCurrentSessionId();
+    // 优先使用当前任务的审批状态,如果没有则查找任何有待审批状态的任务
+    let pendingApproval = currentPendingApproval.value;
+    if (!pendingApproval) {
+      // 查找任何有待审批状态的任务
+      for (const [taskId, approval] of taskPendingApprovals.value.entries()) {
+        pendingApproval = approval;
+        // 切换到该任务以便用户看到审批界面
+        if (currentTaskId.value !== taskId) {
+          await switchTask(taskId);
+        }
+        break;
+      }
+    }
+    if (!pendingApproval) return;
+
+    const sessionId = pendingApproval.sessionId;
     if (!sessionId) return;
     if (!sessionId) return;
 
 
     const approveTask = taskList.value.find((t) => t.sessionId === sessionId);
     const approveTask = taskList.value.find((t) => t.sessionId === sessionId);
@@ -665,20 +723,18 @@
       messages.value = approveTask.messages;
       messages.value = approveTask.messages;
     }
     }
 
 
-    loading.value = true;
     approveTask.isStreaming = true;
     approveTask.isStreaming = true;
     showTodoBar.value = false;
     showTodoBar.value = false;
     currentTodos.value = [];
     currentTodos.value = [];
 
 
     const controller = new AbortController();
     const controller = new AbortController();
-    activeAbortController.value = controller;
-    streaming.value = true;
+    setTaskAbortController(approveTask.id, controller);
 
 
     try {
     try {
       const result = await chatResumeStream(
       const result = await chatResumeStream(
         {
         {
           session_id: sessionId,
           session_id: sessionId,
-          thread_id: pendingApprovalThreadId.value || undefined,
+          thread_id: pendingApproval?.threadId || undefined,
           action: 'approve',
           action: 'approve',
           signal: controller.signal,
           signal: controller.signal,
         },
         },
@@ -709,14 +765,9 @@
         }
         }
       }
       }
     } finally {
     } finally {
-      if (activeAbortController.value === controller) {
-        activeAbortController.value = null;
-      }
-      streaming.value = false;
-      loading.value = false;
+      setTaskAbortController(approveTask.id, null);
       approveTask.isStreaming = false;
       approveTask.isStreaming = false;
-      pendingApprovalSessionId.value = '';
-      pendingApprovalThreadId.value = '';
+      clearTaskPendingApproval(approveTask.id);
       if (currentTaskId.value === approveTask.id) {
       if (currentTaskId.value === approveTask.id) {
         await scrollToBottom();
         await scrollToBottom();
       }
       }
@@ -724,7 +775,22 @@
   };
   };
 
 
   const handleReject = async () => {
   const handleReject = async () => {
-    const sessionId = pendingApprovalSessionId.value || getCurrentSessionId();
+    // 优先使用当前任务的审批状态,如果没有则查找任何有待审批状态的任务
+    let pendingApproval = currentPendingApproval.value;
+    if (!pendingApproval) {
+      // 查找任何有待审批状态的任务
+      for (const [taskId, approval] of taskPendingApprovals.value.entries()) {
+        pendingApproval = approval;
+        // 切换到该任务以便用户看到审批界面
+        if (currentTaskId.value !== taskId) {
+          await switchTask(taskId);
+        }
+        break;
+      }
+    }
+    if (!pendingApproval) return;
+
+    const sessionId = pendingApproval.sessionId;
     if (!sessionId) return;
     if (!sessionId) return;
 
 
     const rejectTask = taskList.value.find((t) => t.sessionId === sessionId);
     const rejectTask = taskList.value.find((t) => t.sessionId === sessionId);
@@ -742,9 +808,8 @@
 
 
     rejectTask.messages = [...taskMessages];
     rejectTask.messages = [...taskMessages];
 
 
-    const threadId = pendingApprovalThreadId.value || undefined;
-    pendingApprovalSessionId.value = '';
-    pendingApprovalThreadId.value = '';
+    const threadId = pendingApproval?.threadId || undefined;
+    clearTaskPendingApproval(rejectTask.id);
 
 
     try {
     try {
       await chatResumeStream(
       await chatResumeStream(
@@ -987,7 +1052,7 @@
       return;
       return;
     }
     }
     if (loading.value) return;
     if (loading.value) return;
-    if (pendingApprovalSessionId.value) {
+    if (currentPendingApproval.value) {
       message.warning('请先审批执行计划');
       message.warning('请先审批执行计划');
       return;
       return;
     }
     }
@@ -1015,7 +1080,6 @@
     selectedSkill.value = null;
     selectedSkill.value = null;
 
 
     try {
     try {
-      loading.value = true;
       await nextTick();
       await nextTick();
       chatMessagesRef.value?.forceScrollToBottom();
       chatMessagesRef.value?.forceScrollToBottom();
 
 
@@ -1045,7 +1109,6 @@
         currentTask.messages = [...messages.value];
         currentTask.messages = [...messages.value];
       }
       }
     } finally {
     } finally {
-      loading.value = false;
       await scrollToBottom();
       await scrollToBottom();
     }
     }
   };
   };
@@ -1321,8 +1384,7 @@
           elapsedMs,
           elapsedMs,
           prevThinkingContent: aiMsg.thinkingContent,
           prevThinkingContent: aiMsg.thinkingContent,
         };
         };
-        pendingApprovalSessionId.value = interruptSessionId;
-        pendingApprovalThreadId.value = data.thread_id || '';
+        setTaskPendingApproval(taskId, interruptSessionId, data.thread_id || '');
         break;
         break;
       }
       }
     }
     }
@@ -1397,8 +1459,7 @@
     if (originTask) originTask.isStreaming = true;
     if (originTask) originTask.isStreaming = true;
 
 
     const controller = new AbortController();
     const controller = new AbortController();
-    activeAbortController.value = controller;
-    streaming.value = true;
+    setTaskAbortController(originTaskId, controller);
 
 
     try {
     try {
       const result = await unifiedStream(
       const result = await unifiedStream(
@@ -1424,6 +1485,12 @@
           }
           }
           originTask.pendingSessionId = undefined;
           originTask.pendingSessionId = undefined;
           if (originTask.id !== result.session_id) {
           if (originTask.id !== result.session_id) {
+            // 将 AbortController 从旧 ID 迁移到新 ID
+            const controller = taskAbortControllers.value.get(originTaskId);
+            if (controller) {
+              setTaskAbortController(originTaskId, null);
+              setTaskAbortController(result.session_id, controller);
+            }
             taskList.value = taskList.value.filter((t) => t.id !== result.session_id);
             taskList.value = taskList.value.filter((t) => t.id !== result.session_id);
             originTask.id = result.session_id;
             originTask.id = result.session_id;
             historyLoadedTasks.value.add(result.session_id);
             historyLoadedTasks.value.add(result.session_id);
@@ -1454,11 +1521,9 @@
       }
       }
       throw error;
       throw error;
     } finally {
     } finally {
-      if (activeAbortController.value === controller) {
-        activeAbortController.value = null;
-      }
-      streaming.value = false;
-      // 任务在流结束时可能已被改名为后端 session_id,用发送时捕获的对象引用重置状态
+      // 任务在流结束时可能已被改名为后端 session_id,需要使用最终的 ID 清理状态
+      const finalTaskId = originTask?.id || originTaskId;
+      setTaskAbortController(finalTaskId, null);
       if (originTask) originTask.isStreaming = false;
       if (originTask) originTask.isStreaming = false;
     }
     }
   };
   };
@@ -1506,8 +1571,7 @@
     if (originTask) originTask.isStreaming = true;
     if (originTask) originTask.isStreaming = true;
 
 
     const controller = new AbortController();
     const controller = new AbortController();
-    activeAbortController.value = controller;
-    streaming.value = true;
+    setTaskAbortController(originTaskId, controller);
 
 
     try {
     try {
       const result = await reviewPdfStream(
       const result = await reviewPdfStream(
@@ -1534,6 +1598,12 @@
           }
           }
           originTask.pendingSessionId = undefined;
           originTask.pendingSessionId = undefined;
           if (originTask.id !== result.session_id) {
           if (originTask.id !== result.session_id) {
+            // 将 AbortController 从旧 ID 迁移到新 ID
+            const controller = taskAbortControllers.value.get(originTaskId);
+            if (controller) {
+              setTaskAbortController(originTaskId, null);
+              setTaskAbortController(result.session_id, controller);
+            }
             taskList.value = taskList.value.filter((t) => t.id !== result.session_id);
             taskList.value = taskList.value.filter((t) => t.id !== result.session_id);
             originTask.id = result.session_id;
             originTask.id = result.session_id;
             historyLoadedTasks.value.add(result.session_id);
             historyLoadedTasks.value.add(result.session_id);
@@ -1564,11 +1634,9 @@
       }
       }
       throw error;
       throw error;
     } finally {
     } finally {
-      if (activeAbortController.value === controller) {
-        activeAbortController.value = null;
-      }
-      streaming.value = false;
-      // 任务在流结束时可能已被改名为后端 session_id,用发送时捕获的对象引用重置状态
+      // 任务在流结束时可能已被改名为后端 session_id,需要使用最终的 ID 清理状态
+      const finalTaskId = originTask?.id || originTaskId;
+      setTaskAbortController(finalTaskId, null);
       if (originTask) originTask.isStreaming = false;
       if (originTask) originTask.isStreaming = false;
     }
     }
   };
   };
@@ -1626,7 +1694,6 @@
 
 
         // 如果是历史任务,加载其消息
         // 如果是历史任务,加载其消息
         if (targetTask.sessionId && !historyLoadedTasks.value.has(targetTask.id)) {
         if (targetTask.sessionId && !historyLoadedTasks.value.has(targetTask.id)) {
-          loading.value = true;
           try {
           try {
             const res = await getDetail(targetTask.sessionId);
             const res = await getDetail(targetTask.sessionId);
             const messages = res?.messages || (Array.isArray(res) ? res : res?.data);
             const messages = res?.messages || (Array.isArray(res) ? res : res?.data);
@@ -1636,8 +1703,6 @@
             historyLoadedTasks.value.add(targetTask.id);
             historyLoadedTasks.value.add(targetTask.id);
           } catch (error) {
           } catch (error) {
             console.error('加载历史会话失败:', error);
             console.error('加载历史会话失败:', error);
-          } finally {
-            loading.value = false;
           }
           }
         }
         }
 
 
@@ -1751,8 +1816,8 @@
       clearTimeout(downloadConfirmTimer);
       clearTimeout(downloadConfirmTimer);
       downloadConfirmTimer = null;
       downloadConfirmTimer = null;
     }
     }
-    // 组件卸载时主动断开流式连接
-    activeAbortController.value?.abort();
+    // 组件卸载时主动断开所有任务的流式连接
+    taskAbortControllers.value.forEach((controller) => controller.abort());
   });
   });
 </script>
 </script>