import { defineStore } from 'pinia'; export interface ConversationSummary { id: string; title: string; updated_at: string | number; total_messages?: number; total_tools?: number; } export interface WorkspaceConversationGroup { workspaceId: string; conversations: ConversationSummary[]; loading: boolean; hasMore: boolean; loadingMore: boolean; offset: number; visibleOffset: number; visibleLimit: number; bufferLimit: number; fetchLimit: number; expanded: boolean; } interface ConversationState { conversations: ConversationSummary[]; searchResults: ConversationSummary[]; conversationInsertAnimations: Record; conversationListAnimationMode: 'idle' | 'create' | 'duplicate' | 'delete'; pendingDeletingConversationIds: string[]; conversationsLoading: boolean; hasMoreConversations: boolean; loadingMoreConversations: boolean; currentConversationId: string | null; currentConversationTitle: string; searchQuery: string; searchTimer: ReturnType | null; searchActive: boolean; searchInProgress: boolean; searchMoreAvailable: boolean; searchOffset: number; searchTotal: number; conversationsOffset: number; conversationsLimit: number; runningWorkspaceTasks: any[]; acknowledgedCompletedTaskIds: string[]; workspaceGroups: WorkspaceConversationGroup[]; multiAgentMode: boolean; } export const useConversationStore = defineStore('conversation', { state: (): ConversationState => ({ conversations: [], searchResults: [], conversationInsertAnimations: {}, conversationListAnimationMode: 'idle', pendingDeletingConversationIds: [], conversationsLoading: false, hasMoreConversations: false, loadingMoreConversations: false, currentConversationId: null, currentConversationTitle: '', searchQuery: '', searchTimer: null, searchActive: false, searchInProgress: false, searchMoreAvailable: false, searchOffset: 0, searchTotal: 0, conversationsOffset: 0, conversationsLimit: 20, runningWorkspaceTasks: [], acknowledgedCompletedTaskIds: [], workspaceGroups: [], multiAgentMode: false }), actions: { resetConversations() { this.conversations = []; this.searchResults = []; this.conversationInsertAnimations = {}; this.conversationListAnimationMode = 'idle'; this.pendingDeletingConversationIds = []; this.searchActive = false; this.searchInProgress = false; this.searchMoreAvailable = false; this.searchOffset = 0; this.searchTotal = 0; this.hasMoreConversations = false; this.loadingMoreConversations = false; this.conversationsOffset = 0; this.runningWorkspaceTasks = []; this.acknowledgedCompletedTaskIds = []; }, cancelSearchTimer() { if (this.searchTimer) { clearTimeout(this.searchTimer); this.searchTimer = null; } }, setWorkspaceGroups(groups: WorkspaceConversationGroup[]) { this.workspaceGroups = groups; }, setWorkspaceGroupExpanded(workspaceId: string, expanded: boolean) { const group = this.workspaceGroups.find((g) => g.workspaceId === workspaceId); if (group) { group.expanded = expanded; } }, setWorkspaceGroupConversations(workspaceId: string, conversations: ConversationSummary[]) { const group = this.workspaceGroups.find((g) => g.workspaceId === workspaceId); if (group) { group.conversations = conversations; } }, appendWorkspaceGroupConversations(workspaceId: string, conversations: ConversationSummary[]) { const group = this.workspaceGroups.find((g) => g.workspaceId === workspaceId); if (group) { group.conversations.push(...conversations); } }, setWorkspaceGroupLoading(workspaceId: string, loading: boolean) { const group = this.workspaceGroups.find((g) => g.workspaceId === workspaceId); if (group) { group.loading = loading; } }, setWorkspaceGroupLoadingMore(workspaceId: string, loadingMore: boolean) { const group = this.workspaceGroups.find((g) => g.workspaceId === workspaceId); if (group) { group.loadingMore = loadingMore; } }, setWorkspaceGroupHasMore(workspaceId: string, hasMore: boolean) { const group = this.workspaceGroups.find((g) => g.workspaceId === workspaceId); if (group) { group.hasMore = hasMore; } }, setWorkspaceGroupOffset(workspaceId: string, offset: number) { const group = this.workspaceGroups.find((g) => g.workspaceId === workspaceId); if (group) { group.offset = offset; } }, setWorkspaceGroupVisibleOffset(workspaceId: string, visibleOffset: number) { const group = this.workspaceGroups.find((g) => g.workspaceId === workspaceId); if (group) { group.visibleOffset = Math.max(0, visibleOffset); } }, ensureWorkspaceGroup(workspaceId: string) { if (!workspaceId) return; const exists = this.workspaceGroups.some((g) => g.workspaceId === workspaceId); if (!exists) { this.workspaceGroups.push({ workspaceId, conversations: [], loading: false, hasMore: false, loadingMore: false, offset: 0, visibleOffset: 0, visibleLimit: 5, bufferLimit: 20, fetchLimit: 25, expanded: true }); } }, async loadWorkspaceConversations( workspaceId: string, { reset = false, refresh = false } = {} ) { if (!workspaceId) return; console.log('[sidebar-debug] loadWorkspaceConversations', { workspaceId, reset, refresh }); let index = this.workspaceGroups.findIndex((g) => g.workspaceId === workspaceId); if (index === -1) { this.ensureWorkspaceGroup(workspaceId); index = this.workspaceGroups.length - 1; } const group = this.workspaceGroups[index]; if (reset) { group.conversations = []; group.offset = 0; group.visibleOffset = 0; group.hasMore = false; } if (group.loading || group.loadingMore) return; const fetchOffset = refresh ? 0 : group.offset; group.loading = true; try { const maParam = this.multiAgentMode ? '&multi_agent_mode=1' : '&multi_agent_mode=0'; const response = await fetch( `/api/conversations?workspace_id=${encodeURIComponent(workspaceId)}&limit=${group.fetchLimit}&offset=${fetchOffset}${maParam}` ); const data = await response.json(); if (data.success) { const items = (data.data?.conversations || []).map((conv: any) => ({ id: conv.id, title: conv.title, updated_at: conv.updated_at, total_messages: conv.total_messages, total_tools: conv.total_tools })); if (refresh) { const tail = group.conversations.slice(items.length); group.conversations = [...items, ...tail]; } else if (fetchOffset === 0) { group.conversations = items; } else { group.conversations.push(...items); } group.hasMore = !!data.data?.has_more; if (!refresh) { group.offset = fetchOffset + items.length; } } else { console.error('加载工作区对话失败:', data.error); } } catch (error) { console.error('加载工作区对话异常:', error); } finally { group.loading = false; } }, async loadMoreWorkspaceConversations(workspaceId: string) { const index = this.workspaceGroups.findIndex((g) => g.workspaceId === workspaceId); if (index === -1) return; const group = this.workspaceGroups[index]; if (group.loadingMore) return; const hasHidden = group.conversations.length > group.visibleLimit; if (!hasHidden && !group.hasMore) return; group.loadingMore = true; // 先尝试从后端再加载 20 条作为新的缓冲 if (group.hasMore) { try { const fetchOffset = group.conversations.length; const response = await fetch( `/api/conversations?workspace_id=${encodeURIComponent(workspaceId)}&limit=${group.bufferLimit}&offset=${fetchOffset}` ); const data = await response.json(); if (data.success) { const items = (data.data?.conversations || []).map((conv: any) => ({ id: conv.id, title: conv.title, updated_at: conv.updated_at, total_messages: conv.total_messages, total_tools: conv.total_tools })); group.conversations.push(...items); group.hasMore = !!data.data?.has_more; } } catch (error) { console.error('加载更多工作区对话异常:', error); } } // 把可见区扩大 20 条,让用户直接看到更多对话 group.visibleLimit += group.bufferLimit; group.loadingMore = false; } } });