import { create } from 'zustand'; import { persist, createJSONStorage } from 'zustand/middleware'; import type { User, Event, Note, AIConversation, EventType, RepeatType } from '../types'; import { api } from '../services/api'; import { syncRemindersToSW } from '../services/swSync'; import { calculateNextReminderDate, findNextValidReminderDate, isDuplicateReminder, createNextRecurringEventData } from '../utils/repeatCalculator'; // 应用设置类型 interface AppSettings { showHolidays: boolean; // 是否显示节假日 holidayDisplayCount: number; // 节假日显示数量 showStatutoryOnly: boolean; // 仅显示法定节假日 enabledHolidays: string[]; // 用户关注的节假日ID列表(空表示全部) browserNotifications: boolean; // 是否启用浏览器通知 } // 默认设置 const defaultSettings: AppSettings = { showHolidays: true, holidayDisplayCount: 3, showStatutoryOnly: false, enabledHolidays: [], browserNotifications: false, }; interface AppState { // Auth state user: User | null; isAuthenticated: boolean; isLoading: boolean; // Settings state settings: AppSettings; updateSettings: (settings: Partial) => void; // Data state events: Event[]; notes: Note | null; conversations: AIConversation[]; // Actions setUser: (user: User | null) => void; setLoading: (loading: boolean) => void; setEvents: (events: Event[]) => void; addEvent: (event: Event) => void; updateEvent: (id: string, updates: Partial) => void; deleteEvent: (id: string) => void; setNotes: (notes: Note | null) => void; updateNotesContent: (content: string) => void; setConversations: (conversations: AIConversation[]) => void; addConversation: (conversation: AIConversation) => void; // Data fetch actions fetchEvents: (type?: EventType) => Promise; fetchNotes: () => Promise; saveNotes: (content: string) => Promise; createEvent: (event: Partial) => Promise<{ error: any }>; updateEventById: (id: string, event: Partial) => Promise<{ error: any }>; deleteEventById: (id: string) => Promise<{ error: any }>; // Auth actions login: (email: string, password: string) => Promise<{ error: any }>; register: (email: string, password: string, nickname?: string) => Promise<{ error: any }>; logout: () => Promise; checkAuth: () => Promise; } export const useAppStore = create()( persist( (set) => ({ // Initial state user: null, isAuthenticated: false, isLoading: true, settings: defaultSettings, events: [], notes: null, conversations: [], // Settings updateSettings: (newSettings) => set((state) => ({ settings: { ...state.settings, ...newSettings }, })), // Setters setUser: (user) => set({ user, isAuthenticated: !!user }), setLoading: (isLoading) => set({ isLoading }), setEvents: (events) => set({ events }), addEvent: (event) => set((state) => ({ events: [...state.events, event] })), updateEvent: (id, updates) => set((state) => ({ events: state.events.map((e) => (e.id === id ? { ...e, ...updates } : e)), })), deleteEvent: (id) => set((state) => ({ events: state.events.filter((e) => e.id !== id), })), setNotes: (notes) => set({ notes }), updateNotesContent: (content) => set((state) => ({ notes: state.notes ? { ...state.notes, content } : null, })), setConversations: (conversations) => set({ conversations }), addConversation: (conversation) => set((state) => ({ conversations: [conversation, ...state.conversations], })), // Data fetch actions fetchEvents: async (type) => { try { const events = await api.events.list(type); set({ events }); } catch (error) { console.error('Failed to fetch events:', error); } }, fetchNotes: async () => { try { const notes = await api.notes.get(); set({ notes }); } catch (error) { console.error('Failed to fetch notes:', error); } }, saveNotes: async (content) => { try { const notes = await api.notes.update(content); set({ notes }); } catch (error) { console.error('Failed to save notes:', error); throw error; } }, createEvent: async (event) => { try { const newEvent = await api.events.create(event); set((state) => ({ events: [...state.events, newEvent] })); // 如果是提醒事件,同步到 Service Worker if (event.type === 'reminder' && event.reminder_times && event.reminder_times.length > 0) { await syncRemindersToSW(); } return { error: null }; } catch (error: any) { return { error: error.message || '创建失败' }; } }, updateEventById: async (id, event) => { try { // 使用 set 的回调函数获取当前状态 let currentEvent: Event | undefined; let allEvents: Event[] = []; set((state) => { allEvents = state.events; currentEvent = state.events.find((e) => e.id === id); return { events: state.events.map((e) => e.id === id ? { ...e, ...event } : e ), }; }); if (!currentEvent) { return { error: '事件不存在' }; } // 如果是标记完成,且是重复提醒,自动创建下一周期,并移除当前提醒的重复设置 if (event.is_completed && currentEvent.repeat_type !== 'none') { // 从 next_reminder_date 开始查找正确的下一个提醒日期 const nextReminderDate = currentEvent.next_reminder_date || currentEvent.date; const nextValidDate = findNextValidReminderDate( nextReminderDate, currentEvent.repeat_type as RepeatType, currentEvent.repeat_interval ); // 检查是否已存在相同的提醒(去重) const exists = isDuplicateReminder( allEvents, currentEvent.title, nextValidDate, currentEvent.repeat_type as RepeatType ); if (!exists) { // 使用统一的重复事件创建函数,自动继承所有字段(包括 priority 和 reminder_times) const newEventData = createNextRecurringEventData( currentEvent, nextValidDate ); const newEvent = await api.events.create(newEventData); // 添加新事件到本地状态 set((state) => ({ events: [...state.events, newEvent], })); } // 发送 API 请求:标记为已完成并移除重复设置(合并为一个请求) await api.events.update(id, { is_completed: true, repeat_type: 'none', repeat_interval: null, next_reminder_date: null, }); // 更新本地状态:标记为已完成并移除重复设置 set((state) => ({ events: state.events.map((e) => e.id === id ? { ...e, is_completed: true, repeat_type: 'none', repeat_interval: null, next_reminder_date: null, } : e ), })); } else { // 非完成操作,正常发送 API 请求 await api.events.update(id, event); } // 如果更新涉及提醒设置,同步到 Service Worker if (event.reminder_times || event.type === 'reminder') { await syncRemindersToSW(); } return { error: null }; } catch (error: any) { // 失败时回滚,重新获取数据 const events = await api.events.list(); set({ events }); return { error: error.message || '更新失败' }; } }, deleteEventById: async (id) => { try { await api.events.delete(id); set((state) => ({ events: state.events.filter((e) => e.id !== id), })); return { error: null }; } catch (error: any) { return { error: error.message || '删除失败' }; } }, // Auth actions login: async (email, password) => { try { const { user, token, refreshToken } = await api.auth.login(email, password); api.setTokens(token, refreshToken); set({ user, isAuthenticated: true }); return { error: null }; } catch (error: any) { const errorMessage = error.message || '登录失败,请检查邮箱和密码'; return { error: errorMessage }; } }, register: async (email, password, nickname) => { try { const { user, token, refreshToken } = await api.auth.register(email, password, nickname); api.setTokens(token, refreshToken); set({ user, isAuthenticated: true }); return { error: null }; } catch (error: any) { const errorMessage = error.message || '注册失败,请稍后重试'; return { error: errorMessage }; } }, logout: async () => { try { await api.auth.logout(); } catch { // Ignore logout error } api.clearTokens(); set({ user: null, isAuthenticated: false, events: [], notes: null }); }, checkAuth: async () => { set({ isLoading: true }); const token = api.getToken(); if (!token) { set({ isAuthenticated: false, isLoading: false }); return; } try { const { user } = await api.auth.getCurrentUser(); set({ user, isAuthenticated: true, isLoading: false }); } catch { // Token invalid, try refresh try { const { token: newToken } = await api.auth.refreshToken(); const { user } = await api.auth.getCurrentUser(); const refreshToken = api.getRefreshToken()!; api.setTokens(newToken, refreshToken); set({ user, isAuthenticated: true, isLoading: false }); } catch { api.clearTokens(); set({ isAuthenticated: false, isLoading: false }); } } }, }), { name: 'qia-storage', storage: createJSONStorage(() => localStorage), partialize: (state) => ({ user: state.user, isAuthenticated: state.isAuthenticated, settings: state.settings, }), } ) );