From b411ac169a8dc0926d9141ba11a76a8498e0b2f0 Mon Sep 17 00:00:00 2001 From: dark Date: Sat, 14 Feb 2026 11:34:51 +0800 Subject: [PATCH] feat: frontend types, API client, AuthContext, and dynamic sidebar --- .../pc/src/components/layout/Sidebar.tsx | 117 +++++++--- .../pc/src/contexts/AuthContext.tsx | 101 ++++++++- frontend/react-shadcn/pc/src/services/api.ts | 204 +++++++++++++++++- frontend/react-shadcn/pc/src/types/index.ts | 164 ++++++++++++++ 4 files changed, 555 insertions(+), 31 deletions(-) diff --git a/frontend/react-shadcn/pc/src/components/layout/Sidebar.tsx b/frontend/react-shadcn/pc/src/components/layout/Sidebar.tsx index 3ed7cac..88d0720 100644 --- a/frontend/react-shadcn/pc/src/components/layout/Sidebar.tsx +++ b/frontend/react-shadcn/pc/src/components/layout/Sidebar.tsx @@ -1,15 +1,43 @@ import { NavLink } from 'react-router-dom' -import { LayoutDashboard, Users, LogOut, Settings } from 'lucide-react' +import { + LayoutDashboard, Users, LogOut, Settings, FolderOpen, + Shield, Menu as MenuIcon, Building2, User, ChevronDown, +} from 'lucide-react' +import type { LucideIcon } from 'lucide-react' import { useAuth } from '@/contexts/AuthContext' +import { useState, useRef, useEffect } from 'react' +import type { MenuItem } from '@/types' -const navItems = [ - { path: '/dashboard', icon: LayoutDashboard, label: '首页' }, - { path: '/users', icon: Users, label: '用户管理' }, - { path: '/settings', icon: Settings, label: '设置' }, -] +const iconMap: Record = { + User, LayoutDashboard, Users, FolderOpen, Shield, + Menu: MenuIcon, Building2, Settings, +} + +function getIcon(iconName: string): LucideIcon { + return iconMap[iconName] || LayoutDashboard +} export function Sidebar() { - const { user, logout } = useAuth() + const { user, logout, userMenus, currentOrg, userOrgs, switchOrg } = useAuth() + const [orgDropdownOpen, setOrgDropdownOpen] = useState(false) + const dropdownRef = useRef(null) + + useEffect(() => { + function handleClickOutside(e: MouseEvent) { + if (dropdownRef.current && !dropdownRef.current.contains(e.target as Node)) { + setOrgDropdownOpen(false) + } + } + document.addEventListener('mousedown', handleClickOutside) + return () => document.removeEventListener('mousedown', handleClickOutside) + }, []) + + const handleSwitchOrg = async (orgId: number) => { + await switchOrg(orgId) + setOrgDropdownOpen(false) + } + + const menuItems: MenuItem[] = userMenus.length > 0 ? userMenus : [] return (