'use client'; import { useState, useCallback } from 'react'; // 笔记数据类型 export interface Note { id: number; noteId: string; userId: string; conversationId?: string | null; messageId?: string | null; title: string; content: string; tags: string[]; isPinned: boolean; isArchived: boolean; createdAt: string; updatedAt: string; } // 创建笔记参数 export interface CreateNoteParams { title: string; content: string; tags?: string[]; conversationId?: string; messageId?: string; } // 更新笔记参数 export interface UpdateNoteParams { title?: string; content?: string; tags?: string[]; isPinned?: boolean; isArchived?: boolean; } // 筛选参数 export interface NotesFilter { search?: string; tags?: string[]; isPinned?: boolean; isArchived?: boolean; } /** * 笔记管理 Hook * 提供笔记的增删改查功能 */ export function useNotes() { const [notes, setNotes] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); // 获取笔记列表 const fetchNotes = useCallback(async (filter?: NotesFilter) => { setLoading(true); setError(null); try { const params = new URLSearchParams(); if (filter?.search) params.set('search', filter.search); if (filter?.tags?.length) params.set('tags', filter.tags.join(',')); if (filter?.isPinned !== undefined) params.set('isPinned', String(filter.isPinned)); if (filter?.isArchived !== undefined) params.set('isArchived', String(filter.isArchived)); const response = await fetch(`/api/notes?${params.toString()}`); if (!response.ok) { throw new Error('获取笔记列表失败'); } const data = await response.json(); setNotes(data.notes || []); return data.notes || []; } catch (err) { const message = err instanceof Error ? err.message : '获取笔记列表失败'; setError(message); return []; } finally { setLoading(false); } }, []); // 创建笔记 const createNote = useCallback(async (params: CreateNoteParams): Promise => { setLoading(true); setError(null); try { const response = await fetch('/api/notes', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params), }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || '创建笔记失败'); } const data = await response.json(); // 将新笔记添加到列表开头 setNotes(prev => [data.note, ...prev]); return data.note; } catch (err) { const message = err instanceof Error ? err.message : '创建笔记失败'; setError(message); return null; } finally { setLoading(false); } }, []); // 更新笔记 const updateNote = useCallback(async (noteId: string, params: UpdateNoteParams): Promise => { setLoading(true); setError(null); try { const response = await fetch(`/api/notes/${noteId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params), }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || '更新笔记失败'); } const data = await response.json(); // 更新列表中的笔记 setNotes(prev => prev.map(note => note.noteId === noteId ? data.note : note)); return data.note; } catch (err) { const message = err instanceof Error ? err.message : '更新笔记失败'; setError(message); return null; } finally { setLoading(false); } }, []); // 删除笔记 const deleteNote = useCallback(async (noteId: string): Promise => { setLoading(true); setError(null); try { const response = await fetch(`/api/notes/${noteId}`, { method: 'DELETE', }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || '删除笔记失败'); } // 从列表中移除笔记 setNotes(prev => prev.filter(note => note.noteId !== noteId)); return true; } catch (err) { const message = err instanceof Error ? err.message : '删除笔记失败'; setError(message); return false; } finally { setLoading(false); } }, []); // 切换置顶状态 const togglePin = useCallback(async (noteId: string): Promise => { const note = notes.find(n => n.noteId === noteId); if (!note) return false; const result = await updateNote(noteId, { isPinned: !note.isPinned }); return result !== null; }, [notes, updateNote]); // 切换归档状态 const toggleArchive = useCallback(async (noteId: string): Promise => { const note = notes.find(n => n.noteId === noteId); if (!note) return false; const result = await updateNote(noteId, { isArchived: !note.isArchived }); return result !== null; }, [notes, updateNote]); // 获取所有标签 const getAllTags = useCallback((): string[] => { const tagSet = new Set(); notes.forEach(note => { note.tags?.forEach(tag => tagSet.add(tag)); }); return Array.from(tagSet); }, [notes]); return { notes, loading, error, fetchNotes, createNote, updateNote, deleteNote, togglePin, toggleArchive, getAllTags, }; }