import { createStore } from "zustand/vanilla"; import { createJSONStorage, persist } from "zustand/middleware"; import { accountStore } from "~/store/account"; export type HostOption = { label: string; host: string; source: "local" | "remote"; }; type CacheSection = "accounts" | "records" | "logs"; type DensityMode = "comfortable" | "compact"; type SettingsState = { persistAccounts: boolean; persistRecords: boolean; persistLogs: boolean; debugEnabled: boolean; autoScrollLogs: boolean; showLogTimestamps: boolean; densityMode: DensityMode; logFontSize: number; sidebarWidth: number; localHosts: HostOption[]; remoteHosts: HostOption[]; setPersistSection: (section: CacheSection, value: boolean) => void; clearPersistedSection: (section: CacheSection) => void; clearAllPersistedData: () => void; setDebugEnabled: (value: boolean) => void; setAutoScrollLogs: (value: boolean) => void; setShowLogTimestamps: (value: boolean) => void; setDensityMode: (value: DensityMode) => void; setLogFontSize: (value: number) => void; setSidebarWidth: (value: number) => void; addLocalHost: (host: Omit) => void; removeLocalHost: (host: string) => void; setRemoteHosts: (hosts: Omit[]) => void; }; const accountStorageKey = "account-storage"; const settingsStorageKey = "settings-storage"; type PersistedStorage = { state?: Record; version?: number; }; const patchAccountStorage = ( patcher: (state: Record) => Record, ) => { const rawValue = localStorage.getItem(accountStorageKey); if (!rawValue) { return; } try { const parsedValue = JSON.parse(rawValue) as PersistedStorage; const currentState = parsedValue.state && typeof parsedValue.state === "object" ? parsedValue.state : {}; const nextState = patcher(currentState); localStorage.setItem( accountStorageKey, JSON.stringify({ ...parsedValue, state: nextState, }), ); } catch { localStorage.removeItem(accountStorageKey); } }; const uniqueHosts = (hosts: HostOption[]) => { const map = new Map(); for (const item of hosts) { if (!map.has(item.host)) { map.set(item.host, item); } } return Array.from(map.values()); }; export const getMergedHosts = ( localHosts: HostOption[], remoteHosts: HostOption[], ) => { return uniqueHosts([...localHosts, ...remoteHosts]); }; export const settingsStore = createStore()( persist( (set, get) => ({ persistAccounts: true, persistRecords: true, persistLogs: true, debugEnabled: false, autoScrollLogs: true, showLogTimestamps: false, densityMode: "comfortable", logFontSize: 12, sidebarWidth: 320, localHosts: [ { label: "默认站点", host: "cqcst.leykeji.com", source: "local" }, ], remoteHosts: [], setPersistSection: (section, value) => { if (section === "accounts") set({ persistAccounts: value }); if (section === "records") set({ persistRecords: value }); if (section === "logs") set({ persistLogs: value }); if (!value) { queueMicrotask(() => get().clearPersistedSection(section)); } }, clearPersistedSection: (section) => { const store = accountStore.getState(); if (section === "accounts") { store.clearAccountsData(); localStorage.removeItem(accountStorageKey); } if (section === "records") { store.clearRecordsData(); patchAccountStorage((state) => { const { records, recordCacheMap, workList, examList, workExamCacheMap, ...rest } = state; void records; void recordCacheMap; void workList; void examList; void workExamCacheMap; return rest; }); } if (section === "logs") { store.clearAllStudyLogs(); patchAccountStorage((state) => { const { studyLogsMap, ...rest } = state; void studyLogsMap; return rest; }); } }, clearAllPersistedData: () => { accountStore.getState().clearAllData(); localStorage.removeItem(accountStorageKey); localStorage.removeItem(settingsStorageKey); window.location.reload(); }, setDebugEnabled: (value) => set({ debugEnabled: value }), setAutoScrollLogs: (value) => set({ autoScrollLogs: value }), setShowLogTimestamps: (value) => set({ showLogTimestamps: value }), setDensityMode: (value) => set({ densityMode: value }), setLogFontSize: (value) => set({ logFontSize: value }), setSidebarWidth: (value) => set({ sidebarWidth: value }), addLocalHost: (host) => set((state) => ({ localHosts: uniqueHosts([ { ...host, source: "local" }, ...state.localHosts, ...state.remoteHosts, ]).filter((item) => item.source === "local"), })), removeLocalHost: (host) => set((state) => ({ localHosts: state.localHosts.filter((item) => item.host !== host), })), setRemoteHosts: (hosts) => set({ remoteHosts: uniqueHosts( hosts.map((item) => ({ ...item, source: "remote" as const })), ), }), }), { name: "settings-storage", storage: createJSONStorage(() => localStorage), }, ), );