refactor(frontend): P1-P2 架构统一 — utils/hooks/api 模块化
P1: - utils/storage.ts、theme.ts、validate.ts + index 统一出口 - request/store/useTheme 接入 storage;清零 confirm/alert - PipelineManager、TerminalAuditTab 拆分子模块(<700行红线) P2: - api/monitor、api/deploy 子目录化 - hooks/api 扩展:servers/pipelines/alerts/audit/sessionCommands - PipelineManager、AuditOperationsTab 接入 TanStack Query
This commit is contained in:
1 parent
d19a03d427
commit
f45e203e21
196 files changed
+3228
-2018
No files matched your search
@@ -1,38 +1,16 @@
|
||||
import { createContext, useContext, useState, useCallback, useMemo, useEffect } from 'react';
|
||||
import {
|
||||
type Theme,
|
||||
type ThemeOption,
|
||||
THEME_OPTIONS,
|
||||
getInitialTheme,
|
||||
persistTheme,
|
||||
applyThemeToDocument,
|
||||
getNextTheme,
|
||||
} from '@/utils/theme';
|
||||
|
||||
export type Theme =
|
||||
| 'ocean-deep'
|
||||
| 'light-professional'
|
||||
| 'midnight-purple'
|
||||
| 'pine-green'
|
||||
| 'orange-vitality';
|
||||
|
||||
export interface ThemeOption {
|
||||
id: Theme;
|
||||
name: string;
|
||||
description: string;
|
||||
isDark: boolean;
|
||||
primaryColor: string;
|
||||
}
|
||||
|
||||
export const THEME_OPTIONS: ThemeOption[] = [
|
||||
{ id: 'ocean-deep', name: '深海蓝', description: '专业稳重的深蓝色调', isDark: true, primaryColor: '#3b82f6' },
|
||||
{ id: 'light-professional', name: '明亮白', description: '清爽干净的浅色主题', isDark: false, primaryColor: '#2563eb' },
|
||||
{ id: 'midnight-purple', name: '午夜紫', description: '神秘优雅的紫色调', isDark: true, primaryColor: '#a855f7' },
|
||||
{ id: 'pine-green', name: '松林绿', description: '自然清新的绿色主题', isDark: true, primaryColor: '#22c55e' },
|
||||
{ id: 'orange-vitality', name: '活力橙', description: '温暖活力的橙色主题', isDark: true, primaryColor: '#f97316' },
|
||||
];
|
||||
|
||||
const THEME_ORDER: Theme[] = THEME_OPTIONS.map((o) => o.id);
|
||||
const DEFAULT_THEME: Theme = 'ocean-deep';
|
||||
const STORAGE_KEY = 'aiops-theme';
|
||||
|
||||
// Backward compatibility: map old theme names to new ones
|
||||
function migrateLegacyTheme(value: string | null): Theme | null {
|
||||
if (value === 'dark') return 'ocean-deep';
|
||||
if (value === 'light') return 'light-professional';
|
||||
return null;
|
||||
}
|
||||
export type { Theme, ThemeOption };
|
||||
export { THEME_OPTIONS };
|
||||
|
||||
interface ThemeContextType {
|
||||
theme: Theme;
|
||||
@@ -42,53 +20,29 @@ interface ThemeContextType {
|
||||
|
||||
const ThemeContext = createContext<ThemeContextType | null>(null);
|
||||
|
||||
function getInitialTheme(): Theme {
|
||||
if (typeof window === 'undefined') return DEFAULT_THEME;
|
||||
const stored = localStorage.getItem(STORAGE_KEY);
|
||||
const migrated = migrateLegacyTheme(stored);
|
||||
if (migrated) {
|
||||
// Persist the migrated value so we don't migrate every time
|
||||
localStorage.setItem(STORAGE_KEY, migrated);
|
||||
return migrated;
|
||||
}
|
||||
if (stored && THEME_ORDER.includes(stored as Theme)) {
|
||||
return stored as Theme;
|
||||
}
|
||||
return DEFAULT_THEME;
|
||||
}
|
||||
|
||||
function applyTheme(theme: Theme) {
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
}
|
||||
|
||||
export function ThemeProvider({ children }: { children: React.ReactNode }) {
|
||||
const [theme, setThemeState] = useState<Theme>(getInitialTheme);
|
||||
|
||||
useEffect(() => {
|
||||
applyTheme(theme);
|
||||
applyThemeToDocument(theme);
|
||||
}, [theme]);
|
||||
|
||||
const toggleTheme = useCallback(() => {
|
||||
setThemeState((prev) => {
|
||||
const idx = THEME_ORDER.indexOf(prev);
|
||||
const next = THEME_ORDER[(idx + 1) % THEME_ORDER.length];
|
||||
localStorage.setItem(STORAGE_KEY, next);
|
||||
const next = getNextTheme(prev);
|
||||
persistTheme(next);
|
||||
return next;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const setTheme = useCallback((t: Theme) => {
|
||||
localStorage.setItem(STORAGE_KEY, t);
|
||||
persistTheme(t);
|
||||
setThemeState(t);
|
||||
}, []);
|
||||
|
||||
const value = useMemo(
|
||||
() => ({
|
||||
theme,
|
||||
toggleTheme,
|
||||
setTheme,
|
||||
}),
|
||||
[theme, toggleTheme, setTheme]
|
||||
() => ({ theme, toggleTheme, setTheme }),
|
||||
[theme, toggleTheme, setTheme],
|
||||
);
|
||||
|
||||
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
|
||||
@@ -98,4 +52,4 @@ export function useTheme(): ThemeContextType {
|
||||
const ctx = useContext(ThemeContext);
|
||||
if (!ctx) throw new Error('useTheme must be used within ThemeProvider');
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user