import { create } from "zustand"; import { persist } from "zustand/middleware"; import type { User } from "@/types"; import { removeItem, STORAGE_KEYS } from "@/utils/storage"; import i18n from "@/i18n"; // 主题状态 interface ThemeState { sidebarCollapsed: boolean; toggleSidebar: () => void; } export const useThemeStore = create((set) => ({ sidebarCollapsed: false, toggleSidebar: () => set((state) => ({ sidebarCollapsed: !state.sidebarCollapsed })), })); // 语言状态(i18n — U3 国际化) type AppLanguage = "zh-CN" | "en-US"; interface LanguageState { language: AppLanguage; setLanguage: (lang: AppLanguage) => void; } export const useLanguageStore = create()( persist( (set) => ({ language: "zh-CN" as AppLanguage, setLanguage: (lang) => { // Ensure the target locale bundle is loaded (en-US is lazy) before switching. import("@/i18n") .then(async ({ default: i18n, ensureLocaleLoaded }) => { await ensureLocaleLoaded(lang); i18n.changeLanguage(lang); }) .catch(() => { /* i18n not yet loaded */ }); set({ language: lang }); }, }), { name: "language-storage", }, ), ); // 会话安全策略:用于 RDP/SSH/POD 等远程会话的水印、剪贴板和文件管控。 // Logan.Li interface SessionSecurityState { watermarkEnabled: boolean; recordEnabled: boolean; clipboardEnabled: boolean; fileUploadEnabled: boolean; fileDownloadEnabled: boolean; commandPolicyEnabled: boolean; approvalRequired: boolean; setWatermarkEnabled: (enabled: boolean) => void; setPolicy: ( policy: Partial< Omit >, ) => void; } export const useSessionSecurityStore = create()( persist( (set) => ({ watermarkEnabled: true, recordEnabled: true, clipboardEnabled: true, fileUploadEnabled: true, fileDownloadEnabled: true, commandPolicyEnabled: false, approvalRequired: false, setWatermarkEnabled: (watermarkEnabled) => set({ watermarkEnabled }), setPolicy: (policy) => set(policy), }), { name: "session-security-storage", }, ), ); export const useSessionWatermarkStore = useSessionSecurityStore; // 用户状态 interface UserState { user: User | null; token: string | null; isAuthenticated: boolean; theme?: string; /** 当前用户权限码列表(RBAC 按钮级控制);admin 为 ["*"];null 表示未加载 */ permissions: string[] | null; setUser: (user: User | null) => void; setToken: (token: string | null) => void; setPermissions: (permissions: string[] | null) => void; login: (user: User, token: string, permissions?: string[]) => void; logout: () => void; } export const useUserStore = create()( persist( (set) => ({ user: null as User | null, token: null as string | null, isAuthenticated: false, theme: "ocean-deep", permissions: null as string[] | null, setUser: (user) => set({ user }), setToken: (token) => set({ token }), setPermissions: (permissions) => set({ permissions }), login: (user, token, permissions) => set({ user, token, isAuthenticated: true, permissions: permissions ?? null, }), logout: () => { removeItem(STORAGE_KEYS.token); set({ user: null as User | null, token: null as string | null, isAuthenticated: false, permissions: null, }); }, }), { name: "user-storage", }, ), ); // 菜单状态 interface MenuState { activeMenu: string; openMenus: string[]; setActiveMenu: (menu: string) => void; toggleMenu: (menu: string) => void; } export const useMenuStore = create((set) => ({ activeMenu: "dashboard", openMenus: [], setActiveMenu: (menu) => set({ activeMenu: menu }), toggleMenu: (menu) => set((state) => ({ openMenus: state.openMenus.includes(menu) ? state.openMenus.filter((m) => m !== menu) : [...state.openMenus, menu], })), })); // 标签页状态 interface TabItem { id: string; title: string; path: string; closable?: boolean; } interface TabState { tabs: TabItem[]; activeTab: string; addTab: (tab: TabItem) => void; removeTab: (tabId: string) => void; setActiveTab: (tabId: string) => void; } export const useTabStore = create((set) => ({ tabs: [ { id: "dashboard", title: i18n.t("monitor.dashboard.custom.typeGauge"), path: "/", closable: false, }, ], activeTab: "dashboard", addTab: (tab) => set((state) => { const exists = state.tabs.find((t) => t.id === tab.id); if (exists) { return { activeTab: tab.id }; } return { tabs: [...state.tabs, tab], activeTab: tab.id }; }), removeTab: (tabId) => set((state) => { const newTabs = state.tabs.filter((t) => t.id !== tabId); if (state.activeTab === tabId && newTabs.length > 0) { return { tabs: newTabs, activeTab: newTabs[newTabs.length - 1].id }; } return { tabs: newTabs }; }), setActiveTab: (tabId) => set({ activeTab: tabId }), })); // 通知状态 interface Notification { id: string; type: "info" | "success" | "warning" | "error"; title: string; message: string; timestamp: number; read: boolean; } interface NotificationState { notifications: Notification[]; unreadCount: number; addNotification: ( notification: Omit, ) => void; markAsRead: (id: string) => void; markAllAsRead: () => void; removeNotification: (id: string) => void; } export const useNotificationStore = create((set) => ({ notifications: [], unreadCount: 0, addNotification: (notification) => set((state) => ({ notifications: [ { ...notification, id: Date.now().toString(), timestamp: Date.now(), read: false, }, ...state.notifications, ].slice(0, 100), unreadCount: state.unreadCount + 1, })), markAsRead: (id) => set((state) => { const notification = state.notifications.find((n) => n.id === id); if (notification && !notification.read) { return { notifications: state.notifications.map((n) => n.id === id ? { ...n, read: true } : n, ), unreadCount: Math.max(0, state.unreadCount - 1), }; } return state; }), markAllAsRead: () => set((state) => ({ notifications: state.notifications.map((n) => ({ ...n, read: true })), unreadCount: 0, })), removeNotification: (id) => set((state) => ({ notifications: state.notifications.filter((n) => n.id !== id), })), }));