diff --git a/app/api/roles/promote/route.ts b/app/api/roles/promote/route.ts index 3590bd7..fe8219d 100644 --- a/app/api/roles/promote/route.ts +++ b/app/api/roles/promote/route.ts @@ -2,12 +2,16 @@ import { createDb } from "@/lib/db"; import { roles, userRoles } from "@/lib/schema"; import { eq } from "drizzle-orm"; import { ROLES } from "@/lib/permissions"; +import { assignRoleToUser } from "@/lib/auth"; export const runtime = "edge"; export async function POST(request: Request) { try { - const { userId, roleName } = await request.json() as { userId: string, roleName: string }; + const { userId, roleName } = await request.json() as { + userId: string, + roleName: typeof ROLES.KNIGHT | typeof ROLES.CIVILIAN + }; if (!userId || !roleName) { return Response.json( { error: "缺少必要参数" }, @@ -15,23 +19,23 @@ export async function POST(request: Request) { ); } - if (roleName !== ROLES.KNIGHT) { + if (![ROLES.KNIGHT, ROLES.CIVILIAN].includes(roleName)) { return Response.json( - { error: "只能册封骑士" }, + { error: "角色不合法" }, { status: 400 } ); } const db = createDb(); - const isEmperor = await db.query.userRoles.findFirst({ + const currentUserRole = await db.query.userRoles.findFirst({ where: eq(userRoles.userId, userId), with: { role: true, }, - }).then(userRole => userRole?.role.name === ROLES.EMPEROR); + }); - if (isEmperor) { + if (currentUserRole?.role.name === ROLES.EMPEROR) { return Response.json( { error: "不能降级皇帝" }, { status: 400 } @@ -43,29 +47,29 @@ export async function POST(request: Request) { }); if (!targetRole) { + const description = roleName === ROLES.KNIGHT + ? "高级用户" + : "普通用户"; + const [newRole] = await db.insert(roles) .values({ name: roleName, - description: "高级用户", + description, }) .returning(); targetRole = newRole; } - await db.delete(userRoles) - .where(eq(userRoles.userId, userId)); + await assignRoleToUser(db, userId, targetRole.id); - await db.insert(userRoles) - .values({ - userId, - roleId: targetRole.id, - }); - - return Response.json({ success: true }); + return Response.json({ + success: true, + message: roleName === ROLES.KNIGHT ? "册封成功" : "贬为平民" + }); } catch (error) { - console.error("Failed to promote user:", error); + console.error("Failed to change user role:", error); return Response.json( - { error: "升级用户失败" }, + { error: "操作失败" }, { status: 500 } ); } diff --git a/app/components/profile/promote-panel.tsx b/app/components/profile/promote-panel.tsx index c2d0e7d..e51e724 100644 --- a/app/components/profile/promote-panel.tsx +++ b/app/components/profile/promote-panel.tsx @@ -1,25 +1,25 @@ "use client" import { Button } from "@/components/ui/button" -import { Sword, Search, Loader2 } from "lucide-react" +import { Sword, Loader2, UserMinus } from "lucide-react" import { Input } from "@/components/ui/input" import { useState } from "react" import { useToast } from "@/components/ui/use-toast" import { ROLES } from "@/lib/permissions" - export function PromotePanel() { const [email, setEmail] = useState("") const [loading, setLoading] = useState(false) + const [action, setAction] = useState<"promote" | "demote">("promote") const { toast } = useToast() - const handlePromote = async () => { + const handleAction = async () => { if (!email) return setLoading(true) try { const res = await fetch(`/api/roles/users?email=${encodeURIComponent(email)}`) - const data = await res.json() as { user?: { id: string; name?: string; email: string }; error?: string } + const data = await res.json() as { user?: { id: string; name?: string; email: string; role?: string }; error?: string } if (!res.ok) throw new Error(data.error || '未知错误') if (!data.user) { @@ -31,26 +31,43 @@ export function PromotePanel() { return } + if (action === "promote" && data.user.role === ROLES.KNIGHT) { + toast({ + title: "用户已是骑士", + description: "无需重复册封", + }) + return + } + + if (action === "demote" && data.user.role === ROLES.CIVILIAN) { + toast({ + title: "用户已是平民", + description: "无需重复贬为平民", + }) + return + } + const promoteRes = await fetch('/api/roles/promote', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userId: data.user.id, - roleName: ROLES.KNIGHT + roleName: action === "promote" ? ROLES.KNIGHT : ROLES.CIVILIAN }) }) - if (!promoteRes.ok) throw new Error('册封失败') + const result = await promoteRes.json() as { error: string } + if (!promoteRes.ok) throw new Error(result.error) toast({ - title: "册封成功", - description: `已将 ${data.user.email} 册封为骑士` + title: action === "promote" ? "册封成功" : "贬为平民", + description: `已将 ${data.user.email} ${action === "promote" ? "册封为骑士" : "贬为平民"}` }) setEmail("") } catch (error) { toast({ - title: "册封失败", + title: "操作失败", description: error instanceof Error ? error.message : "请稍后重试", variant: "destructive" }) @@ -63,10 +80,10 @@ export function PromotePanel() {
-

册封骑士

+

角色管理

-
+
- +
+ + +
) diff --git a/app/profile/page.tsx b/app/profile/page.tsx index 260c449..543dc9d 100644 --- a/app/profile/page.tsx +++ b/app/profile/page.tsx @@ -13,13 +13,11 @@ export default async function ProfilePage() { } return ( -
-
+
+
-
-
- -
+
+