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 (
- {user?.email || ''}
+ {user?.role || ''}