feat: 实现完整的板块级RBAC内容审核系统
- 新增站长/超级管理员/管理员/板块管理员四级角色体系 - 实现实时权限快照加载与细粒度权限校验 - 新增内容审核队列与前后端页面 - 重构用户权限管理与站点管理逻辑 - 新增评论/帖子审核状态与通知推送 - 优化前端权限控制与角色徽章展示 - 修正数据库迁移与默认值问题
This commit is contained in:
70
frontend/components/RoleBadge.tsx
Normal file
70
frontend/components/RoleBadge.tsx
Normal file
@@ -0,0 +1,70 @@
|
||||
"use client";
|
||||
|
||||
import { Crown, BadgeCheck, ShieldCheck, Shield, Users, type LucideIcon } from "lucide-react";
|
||||
import { roleMeta, type RoleIconKey } from "@/lib/roles";
|
||||
|
||||
// 角色图标集中映射(图标库不含 ShieldStar,超管使用 BadgeCheck 表达"全权限认证")
|
||||
const ICONS: Record<RoleIconKey, LucideIcon> = {
|
||||
crown: Crown,
|
||||
"shield-star": BadgeCheck,
|
||||
shield: ShieldCheck,
|
||||
"shield-board": Shield,
|
||||
user: Users,
|
||||
};
|
||||
|
||||
/**
|
||||
* 角色徽章:图标 + 文案,配色走角色元数据中的 CSS token。
|
||||
* - board_admin 额外展示授权板块数(或板块名)
|
||||
* - variant=plain 时仅图标+文字不着底色(用于表头/文本行)
|
||||
*/
|
||||
export default function RoleBadge({
|
||||
role,
|
||||
boardIds,
|
||||
boardNames,
|
||||
size = 11,
|
||||
className = "",
|
||||
title,
|
||||
truncate = false,
|
||||
}: {
|
||||
role?: string | null;
|
||||
boardIds?: number[] | null;
|
||||
/** id -> 名称映射;提供时板块管理员展示板块名(多选时折叠为 N 个板块) */
|
||||
boardNames?: Map<number, string> | Record<number, string>;
|
||||
size?: number;
|
||||
className?: string;
|
||||
title?: string;
|
||||
/** 窄列场景:限制最大宽度并省略过长文案 */
|
||||
truncate?: boolean;
|
||||
}) {
|
||||
const meta = roleMeta(role);
|
||||
const Icon = ICONS[meta.icon];
|
||||
|
||||
let label = meta.label;
|
||||
if (role === "board_admin") {
|
||||
if (boardNames) {
|
||||
const names = (boardIds ?? [])
|
||||
.map((id) => (boardNames instanceof Map ? boardNames.get(id) : boardNames[id]))
|
||||
.filter(Boolean) as string[];
|
||||
if (names.length === 1) {
|
||||
label = `${meta.label} · ${names[0]}`;
|
||||
} else if (names.length > 1) {
|
||||
label = `${meta.label} · ${names.length} 个板块`;
|
||||
}
|
||||
} else if (boardIds && boardIds.length > 0) {
|
||||
label = `${meta.label} · ${boardIds.length} 个板块`;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<span
|
||||
className={`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[11px] font-bold leading-[1.6] ${
|
||||
truncate ? "max-w-full whitespace-nowrap" : "whitespace-nowrap"
|
||||
} ${className}`}
|
||||
style={{ background: `var(${meta.softToken})`, color: `var(${meta.colorToken})` }}
|
||||
title={title ?? label}
|
||||
>
|
||||
<Icon size={size} className="shrink-0" />
|
||||
{truncate ? <span className="overflow-hidden text-ellipsis">{label}</span> : label}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user