fix bug
This commit is contained in:
parent
55fd44ed87
commit
b97e1de2a7
@ -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
|
||||
|
||||
@ -481,23 +481,27 @@ export default function MembersPage() {
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Select
|
||||
value={m.role}
|
||||
onValueChange={(v) => v && handleRoleChange(m.id, v)}
|
||||
>
|
||||
<SelectTrigger className="w-28 h-7 text-xs">
|
||||
<SelectValue>
|
||||
{ROLES[m.role as keyof typeof ROLES] || m.role}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="student">同学</SelectItem>
|
||||
<SelectItem value="class_admin">班级管理员</SelectItem>
|
||||
{isSuperAdmin && (
|
||||
{isSuperAdmin ? (
|
||||
<Select
|
||||
value={m.role}
|
||||
onValueChange={(v) => v && handleRoleChange(m.id, v)}
|
||||
>
|
||||
<SelectTrigger className="w-28 h-7 text-xs">
|
||||
<SelectValue>
|
||||
{ROLES[m.role as keyof typeof ROLES] || m.role}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="student">同学</SelectItem>
|
||||
<SelectItem value="class_admin">班级管理员</SelectItem>
|
||||
<SelectItem value="super_admin">超级管理员</SelectItem>
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
) : (
|
||||
<Badge variant="outline">
|
||||
{ROLES[m.role as keyof typeof ROLES] || m.role}
|
||||
</Badge>
|
||||
)}
|
||||
{getStatusBadge(m.status)}
|
||||
{m.status === "approved" && (
|
||||
<Button
|
||||
|
||||
@ -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,41 +85,43 @@ export function Sidebar() {
|
||||
</Link>
|
||||
))}
|
||||
|
||||
<RoleGuard roles={["super_admin", "class_admin"]}>
|
||||
<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) => (
|
||||
<Link
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
onClick={close}
|
||||
className={cn(
|
||||
"flex items-center gap-3 px-3 py-2 rounded-lg text-sm transition-colors",
|
||||
pathname.startsWith(item.href)
|
||||
? "bg-gray-900 text-white"
|
||||
: "text-gray-600 hover:bg-gray-100"
|
||||
)}
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5 shrink-0"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
{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>
|
||||
{visibleAdminItems.map((item) => (
|
||||
<Link
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
onClick={close}
|
||||
className={cn(
|
||||
"flex items-center gap-3 px-3 py-2 rounded-lg text-sm transition-colors",
|
||||
pathname.startsWith(item.href)
|
||||
? "bg-gray-900 text-white"
|
||||
: "text-gray-600 hover:bg-gray-100"
|
||||
)}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={1.5}
|
||||
d={item.icon}
|
||||
/>
|
||||
</svg>
|
||||
{item.label}
|
||||
</Link>
|
||||
))}
|
||||
</RoleGuard>
|
||||
<svg
|
||||
className="w-5 h-5 shrink-0"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={1.5}
|
||||
d={item.icon}
|
||||
/>
|
||||
</svg>
|
||||
{item.label}
|
||||
</Link>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</nav>
|
||||
|
||||
<div className="p-4 border-t border-gray-200">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user