269 lines
9.0 KiB
TypeScript
269 lines
9.0 KiB
TypeScript
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<string, 'create' | 'duplicate' | 'duplicateSource'>;
|
|
conversationListAnimationMode: 'idle' | 'create' | 'duplicate' | 'delete';
|
|
pendingDeletingConversationIds: string[];
|
|
conversationsLoading: boolean;
|
|
hasMoreConversations: boolean;
|
|
loadingMoreConversations: boolean;
|
|
currentConversationId: string | null;
|
|
currentConversationTitle: string;
|
|
searchQuery: string;
|
|
searchTimer: ReturnType<typeof setTimeout> | 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;
|
|
}
|
|
}
|
|
});
|