templates.component.html 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. <section class="templates-page">
  2. <header class="templates-header">
  3. <div>
  4. <span class="templates-eyebrow">效率资产</span>
  5. <h1>模板库</h1>
  6. <p>保存常用生成配置,后续用于批量生产、资产追溯和作品复盘。</p>
  7. </div>
  8. <button class="btn" type="button" (click)="refresh()">刷新</button>
  9. </header>
  10. <div class="templates-message" *ngIf="message()">{{ message() }}</div>
  11. <div class="templates-stats">
  12. <button class="template-stat" type="button" [class.is-active]="scopeFilter() === 'all'" (click)="setScopeFilter('all')">
  13. <span>全部模板</span>
  14. <strong>{{ stats().all }}</strong>
  15. </button>
  16. <button class="template-stat" type="button" [class.is-active]="scopeFilter() === 'system'" (click)="setScopeFilter('system')">
  17. <span>系统模板</span>
  18. <strong>{{ stats().system }}</strong>
  19. </button>
  20. <button class="template-stat" type="button" [class.is-active]="scopeFilter() === 'user'" (click)="setScopeFilter('user')">
  21. <span>我的模板</span>
  22. <strong>{{ stats().user }}</strong>
  23. </button>
  24. <button class="template-stat" type="button" [class.is-active]="pipelineFilter() === 'topic-to-video'" (click)="pipelineFilter.set('topic-to-video')">
  25. <span>主题生视频</span>
  26. <strong>{{ stats().topic }}</strong>
  27. </button>
  28. </div>
  29. <div class="templates-toolbar">
  30. <div class="template-search">
  31. <span class="icon">search</span>
  32. <input
  33. type="text"
  34. placeholder="搜索模板名称、分类、标签"
  35. [ngModel]="searchTerm()"
  36. (ngModelChange)="searchTerm.set($event)">
  37. </div>
  38. <select [ngModel]="scopeFilter()" (ngModelChange)="scopeFilter.set($event)">
  39. <option value="all">全部来源</option>
  40. <option value="system">系统模板</option>
  41. <option value="user">我的模板</option>
  42. </select>
  43. <select [ngModel]="pipelineFilter()" (ngModelChange)="pipelineFilter.set($event)">
  44. <option value="all">全部 Pipeline</option>
  45. <option *ngFor="let pipeline of pipelines" [value]="pipeline.route">{{ pipeline.displayName }}</option>
  46. </select>
  47. <select [ngModel]="categoryFilter()" (ngModelChange)="categoryFilter.set($event)">
  48. <option value="all">全部分类</option>
  49. <option *ngFor="let category of categories" [value]="category">{{ category }}</option>
  50. </select>
  51. </div>
  52. <div class="templates-list" *ngIf="filteredTemplates().length > 0; else emptyState">
  53. <article class="template-card" *ngFor="let template of filteredTemplates(); trackBy: trackByTemplate">
  54. <div class="template-card-main">
  55. <div class="template-card-head">
  56. <div>
  57. <span class="template-source">{{ scopeLabel(template.scope) }}</span>
  58. <h3>{{ template.name }}</h3>
  59. </div>
  60. <span class="template-status">{{ pipelineLabel(template.pipelineId) }}</span>
  61. </div>
  62. <p class="template-desc">{{ template.description || '未填写模板说明' }}</p>
  63. <div class="template-edit-form" *ngIf="editingId() === template.id">
  64. <label>
  65. 名称
  66. <input type="text" [ngModel]="editDraft().name" (ngModelChange)="updateEditDraft({ name: $event })">
  67. </label>
  68. <label>
  69. 说明
  70. <textarea rows="3" [ngModel]="editDraft().description" (ngModelChange)="updateEditDraft({ description: $event })"></textarea>
  71. </label>
  72. <label>
  73. 分类
  74. <select [ngModel]="editDraft().category" (ngModelChange)="updateEditDraft({ category: $event })">
  75. <option *ngFor="let category of categories" [value]="category">{{ category }}</option>
  76. </select>
  77. </label>
  78. <label>
  79. 标签
  80. <input type="text" placeholder="用逗号分隔" [ngModel]="editDraft().tagsText" (ngModelChange)="updateEditDraft({ tagsText: $event })">
  81. </label>
  82. <div class="template-edit-actions">
  83. <button class="btn btn-primary" type="button" (click)="saveEdit(template)">保存修改</button>
  84. <button class="btn" type="button" (click)="cancelEdit()">取消</button>
  85. </div>
  86. </div>
  87. <div class="template-config">
  88. <strong>配置摘要</strong>
  89. <pre>{{ template.config | json }}</pre>
  90. </div>
  91. <div class="template-tags">
  92. <span class="template-tag">{{ template.category }}</span>
  93. <span class="template-tag" *ngFor="let tag of template.tags">{{ tag }}</span>
  94. </div>
  95. <div class="template-meta">
  96. <span>使用 {{ template.usageCount || 0 }} 次</span>
  97. <span>更新 {{ formatTime(template.updatedAt) }}</span>
  98. </div>
  99. </div>
  100. <div class="template-actions">
  101. <button class="btn btn-primary" type="button" (click)="markUsed(template)">使用模板</button>
  102. <button class="btn" type="button" (click)="cloneTemplate(template)">复制到我的模板</button>
  103. <button class="btn" type="button" (click)="startEdit(template)" [disabled]="template.scope !== 'user'">编辑</button>
  104. <button class="btn btn-warn" type="button" (click)="deleteTemplate(template)" [disabled]="template.scope !== 'user'">删除</button>
  105. </div>
  106. </article>
  107. </div>
  108. <ng-template #emptyState>
  109. <div class="templates-empty">
  110. <h3>还没有匹配的模板</h3>
  111. <p>可以调整筛选条件,或先从系统模板复制一份作为你的常用模板。</p>
  112. </div>
  113. </ng-template>
  114. </section>