Files
Genarrative/apps/admin-web/src/app/adminRoutes.ts
T
k88936 48b6880955 修复(后台导航): 会员档位路由补入充值分组
- 将 membership-plans 加入 adminNavGroups 的 billing 分组,桌面端侧边栏不再漏掉「会员档位」入口
2026-10-05 11:55:29 +08:00

213 lines
6.1 KiB
TypeScript

/** 后台单页应用可导航的路由标识。 */
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'
);
}