Initial commit: SQL audit platform v0.1.0

FastAPI backend with auth, user, instance, ticket, query, dashboard APIs.
React + TypeScript frontend with mock data UI (10 pages).
SQLite + async SQLAlchemy, JWT auth, role-based access control.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
loganandClaude Opus 4.7 committed 2026-05-22 11:11:57 +08:00
commit 439155c92e
290 files changed
+61950

No files matched your search

+164
View File
@@ -0,0 +1,164 @@
import { createContext, useContext, useState, useCallback, useMemo } from 'react';
import { menuItems, currentUser as defaultUser } from '@/lib/mock';
import { authApi } from '@/api/auth';
export type UserRole = 'admin' | 'dba' | 'developer' | 'guest';
export interface AuthUser {
id: number;
username: string;
email: string;
role: UserRole;
roleName: string;
avatar: string;
}
interface AuthContextType {
user: AuthUser;
isLoggedIn: boolean;
login: (username: string, password: string) => Promise<boolean>;
logout: () => void;
switchRole: (role: UserRole) => void;
hasPermission: (menuId: string) => boolean;
visibleMenuItems: typeof menuItems;
isAdmin: boolean;
isDBA: boolean;
isDeveloper: boolean;
isGuest: boolean;
}
const roleNameMap: Record<UserRole, string> = {
admin: '超级管理员',
dba: '数据库管理员',
developer: '开发人员',
guest: '访客',
};
const routePermissionMap: Record<string, UserRole[]> = {
dashboard: ['admin', 'dba', 'developer', 'guest'],
mysql: ['admin', 'dba'],
postgres: ['admin', 'dba'],
redis: ['admin', 'dba'],
mongo: ['admin', 'dba'],
tickets: ['admin', 'dba', 'developer'],
queries: ['admin', 'dba', 'developer', 'guest'],
roles: ['admin'],
users: ['admin'],
'data-permission': ['admin', 'dba'],
'audit-rules': ['admin', 'dba'],
workflow: ['admin', 'dba'],
'auto-task': ['admin'],
announcement: ['admin'],
'config-platform': ['admin'],
notifications: ['admin'],
};
export const actionPermissionMap: Record<string, UserRole[]> = {
'ticket.create': ['admin', 'dba', 'developer'],
'ticket.approve': ['admin', 'dba'],
'ticket.execute': ['admin', 'dba'],
'ticket.rollback': ['admin', 'dba'],
'ticket.delete': ['admin'],
'query.create': ['admin', 'dba', 'developer'],
'query.export': ['admin', 'dba', 'developer'],
'instance.add': ['admin'],
'instance.edit': ['admin', 'dba'],
'instance.delete': ['admin'],
'user.manage': ['admin'],
'role.manage': ['admin'],
'rule.manage': ['admin', 'dba'],
'workflow.manage': ['admin', 'dba'],
'config.manage': ['admin'],
'announcement.manage': ['admin'],
'auto-task.manage': ['admin'],
};
const AuthContext = createContext<AuthContextType | null>(null);
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<AuthUser>({
id: defaultUser.id,
username: defaultUser.username,
email: defaultUser.email,
role: defaultUser.role,
roleName: defaultUser.roleName,
avatar: defaultUser.avatar,
});
const [isLoggedIn, setIsLoggedIn] = useState(() => !!localStorage.getItem('token'));
const login = useCallback(async (username: string, password: string): Promise<boolean> => {
try {
const res = await authApi.login(username, password);
localStorage.setItem('token', res.access_token);
const u = res.user;
const role = u.role as UserRole;
setUser({
id: u.id,
username: u.username,
email: u.email || '',
role,
roleName: roleNameMap[role] || role,
avatar: u.display_name?.charAt(0) || username.charAt(0).toUpperCase(),
});
setIsLoggedIn(true);
return true;
} catch {
return false;
}
}, []);
const logout = useCallback(() => {
localStorage.removeItem('token');
setIsLoggedIn(false);
}, []);
const switchRole = useCallback((role: UserRole) => {
setUser(prev => ({
...prev,
role,
roleName: roleNameMap[role],
username: role === 'admin' ? 'admin' : role === 'dba' ? 'zhangsan' : role === 'developer' ? 'wangwu' : 'visitor',
email: `${role}@company.com`,
avatar: role.charAt(0).toUpperCase(),
}));
}, []);
const hasPermission = useCallback((menuId: string): boolean => {
const allowedRoles = routePermissionMap[menuId];
if (!allowedRoles) return false;
return allowedRoles.includes(user.role);
}, [user.role]);
const visibleMenuItems = useMemo(() => {
return menuItems.filter(item => item.roles.includes(user.role));
}, [user.role]);
const value = useMemo(() => ({
user,
isLoggedIn,
login,
logout,
switchRole,
hasPermission,
visibleMenuItems,
isAdmin: user.role === 'admin',
isDBA: user.role === 'dba',
isDeveloper: user.role === 'developer',
isGuest: user.role === 'guest',
}), [user, isLoggedIn, login, logout, switchRole, hasPermission, visibleMenuItems]);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
export function useAuth(): AuthContextType {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error('useAuth must be used within AuthProvider');
return ctx;
}
export function useActionPermission(action: string): boolean {
const { user } = useAuth();
const allowedRoles = actionPermissionMap[action];
if (!allowedRoles) return false;
return allowedRoles.includes(user.role);
}