import React, { useState, useEffect, useLayoutEffect } from 'react'; import { LayoutDashboard, Users, BookOpen, GraduationCap, Settings, LogOut, FileText, School, UserCog, Palette, X, Building, Gamepad2, CalendarCheck, UserCircle, MessageSquare, Bot, ArrowUp, ArrowDown, Save, UserCheck, Download, Smartphone } from 'lucide-react'; import { UserRole } from '../types'; import { api } from '../services/api'; interface SidebarProps { currentView: string; onChangeView: (view: string) => void; userRole: UserRole; onLogout: () => void; isOpen: boolean; onClose: () => void; } interface MenuItem { id: string; label: string; icon: React.ElementType; roles: UserRole[]; } export const Sidebar: React.FC = ({ currentView, onChangeView, userRole, onLogout, isOpen, onClose }) => { const currentUser = api.auth.getCurrentUser(); const canSeeAI = userRole === UserRole.ADMIN || (userRole === UserRole.TEACHER && currentUser?.aiAccess); const isHomeroom = userRole === UserRole.TEACHER && !!currentUser?.homeroomClass; // Default Items const defaultItems: MenuItem[] = [ { id: 'dashboard', label: '工作台', icon: LayoutDashboard, roles: [UserRole.ADMIN, UserRole.PRINCIPAL, UserRole.TEACHER, UserRole.STUDENT] }, { id: 'my-class', label: '我的班级', icon: UserCheck, roles: isHomeroom ? [UserRole.TEACHER] : [] }, { id: 'ai-assistant', label: 'AI 智能助教', icon: Bot, roles: canSeeAI ? [UserRole.ADMIN, UserRole.TEACHER] : [] }, { id: 'attendance', label: '考勤管理', icon: CalendarCheck, roles: [UserRole.TEACHER, UserRole.PRINCIPAL] }, { id: 'games', label: '互动教学', icon: Gamepad2, roles: [UserRole.TEACHER, UserRole.STUDENT] }, { id: 'wishes', label: '心愿与反馈', icon: MessageSquare, roles: [UserRole.ADMIN, UserRole.PRINCIPAL, UserRole.TEACHER, UserRole.STUDENT] }, { id: 'students', label: '学生管理', icon: Users, roles: [UserRole.ADMIN, UserRole.PRINCIPAL, UserRole.TEACHER] }, { id: 'classes', label: '班级管理', icon: School, roles: [UserRole.ADMIN, UserRole.PRINCIPAL] }, { id: 'schools', label: '学校管理', icon: Building, roles: [UserRole.ADMIN] }, { id: 'courses', label: '课程管理', icon: BookOpen, roles: [UserRole.ADMIN, UserRole.PRINCIPAL, UserRole.TEACHER] }, { id: 'grades', label: '成绩管理', icon: GraduationCap, roles: [UserRole.ADMIN, UserRole.PRINCIPAL, UserRole.TEACHER] }, { id: 'reports', label: '报表统计', icon: FileText, roles: [UserRole.ADMIN, UserRole.PRINCIPAL, UserRole.TEACHER, UserRole.STUDENT] }, { id: 'subjects', label: '学科设置', icon: Palette, roles: [UserRole.ADMIN, UserRole.PRINCIPAL, UserRole.TEACHER] }, { id: 'users', label: '用户管理', icon: UserCog, roles: [UserRole.ADMIN, UserRole.PRINCIPAL, UserRole.TEACHER] }, { id: 'profile', label: '个人中心', icon: UserCircle, roles: [UserRole.ADMIN, UserRole.PRINCIPAL, UserRole.TEACHER, UserRole.STUDENT] }, { id: 'settings', label: '系统设置', icon: Settings, roles: [UserRole.ADMIN, UserRole.PRINCIPAL] }, ]; const [menuItems, setMenuItems] = useState(defaultItems); const [isEditing, setIsEditing] = useState(false); const [installPrompt, setInstallPrompt] = useState(null); const [isStandalone, setIsStandalone] = useState(false); // Robust PWA Check useLayoutEffect(() => { const checkStandalone = () => { const isStandaloneMode = window.matchMedia('(display-mode: standalone)').matches || (window.navigator as any).standalone === true || document.referrer.includes('android-app://'); setIsStandalone(isStandaloneMode); }; checkStandalone(); window.matchMedia('(display-mode: standalone)').addEventListener('change', checkStandalone); return () => window.matchMedia('(display-mode: standalone)').removeEventListener('change', checkStandalone); }, []); // Capture PWA Prompt useEffect(() => { if ((window as any).deferredPrompt) { setInstallPrompt((window as any).deferredPrompt); } const handler = (e: any) => { e.preventDefault(); (window as any).deferredPrompt = e; setInstallPrompt(e); }; window.addEventListener('beforeinstallprompt', handler); return () => window.removeEventListener('beforeinstallprompt', handler); }, []); const handleInstallClick = async () => { const promptEvent = installPrompt || (window as any).deferredPrompt; if (!promptEvent) { alert('安装功能当前不可用。请尝试点击浏览器菜单中的“添加到主屏幕”或“安装应用”。'); return; } promptEvent.prompt(); const { outcome } = await promptEvent.userChoice; if (outcome === 'accepted') { setInstallPrompt(null); (window as any).deferredPrompt = null; } }; useEffect(() => { // Load saved order if (currentUser?.menuOrder && currentUser.menuOrder.length > 0) { const ordered: MenuItem[] = []; const map = new Map(defaultItems.map(i => [i.id, i])); // Add saved items in order currentUser.menuOrder.forEach(id => { if (map.has(id)) { ordered.push(map.get(id)!); map.delete(id); } }); // Append any new/remaining items map.forEach(item => ordered.push(item)); setMenuItems(ordered); } }, []); const handleMove = (index: number, direction: -1 | 1) => { const newItems = [...menuItems]; const targetIndex = index + direction; if (targetIndex < 0 || targetIndex >= newItems.length) return; [newItems[index], newItems[targetIndex]] = [newItems[targetIndex], newItems[index]]; setMenuItems(newItems); }; const saveOrder = async () => { setIsEditing(false); const orderIds = menuItems.map(i => i.id); if (currentUser && currentUser._id) { try { await api.users.saveMenuOrder(currentUser._id, orderIds); // Update local user object const updatedUser = { ...currentUser, menuOrder: orderIds }; localStorage.setItem('user', JSON.stringify(updatedUser)); } catch(e) { console.error("Failed to save menu order"); } } }; const sidebarClasses = ` fixed inset-y-0 left-0 z-50 w-64 bg-slate-900 text-white transition-transform duration-300 ease-in-out transform flex flex-col h-full ${isOpen ? 'translate-x-0' : '-translate-x-full'} lg:relative lg:translate-x-0 shadow-2xl lg:shadow-none `; return ( <> {isOpen &&
}
智慧校园
主菜单
{!isStandalone && ( <> {installPrompt ? ( ) : (
若未显示安装按钮:
iOS: 点击分享 → 添加到主屏幕
Android: 点击菜单 → 安装应用
)} )}
当前角色: {userRole === 'ADMIN' ? '超级管理员' : userRole === 'PRINCIPAL' ? '校长' : userRole === 'TEACHER' ? '教师' : '学生'}
); };