"""admin 后台「页面权限目录」—— RBAC 的权限侧单一真源。 一个权限 = 一个页面(= 左侧导航项)。角色持有一组 page key,登录后左侧只展示这些页(见前端 layout.tsx 按 pages 过滤导航)。key 必须与前端路由一级对齐(/dashboard → "dashboard")。 super_admin 为内建全权角色,恒可见全部页(effective_pages 特判)。新增页面 = 这里加一条 + 前端导航加对应项(key 一致即可被各角色勾选可见)。 """ from __future__ import annotations SUPER_ADMIN_ROLE = "super_admin" # 分组镜像前端导航(app/(main)/layout.tsx 的 NAV_GROUPS);key = 路由一级 PERMISSION_CATALOG: list[dict] = [ {"group": "看板", "pages": [ {"key": "dashboard", "label": "数据大盘"}, {"key": "coupon-data", "label": "领券数据"}, {"key": "ad-revenue-report", "label": "广告收益"}, {"key": "comparison-records", "label": "比价记录"}, {"key": "cps", "label": "CPS收益"}, {"key": "device-liveness", "label": "设备存活"}, ]}, {"group": "奖励审核", "pages": [ {"key": "withdraws", "label": "提现审核"}, {"key": "price-reports", "label": "低价审核"}, {"key": "feedbacks", "label": "用户反馈"}, ]}, {"group": "数据配置", "pages": [ {"key": "config", "label": "系统配置"}, {"key": "ad-revenue", "label": "广告配置"}, {"key": "users", "label": "用户管理"}, ]}, {"group": "其他", "pages": [ {"key": "admins", "label": "权限管理"}, {"key": "event-logs", "label": "埋点日志"}, {"key": "audit-logs", "label": "审计日志"}, ]}, ] # 全部页面 key(super_admin 有效可见 = 此全集;也用于校验角色 pages 合法性) ALL_PAGE_KEYS: list[str] = [p["key"] for g in PERMISSION_CATALOG for p in g["pages"]] _ALL_SET = set(ALL_PAGE_KEYS) # 内建角色定义(种子 / ensure 兜底的单一真源):(key, 中文展示名, 默认可见页)。 # 页集对齐 Prototypes/dashboard/permissions.md 的 ROLES;super_admin 恒全权(pages 空、bypass)。 # key 承重(require_role / admin_user.role),勿改;label 为 UI 展示名。 BUILTIN_ROLES: list[dict] = [ {"name": SUPER_ADMIN_ROLE, "label": "管理员", "pages": []}, {"name": "operator", "label": "运营", "pages": [ "dashboard", "coupon-data", "ad-revenue-report", "comparison-records", "cps", "device-liveness", "price-reports", "feedbacks", ]}, {"name": "finance", "label": "财务", "pages": [ "dashboard", "ad-revenue-report", "cps", "withdraws", ]}, {"name": "tech", "label": "技术", "pages": [ "dashboard", "device-liveness", "config", "ad-revenue", "event-logs", "audit-logs", ]}, ] # 内建 key → 中文展示名(展示 / 自愈用) BUILTIN_LABELS: dict[str, str] = {r["name"]: r["label"] for r in BUILTIN_ROLES} def sanitize_pages(pages: list[str] | None) -> list[str]: """过滤掉不在目录里的 key(去重、保序),防脏数据/目录收缩后的悬空 key。""" seen: set[str] = set() out: list[str] = [] for k in pages or []: if k in _ALL_SET and k not in seen: seen.add(k) out.append(k) return out def effective_pages(role_name: str, role_pages: list[str] | None) -> list[str]: """某角色的有效可见页:super_admin → 全部;其余 → 其 pages 与目录取交(自愈悬空 key)。""" if role_name == SUPER_ADMIN_ROLE: return list(ALL_PAGE_KEYS) return sanitize_pages(role_pages)