/** * Persona 文件夹管理 Store */ import { defineStore } from 'pinia'; import axios from 'axios'; // 类型定义 export interface PersonaFolder { folder_id: string; name: string; parent_id: string | null; description: string | null; sort_order: number; created_at: string; updated_at: string; } export interface Persona { persona_id: string; system_prompt: string; custom_error_message: string | null; begin_dialogs: string[]; tools: string[] | null; skills: string[] | null; folder_id: string | null; sort_order: number; created_at: string; updated_at: string; } export interface FolderTreeNode { folder_id: string; name: string; parent_id: string | null; description: string | null; sort_order: number; children: FolderTreeNode[]; } export interface ReorderItem { id: string; type: 'persona' | 'folder'; sort_order: number; } export const usePersonaStore = defineStore({ id: 'persona', state: () => ({ folderTree: [] as FolderTreeNode[], currentFolderId: null as string | null, currentFolders: [] as PersonaFolder[], currentPersonas: [] as Persona[], breadcrumbPath: [] as FolderTreeNode[], expandedFolderIds: [] as string[], // Store expanded folder IDs loading: false, treeLoading: false, }), getters: { // 当前文件夹名称 currentFolderName(): string { if (this.breadcrumbPath.length === 0) { return '根目录'; } return this.breadcrumbPath[this.breadcrumbPath.length - 1]?.name || '根目录'; }, }, actions: { /** * Toggle folder expansion state */ toggleFolderExpansion(folderId: string) { const index = this.expandedFolderIds.indexOf(folderId); if (index === -1) { this.expandedFolderIds.push(folderId); } else { this.expandedFolderIds.splice(index, 1); } }, /** * Set folder expansion state */ setFolderExpansion(folderId: string, expanded: boolean) { const index = this.expandedFolderIds.indexOf(folderId); if (expanded && index === -1) { this.expandedFolderIds.push(folderId); } else if (!expanded && index !== -1) { this.expandedFolderIds.splice(index, 1); } }, /** * 加载文件夹树形结构 */ async loadFolderTree(): Promise { this.treeLoading = true; try { const response = await axios.get('/api/persona/folder/tree'); if (response.data.status === 'ok') { this.folderTree = response.data.data || []; } else { throw new Error(response.data.message || '获取文件夹树失败'); } } finally { this.treeLoading = false; } }, /** * 导航到指定文件夹 */ async navigateToFolder(folderId: string | null): Promise { this.loading = true; try { this.currentFolderId = folderId; // 并行加载子文件夹和 Persona const [foldersRes, personasRes] = await Promise.all([ axios.get('/api/persona/folder/list', { params: { parent_id: folderId ?? '' } }), axios.get('/api/persona/list', { params: { folder_id: folderId ?? '' } }), ]); if (foldersRes.data.status === 'ok') { this.currentFolders = foldersRes.data.data || []; } if (personasRes.data.status === 'ok') { this.currentPersonas = personasRes.data.data || []; } // 更新面包屑 this.updateBreadcrumb(folderId); } finally { this.loading = false; } }, /** * 更新面包屑路径 */ updateBreadcrumb(folderId: string | null): void { if (folderId === null) { this.breadcrumbPath = []; return; } // 从树中查找路径 const path: FolderTreeNode[] = []; const findPath = (nodes: FolderTreeNode[], targetId: string): boolean => { for (const node of nodes) { if (node.folder_id === targetId) { path.push(node); return true; } if (node.children.length > 0 && findPath(node.children, targetId)) { path.unshift(node); return true; } } return false; }; findPath(this.folderTree, folderId); this.breadcrumbPath = path; }, /** * 刷新当前文件夹内容 */ async refreshCurrentFolder(): Promise { await this.navigateToFolder(this.currentFolderId); }, /** * 移动 Persona 到文件夹 */ async movePersonaToFolder(personaId: string, targetFolderId: string | null): Promise { const response = await axios.post('/api/persona/move', { persona_id: personaId, folder_id: targetFolderId }); if (response.data.status !== 'ok') { throw new Error(response.data.message || '移动人格失败'); } // 刷新当前文件夹内容和文件夹树 await Promise.all([ this.refreshCurrentFolder(), this.loadFolderTree(), ]); }, /** * 移动文件夹到另一个文件夹 */ async moveFolderToFolder(folderId: string, targetParentId: string | null): Promise { const response = await axios.post('/api/persona/folder/update', { folder_id: folderId, parent_id: targetParentId }); if (response.data.status !== 'ok') { throw new Error(response.data.message || '移动文件夹失败'); } // 刷新当前文件夹内容和文件夹树 await Promise.all([ this.refreshCurrentFolder(), this.loadFolderTree(), ]); }, /** * 创建文件夹 */ async createFolder(data: { name: string; parent_id?: string | null; description?: string; }): Promise { const response = await axios.post('/api/persona/folder/create', { ...data, parent_id: data.parent_id ?? this.currentFolderId, }); if (response.data.status !== 'ok') { throw new Error(response.data.message || '创建文件夹失败'); } // 刷新当前文件夹内容和文件夹树 await Promise.all([ this.refreshCurrentFolder(), this.loadFolderTree(), ]); return response.data.data.folder; }, /** * 更新文件夹 */ async updateFolder(data: { folder_id: string; name?: string; description?: string; }): Promise { const response = await axios.post('/api/persona/folder/update', data); if (response.data.status !== 'ok') { throw new Error(response.data.message || '更新文件夹失败'); } // 刷新当前文件夹内容和文件夹树 await Promise.all([ this.refreshCurrentFolder(), this.loadFolderTree(), ]); }, /** * 删除文件夹 */ async deleteFolder(folderId: string): Promise { const response = await axios.post('/api/persona/folder/delete', { folder_id: folderId }); if (response.data.status !== 'ok') { throw new Error(response.data.message || '删除文件夹失败'); } // 刷新当前文件夹内容和文件夹树 await Promise.all([ this.refreshCurrentFolder(), this.loadFolderTree(), ]); }, /** * 删除 Persona */ async deletePersona(personaId: string): Promise { const response = await axios.post('/api/persona/delete', { persona_id: personaId }); if (response.data.status !== 'ok') { throw new Error(response.data.message || '删除人格失败'); } // 刷新当前文件夹内容 await this.refreshCurrentFolder(); }, /** * 批量更新排序 */ async reorderItems(items: ReorderItem[]): Promise { const response = await axios.post('/api/persona/reorder', { items }); if (response.data.status !== 'ok') { throw new Error(response.data.message || '更新排序失败'); } // 刷新当前文件夹内容 await this.refreshCurrentFolder(); }, /** * 根据文件夹 ID 查找树节点 */ findFolderInTree(folderId: string): FolderTreeNode | null { const findNode = (nodes: FolderTreeNode[]): FolderTreeNode | null => { for (const node of nodes) { if (node.folder_id === folderId) { return node; } if (node.children.length > 0) { const found = findNode(node.children); if (found) return found; } } return null; }; return findNode(this.folderTree); }, } });