Files
jiang13-bbs/frontend/components/RoleBadge.tsx
freefire a7b6421840 feat: 实现完整的板块级RBAC内容审核系统
- 新增站长/超级管理员/管理员/板块管理员四级角色体系
- 实现实时权限快照加载与细粒度权限校验
- 新增内容审核队列与前后端页面
- 重构用户权限管理与站点管理逻辑
- 新增评论/帖子审核状态与通知推送
- 优化前端权限控制与角色徽章展示
- 修正数据库迁移与默认值问题
2026-09-15 04:47:34 +08:00

71 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"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>
);
}