/** 后台单页应用可导航的路由标识。 */ export type AdminRouteId = | 'dashboard' | 'overview' | 'tables' | 'debug' | 'tracking' | 'agc-tracking' | 'error-reports' | 'gray-release' | 'redeem' | 'invite' | 'profile-wallet' | 'tasks' | 'recharge-products' | 'membership-plans' | 'recharge-orders' | 'payment-orders' | 'editor-generation-pricing' | 'editor-showcase' | 'game-distribution' | 'game-management' | 'game-reviews' | 'editor-assets' | 'project-snapshots' | 'agc-models' | 'agc-templates' | 'accounts'; export type AdminTabPermission = Exclude< AdminRouteId, 'accounts' | 'agc-models' >; /** 后台导航项定义,hash 是浏览器地址栏和移动底栏共用入口。 */ export interface AdminRouteDefinition { id: AdminRouteId; label: string; hash: string; ownerOnly?: boolean; } export const adminRoutes: AdminRouteDefinition[] = [ { id: 'dashboard', label: 'Dashboard', hash: '#dashboard' }, { id: 'overview', label: '服务总览', hash: '#overview' }, { id: 'tables', label: '表查询', hash: '#tables' }, { id: 'debug', label: 'API 调试', hash: '#debug' }, { id: 'tracking', label: '埋点数据', hash: '#tracking' }, { id: 'agc-tracking', label: '客户端埋点', hash: '#agc-tracking' }, { id: 'error-reports', label: '错误报告', hash: '#error-reports' }, { id: 'gray-release', label: '灰度发布', hash: '#gray-release' }, { id: 'redeem', label: '兑换码', hash: '#redeem' }, { id: 'invite', label: '邀请码', hash: '#invite' }, { id: 'profile-wallet', label: '账号配置', hash: '#profile-wallet' }, { id: 'tasks', label: '任务配置', hash: '#tasks' }, { id: 'recharge-products', label: '充值商品', hash: '#recharge-products' }, { id: 'membership-plans', label: '会员档位', hash: '#membership-plans' }, { id: 'recharge-orders', label: '充值管理', hash: '#recharge-orders' }, { id: 'payment-orders', label: '支付订单', hash: '#payment-orders' }, { id: 'editor-generation-pricing', label: '模型定价', hash: '#editor-generation-pricing', }, { id: 'agc-models', label: 'AGC 模型', hash: '#agc-models', ownerOnly: true }, { id: 'agc-templates', label: '模板管理', hash: '#agc-templates' }, { id: 'editor-showcase', label: '精选审核', hash: '#editor-showcase' }, { id: 'game-distribution', label: '游戏审核', hash: '#game-distribution' }, { id: 'game-management', label: '游戏管理', hash: '#game-management' }, { id: 'game-reviews', label: '游戏评价', hash: '#game-reviews' }, { id: 'editor-assets', label: '素材查询', hash: '#editor-assets' }, { id: 'project-snapshots', label: '项目工程', hash: '#project-snapshots' }, { id: 'accounts', label: '账号管理', hash: '#accounts', ownerOnly: true }, ]; /** * 桌面端侧边栏的导航分组。分组只影响展示顺序和折叠状态,不改变路由 * 权限、hash 或移动端底栏的平铺顺序。 */ export type AdminNavGroupId = | 'workspace' | 'observability' | 'operations' | 'billing' | 'content' | 'agc' | 'access'; export interface AdminNavGroupDefinition { id: AdminNavGroupId; label: string; routeIds: AdminRouteId[]; } export const adminNavGroups: AdminNavGroupDefinition[] = [ { id: 'workspace', label: '工作台', routeIds: ['dashboard', 'overview', 'tables', 'debug'], }, { id: 'observability', label: '数据与监控', routeIds: ['tracking', 'agc-tracking', 'error-reports'], }, { id: 'operations', label: '运营配置', routeIds: ['gray-release', 'redeem', 'invite', 'profile-wallet', 'tasks'], }, { id: 'billing', label: '充值与支付', routeIds: [ 'recharge-products', 'membership-plans', 'recharge-orders', 'payment-orders', ], }, { id: 'agc', label: 'AGC 管理', routeIds: ['editor-generation-pricing', 'agc-models', 'agc-templates'], }, { id: 'content', label: '内容运营', routeIds: [ 'editor-showcase', 'game-distribution', 'game-management', 'game-reviews', 'editor-assets', 'project-snapshots', ], }, { id: 'access', label: '账号权限', routeIds: ['accounts'], }, ]; export interface AdminNavGroup { id: AdminNavGroupId; label: string; routes: AdminRouteDefinition[]; } /** 按固定业务分组筛选当前管理员可见的路由。 */ export function getAdminNavGroups( routes: AdminRouteDefinition[], ): AdminNavGroup[] { return adminNavGroups .map((group) => ({ id: group.id, label: group.label, routes: group.routeIds .map((routeId) => routes.find((route) => route.id === routeId)) .filter((route): route is AdminRouteDefinition => route !== undefined), })) .filter((group) => group.routes.length > 0); } export interface AdminRouteAccess { accountRole: 'owner' | 'member'; tabPermissions: string[]; } export function getAccessibleAdminRoutes( admin: AdminRouteAccess, ): AdminRouteDefinition[] { if (admin.accountRole === 'owner') { return adminRoutes; } const permissions = new Set(admin.tabPermissions); return adminRoutes.filter( (route) => !route.ownerOnly && permissions.has(route.id), ); } export function resolveAccessibleAdminRoute( hash: string, routes: AdminRouteDefinition[], ): AdminRouteId | null { const normalizedHash = hash.trim().toLowerCase().split('?')[0] ?? ''; return ( routes.find((route) => route.hash === normalizedHash)?.id ?? routes[0]?.id ?? null ); } /** 根据地址栏 hash 解析后台路由,未知 hash 回落到 Dashboard。 */ export function resolveAdminRoute(hash: string): AdminRouteId { const normalizedHash = hash.trim().toLowerCase().split('?')[0] ?? ''; return ( adminRoutes.find((route) => route.hash === normalizedHash)?.id ?? 'dashboard' ); } /** 根据后台路由标识反查 hash,供导航点击时同步地址栏。 */ export function routeHash(routeId: AdminRouteId) { return ( adminRoutes.find((route) => route.id === routeId)?.hash ?? adminRoutes[0]?.hash ?? '#dashboard' ); }