app-sidebar.component.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import { Component, EventEmitter, Input, Output, inject } from '@angular/core';
  2. import { CommonModule } from '@angular/common';
  3. import { AuthCreditService } from '../../services/auth-credit.service';
  4. /**
  5. * 全局侧栏 — 3 大分区纯字排版
  6. *
  7. * 01 / 创作 生成相关(pipeline hub + 6 个生成模式)
  8. * 02 / 资产 任务 / 历史 / 结果 / 视频库
  9. * 03 / 发现 视频发现 / 博主监测 / 语音合成
  10. *
  11. * 设计立场:纯字排版,零图标,分区编号用 Fraunces 衬线斜体小号字,
  12. * 二级条目仅文本 + 左侧 2px 高亮竖线(active 时出现),与传统 SaaS 图标列表拉开差距。
  13. */
  14. export interface SidebarItem {
  15. tab: string;
  16. label: string;
  17. badge?: string;
  18. }
  19. export interface SidebarZone {
  20. key: string;
  21. serial: string;
  22. label: string;
  23. items: SidebarItem[];
  24. }
  25. const ZONES: SidebarZone[] = [
  26. {
  27. key: 'create',
  28. serial: '01',
  29. label: '创作',
  30. items: [
  31. { tab: 'home', label: '首页' },
  32. { tab: 'pipelines', label: '生成模式中心' },
  33. { tab: 'batch-production', label: '批量生产' },
  34. { tab: 'image-generation', label: '图片生成' },
  35. { tab: 'topic-to-video', label: '主题生视频' },
  36. { tab: 'image-to-video', label: '图生视频' },
  37. { tab: 'digital-human', label: '数字人合成' },
  38. { tab: 'action-transfer', label: '动作迁移' },
  39. { tab: 'asset-remix', label: '素材合成视频' },
  40. { tab: 'video-generation', label: '标准视频生成' },
  41. ],
  42. },
  43. {
  44. key: 'assets',
  45. serial: '02',
  46. label: '资产',
  47. items: [
  48. { tab: 'drafts', label: '我的创作' },
  49. { tab: 'library', label: '素材库' },
  50. { tab: 'templates', label: '模板库' },
  51. // 老入口保留作为兼容(后续版本可移除)
  52. { tab: 'videos', label: '视频管理' },
  53. { tab: 'tasks', label: '任务管理' },
  54. ],
  55. },
  56. {
  57. key: 'discover',
  58. serial: '03',
  59. label: '发现',
  60. items: [
  61. { tab: 'search', label: '视频发现' },
  62. { tab: 'monitor', label: '博主监测' },
  63. { tab: 'topic-pool', label: '选题池' },
  64. { tab: 'retrospective', label: '发布复盘' },
  65. { tab: 'analysis-history', label: '分析历史' },
  66. { tab: 'daily-reports', label: '日报历史' },
  67. { tab: 'voice-synthesis', label: '语音合成' },
  68. ],
  69. },
  70. {
  71. key: 'account',
  72. serial: '04',
  73. label: '账号',
  74. items: [
  75. { tab: 'user-center', label: '用户中心' },
  76. { tab: 'admin-users', label: '账号明细' },
  77. ],
  78. },
  79. ];
  80. @Component({
  81. selector: 'app-sidebar',
  82. standalone: true,
  83. imports: [CommonModule],
  84. templateUrl: './app-sidebar.component.html',
  85. styleUrls: ['./app-sidebar.component.css'],
  86. })
  87. export class AppSidebarComponent {
  88. @Input() currentTab: string = '';
  89. @Output() tabChange = new EventEmitter<string>();
  90. private readonly auth = inject(AuthCreditService);
  91. get zones(): SidebarZone[] {
  92. if (this.auth.isAdmin) return ZONES;
  93. return ZONES
  94. .map((zone) => ({
  95. ...zone,
  96. items: zone.items.filter((item) => item.tab !== 'admin-users'),
  97. }))
  98. .filter((zone) => zone.items.length > 0);
  99. }
  100. /** trackBy 减少二级渲染时 DOM 重建 */
  101. trackByZone = (_: number, z: SidebarZone) => z.key;
  102. trackByItem = (_: number, it: SidebarItem) => it.tab;
  103. isActive(tab: string): boolean {
  104. return this.currentTab === tab;
  105. }
  106. /** 鼓励通过 keyboard 操作 */
  107. onItemKey(ev: KeyboardEvent, tab: string): void {
  108. if (ev.key === 'Enter' || ev.key === ' ') {
  109. ev.preventDefault();
  110. this.tabChange.emit(tab);
  111. }
  112. }
  113. }