feat: 重构用户角色系统为管理员标识

- 将用户角色字段从role改为is_admin布尔值
- 更新相关API权限检查逻辑
- 修改数据库schema和迁移文件
- 调整前端用户显示逻辑
- 添加API响应工具函数
- 优化权限检查中间件
- 重构英雄组件为原子组件
This commit is contained in:
张翔
2026-03-12 20:45:43 +08:00
parent b207bfa7af
commit f357330ba8
22 changed files with 1078 additions and 552 deletions
+23 -33
View File
@@ -1,21 +1,16 @@
import { NextRequest, NextResponse } from 'next/server';
import { auth } from '@/lib/auth';
import { hasPermission } from '@/lib/auth/permissions';
import { NextRequest } from 'next/server';
import { checkIsAdmin, getAdminUserId } from '@/lib/auth/check-permission';
import { createAuditLog } from '@/lib/audit';
import { uploadFile, deleteFile } from '@/lib/upload';
import { forbidden, badRequest, notFound, success, handleApiError } from '@/lib/api-response';
export async function POST(request: NextRequest) {
try {
const session = await auth();
const { isAdmin } = await checkIsAdmin();
const userId = await getAdminUserId();
if (!session?.user) {
return NextResponse.json({ error: '未授权' }, { status: 401 });
}
const userRole = session.user.role as 'admin' | 'editor' | 'viewer';
if (!hasPermission(userRole, 'content', 'create')) {
return NextResponse.json({ error: '无权限' }, { status: 403 });
if (!isAdmin || !userId) {
return forbidden();
}
const formData = await request.formData();
@@ -23,16 +18,16 @@ export async function POST(request: NextRequest) {
const type = (formData.get('type') as 'image' | 'document') || 'image';
if (!file) {
return NextResponse.json({ error: '未找到文件' }, { status: 400 });
return badRequest('未找到文件');
}
const result = await uploadFile(file, {
type,
userId: session.user.id,
userId,
});
await createAuditLog({
userId: session.user.id,
userId,
action: 'upload',
resourceType: 'file',
resourceId: result.id,
@@ -44,7 +39,7 @@ export async function POST(request: NextRequest) {
},
});
return NextResponse.json({
return success({
success: true,
file: result,
});
@@ -52,43 +47,38 @@ export async function POST(request: NextRequest) {
console.error('文件上传失败:', error);
if (error instanceof Error) {
return NextResponse.json({ error: error.message }, { status: 400 });
return badRequest(error.message);
}
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
return handleApiError(error);
}
}
export async function DELETE(request: NextRequest) {
try {
const session = await auth();
const { isAdmin } = await checkIsAdmin();
const userId = await getAdminUserId();
if (!session?.user) {
return NextResponse.json({ error: '未授权' }, { status: 401 });
}
const userRole = session.user.role as 'admin' | 'editor' | 'viewer';
if (!hasPermission(userRole, 'content', 'delete')) {
return NextResponse.json({ error: '无权限' }, { status: 403 });
if (!isAdmin || !userId) {
return forbidden();
}
const { searchParams } = new URL(request.url);
const fileUrl = searchParams.get('url');
if (!fileUrl) {
return NextResponse.json({ error: '缺少文件 URL' }, { status: 400 });
return badRequest('缺少文件 URL');
}
const success = await deleteFile(fileUrl);
const result = await deleteFile(fileUrl);
if (!success) {
return NextResponse.json({ error: '文件不存在或删除失败' }, { status: 404 });
if (!result) {
return notFound('文件不存在或删除失败');
}
return NextResponse.json({ success: true });
return success({ success: true });
} catch (error) {
console.error('文件删除失败:', error);
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
return handleApiError(error);
}
}