Files
jiang13-bbs/frontend/lib/roles.ts
freefire 42c395a864 feat: 实时消息与管理端运营能力
新增群聊/私信与公共 WebSocket 总线,站长用户内容档案,并将通知与待审角标改为推送驱动;同步精简管理仪表盘并修复主题换肤 DOM 冲突。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 22:58:16 +08:00

133 lines
4.0 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.
// 角色与权限中枢:与后端 model.Role / service.Actor 保持单一对应关系。
// 前端只做"是否展示入口/按钮"的判定,所有最终权限以后端校验为准。
export const ROLES = {
USER: "user",
BOARD_ADMIN: "board_admin",
ADMIN: "admin",
SUPER_ADMIN: "super_admin",
OWNER: "owner",
} as const;
export type RoleKey = (typeof ROLES)[keyof typeof ROLES];
// 角色等级(与后端 model.RoleLevel 一致),未知角色按普通用户处理
export const ROLE_LEVEL: Record<string, number> = {
[ROLES.USER]: 0,
[ROLES.BOARD_ADMIN]: 30,
[ROLES.ADMIN]: 50,
[ROLES.SUPER_ADMIN]: 80,
[ROLES.OWNER]: 100,
};
export function roleLevel(role?: string | null): number {
return ROLE_LEVEL[role ?? ""] ?? 0;
}
/** 管理团队成员(板块管理员及以上) */
export function isStaff(role?: string | null): boolean {
return roleLevel(role) >= ROLE_LEVEL[ROLES.BOARD_ADMIN];
}
/** 管理员及以上(全站内容管理:置顶/加精/公告) */
export function isAdminOrAbove(role?: string | null): boolean {
return roleLevel(role) >= ROLE_LEVEL[ROLES.ADMIN];
}
/** 超级管理员及以上(用户与权限、站点设置) */
export function isSuperOrOwner(role?: string | null): boolean {
return roleLevel(role) >= ROLE_LEVEL[ROLES.SUPER_ADMIN];
}
/** 站长(站点所有者) */
export function isOwner(role?: string | null): boolean {
return role === ROLES.OWNER;
}
/** 站长/超管:群聊监管旁路(可见全部群、撤回任意消息) */
export function canOverseeChat(role?: string | null): boolean {
return role === ROLES.OWNER || role === ROLES.SUPER_ADMIN;
}
/** 携带板块授权的最小用户形状(/me、帖子详情作者等均满足) */
export interface RoleUserLike {
role?: string | null;
board_ids?: number[] | null;
}
/**
* 能否管理指定板块的内容(帖子/评论的编辑删除审核):
* 管理员及以上不限板块;板块管理员仅限被授权板块
*/
export function canModerateBoard(
user: RoleUserLike | null | undefined,
boardId: number | null | undefined
): boolean {
if (!user) return false;
if (isAdminOrAbove(user.role)) return true;
if (user.role !== ROLES.BOARD_ADMIN || !boardId) return false;
return (user.board_ids ?? []).includes(boardId);
}
/** 是否拥有任意板块的内容审核权(后台"内容审核"入口) */
export function canModerateAny(user: RoleUserLike | null | undefined): boolean {
if (!user) return false;
if (isAdminOrAbove(user.role)) return true;
return user.role === ROLES.BOARD_ADMIN && (user.board_ids?.length ?? 0) > 0;
}
/** 角色图标 key(RoleBadge 负责映射到具体图标,集中配置便于替换) */
export type RoleIconKey = "crown" | "shield-star" | "shield" | "shield-board" | "user";
export interface RoleMeta {
key: RoleKey;
label: string;
icon: RoleIconKey;
/** 主色使用的 CSS token 名(RoleBadge 取 var(--token)) */
colorToken: string;
softToken: string;
}
// 各管理角色的图标与配色集中配置;站长固定使用皇冠站长标识
export const ROLE_META: Record<RoleKey, RoleMeta> = {
[ROLES.OWNER]: {
key: ROLES.OWNER,
label: "站长",
icon: "crown",
colorToken: "--gold",
softToken: "--gold-soft",
},
[ROLES.SUPER_ADMIN]: {
key: ROLES.SUPER_ADMIN,
label: "超级管理员",
icon: "shield-star",
colorToken: "--accent",
softToken: "--accent-soft",
},
[ROLES.ADMIN]: {
key: ROLES.ADMIN,
label: "管理员",
icon: "shield",
colorToken: "--accent",
softToken: "--accent-soft",
},
[ROLES.BOARD_ADMIN]: {
key: ROLES.BOARD_ADMIN,
label: "板块管理员",
icon: "shield-board",
colorToken: "--accent",
softToken: "--accent-soft",
},
[ROLES.USER]: {
key: ROLES.USER,
label: "普通用户",
icon: "user",
colorToken: "--ink-3",
softToken: "--panel-2",
},
};
export function roleMeta(role?: string | null): RoleMeta {
return ROLE_META[(role as RoleKey)] ?? ROLE_META.user;
}