空切片 JSON 统一为数组;撤回保留正文供站长阅读,成员侧居中提示与重新编辑;头像支持拖放;角色弹窗补全职责说明并汇入封禁。 Co-authored-by: Cursor <cursoragent@cursor.com>
148 lines
5.0 KiB
TypeScript
148 lines
5.0 KiB
TypeScript
// 角色与权限中枢:与后端 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;
|
||
/**
|
||
* 授权弹窗用的职责说明(站长不出现在可授权列表)。
|
||
* 只描述该角色「有什么」,最终权限以后端为准。
|
||
*/
|
||
grantDesc?: string;
|
||
}
|
||
|
||
// 各管理角色的图标与配色集中配置;站长固定使用皇冠站长标识
|
||
export const ROLE_META: Record<RoleKey, RoleMeta> = {
|
||
[ROLES.OWNER]: {
|
||
key: ROLES.OWNER,
|
||
label: "站长",
|
||
icon: "crown",
|
||
colorToken: "--gold",
|
||
softToken: "--gold-soft",
|
||
grantDesc:
|
||
"站点所有者:全部后台能力、群聊监管、用户内容档案;身份不可授予或降级。",
|
||
},
|
||
[ROLES.SUPER_ADMIN]: {
|
||
key: ROLES.SUPER_ADMIN,
|
||
label: "超级管理员",
|
||
icon: "shield-star",
|
||
colorToken: "--accent",
|
||
softToken: "--accent-soft",
|
||
grantDesc:
|
||
"用户与角色管理、封禁、外观主题、公告;全站内容审核与置顶/加精;群聊监管(可见全部会话、可撤回任意消息)。不可动站长账号,亦无站长专属的用户内容档案。",
|
||
},
|
||
[ROLES.ADMIN]: {
|
||
key: ROLES.ADMIN,
|
||
label: "管理员",
|
||
icon: "shield",
|
||
colorToken: "--accent",
|
||
softToken: "--accent-soft",
|
||
grantDesc:
|
||
"公告管理;全站帖子/评论审核;前台置顶与加精。不含用户权限、外观设置与群聊监管旁路。",
|
||
},
|
||
[ROLES.BOARD_ADMIN]: {
|
||
key: ROLES.BOARD_ADMIN,
|
||
label: "板块管理员",
|
||
icon: "shield-board",
|
||
colorToken: "--accent",
|
||
softToken: "--accent-soft",
|
||
grantDesc:
|
||
"仅审核并管理被授权板块内的帖子与评论(含删除违规内容)。无公告、置顶/加精、用户管理与外观设置;须至少勾选一个板块。",
|
||
},
|
||
[ROLES.USER]: {
|
||
key: ROLES.USER,
|
||
label: "普通用户",
|
||
icon: "user",
|
||
colorToken: "--ink-3",
|
||
softToken: "--panel-2",
|
||
grantDesc:
|
||
"无任何后台入口。可发帖、评论、私信等;新帖与评论按站点规则进入审核。降级为普通用户时会清空板块授权。",
|
||
},
|
||
};
|
||
|
||
export function roleMeta(role?: string | null): RoleMeta {
|
||
return ROLE_META[(role as RoleKey)] ?? ROLE_META.user;
|
||
}
|