This commit is contained in:
aaron 2026-04-12 20:15:04 +08:00
parent 55fd44ed87
commit b97e1de2a7
3 changed files with 70 additions and 53 deletions

View File

@ -95,6 +95,12 @@ async def change_user_status(
status_code=403, detail="Cannot manage users outside your class"
)
# Only super_admin can change roles
if data.role and admin.role != "super_admin":
raise HTTPException(
status_code=403, detail="Only super admin can change user roles"
)
updated = await update_user_status(db, user_id, data.status, data.role)
# Send email notification

View File

@ -481,6 +481,7 @@ export default function MembersPage() {
</p>
</div>
<div className="flex items-center gap-2">
{isSuperAdmin ? (
<Select
value={m.role}
onValueChange={(v) => v && handleRoleChange(m.id, v)}
@ -493,11 +494,14 @@ export default function MembersPage() {
<SelectContent>
<SelectItem value="student"></SelectItem>
<SelectItem value="class_admin"></SelectItem>
{isSuperAdmin && (
<SelectItem value="super_admin"></SelectItem>
)}
</SelectContent>
</Select>
) : (
<Badge variant="outline">
{ROLES[m.role as keyof typeof ROLES] || m.role}
</Badge>
)}
{getStatusBadge(m.status)}
{m.status === "approved" && (
<Button

View File

@ -3,8 +3,9 @@
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useSidebar } from "@/hooks/use-sidebar";
import { RoleGuard } from "@/components/role-guard";
import { cn } from "@/lib/utils";
import type { UserRole } from "@/lib/types";
import { useAuth } from "@/hooks/use-auth";
const navItems = [
{ href: "/dashboard", label: "首页", icon: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" },
@ -19,13 +20,17 @@ const navItems = [
];
const adminItems = [
{ href: "/admin/members", label: "成员管理", icon: "M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" },
{ href: "/admin/classes", label: "班级管理", icon: "M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" },
{ href: "/admin/members", label: "成员管理", icon: "M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z", roles: ["super_admin", "class_admin"] as UserRole[] },
{ href: "/admin/classes", label: "班级管理", icon: "M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4", roles: ["super_admin"] as UserRole[] },
];
export function Sidebar() {
const pathname = usePathname();
const { isOpen, close } = useSidebar();
const { user } = useAuth();
const visibleAdminItems = user
? adminItems.filter((item) => item.roles.includes(user.role))
: [];
return (
<>
@ -80,13 +85,14 @@ export function Sidebar() {
</Link>
))}
<RoleGuard roles={["super_admin", "class_admin"]}>
{visibleAdminItems.length > 0 && (
<>
<div className="pt-4 pb-2">
<p className="px-3 text-xs font-semibold text-gray-400 uppercase tracking-wider">
</p>
</div>
{adminItems.map((item) => (
{visibleAdminItems.map((item) => (
<Link
key={item.href}
href={item.href}
@ -114,7 +120,8 @@ export function Sidebar() {
{item.label}
</Link>
))}
</RoleGuard>
</>
)}
</nav>
<div className="p-4 border-t border-gray-200">