Files
aiops/frontend/src/store/index.ts
T
attacker ff0b268984 feat: 修复仪表盘数据管线 — 补充应用发布种子数据 + 修复limit参数解析 + LDAP认证集成 + User类型完善
后端改进:
- 修复 dashboard/recent-alerts 的 limit 参数解析 (原代码错误地将数字解析为日期)
- 为 dashboard/recent-releases 添加 limit 参数解析支持
- 新增 generateAppReleases 种子数据生成函数 (10条应用发布记录)
- 修复 AlertEvent 的 rule_name/rule_id/severity 数据一致性
- 添加 go-ldap/ldap/v3 依赖并集成 LDAP 认证处理器
- 添加 seed.go 自动种子数据初始化 (admin用户+LDAP配置)
- User model 添加 AuthSource/LDAPConfig 字段

前端改进:
- 修复 User 类型定义以匹配后端 API (real_name/is_admin/auth_source等)
- 修复 Header.tsx 的 real_name 属性引用导致 TypeScript 编译错误
- 统一 API 服务层、暗色主题样式、组件联调优化

验证:
- go build ./... 编译通过
- npm run build 构建通过
- 仪表盘发布历史、告警消息等区域数据正常展示
- 健康检查 /health 正常
2026-06-14 02:11:10 +08:00

162 lines
4.2 KiB
TypeScript

import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import type { User } from '@/types';
// 主题状态
interface ThemeState {
sidebarCollapsed: boolean;
toggleSidebar: () => void;
}
export const useThemeStore = create<ThemeState>((set) => ({
sidebarCollapsed: false,
toggleSidebar: () => set((state) => ({ sidebarCollapsed: !state.sidebarCollapsed })),
}));
// 用户状态
interface UserState {
user: User | null;
token: string | null;
isAuthenticated: boolean;
theme?: string;
setUser: (user: User | null) => void;
setToken: (token: string | null) => void;
login: (user: User, token: string) => void;
logout: () => void;
}
export const useUserStore = create<UserState>()(
persist(
(set) => ({
user: null,
token: null,
isAuthenticated: false,
theme: 'ocean-deep',
setUser: (user) => set({ user }),
setToken: (token) => set({ token }),
login: (user, token) => set({ user, token, isAuthenticated: true }),
logout: () => set({ user: null, token: null, isAuthenticated: false }),
}),
{
name: 'user-storage',
}
)
);
// 菜单状态
interface MenuState {
activeMenu: string;
openMenus: string[];
setActiveMenu: (menu: string) => void;
toggleMenu: (menu: string) => void;
}
export const useMenuStore = create<MenuState>((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<TabState>((set) => ({
tabs: [{ id: 'dashboard', title: '仪表盘', 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<Notification, 'id' | 'timestamp' | 'read'>) => void;
markAsRead: (id: string) => void;
markAllAsRead: () => void;
removeNotification: (id: string) => void;
}
export const useNotificationStore = create<NotificationState>((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),
})),
}));