analysis-run-list.component.html 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. <section class="analysis-runs-page" aria-labelledby="analysis-runs-title">
  2. <header class="page-header">
  3. <div class="title-group">
  4. <span class="title-icon" aria-hidden="true">
  5. <lucide-icon [img]="icons.brain" [size]="19"></lucide-icon>
  6. </span>
  7. <div>
  8. <h1 id="analysis-runs-title">AI 分析运行中心</h1>
  9. <p>最近更新:{{ loadedAt ? formatDate(loadedAt) : '尚未加载' }}</p>
  10. </div>
  11. </div>
  12. <button class="icon-button" type="button" title="刷新运行列表" aria-label="刷新运行列表"
  13. [disabled]="loading" (click)="refresh()">
  14. <lucide-icon [img]="loading ? icons.loader : icons.refresh" [size]="16"
  15. [class.is-spinning]="loading"></lucide-icon>
  16. </button>
  17. </header>
  18. <div class="run-summary" aria-label="当前已加载运行统计">
  19. <div>
  20. <span>已加载</span>
  21. <strong>{{ runs.length }}</strong>
  22. </div>
  23. <div>
  24. <span class="summary-icon is-info"><lucide-icon [img]="icons.activity" [size]="14"></lucide-icon></span>
  25. <span>待处理 / 运行中</span>
  26. <strong>{{ processingCount }}</strong>
  27. </div>
  28. <div>
  29. <span class="summary-icon is-success"><lucide-icon [img]="icons.check" [size]="14"></lucide-icon></span>
  30. <span>完成 / 部分完成</span>
  31. <strong>{{ completedCount }}</strong>
  32. </div>
  33. <div>
  34. <span class="summary-icon is-danger"><lucide-icon [img]="icons.alert" [size]="14"></lucide-icon></span>
  35. <span>失败</span>
  36. <strong>{{ failedCount }}</strong>
  37. </div>
  38. </div>
  39. <div class="run-toolbar">
  40. <label class="search-field">
  41. <lucide-icon [img]="icons.search" [size]="15" aria-hidden="true"></lucide-icon>
  42. <span class="sr-only">搜索运行</span>
  43. <input type="search" [(ngModel)]="searchTerm" placeholder="搜索目标、类型、请求人或运行 ID" />
  44. </label>
  45. <label class="filter-field">
  46. <span>状态</span>
  47. <select [(ngModel)]="statusFilter" (change)="applyStatusFilter()">
  48. <option *ngFor="let option of statusOptions" [ngValue]="option.value">{{ option.label }}</option>
  49. </select>
  50. </label>
  51. <span class="result-count">{{ visibleRuns.length }} 条可见记录</span>
  52. </div>
  53. <div class="state-block" *ngIf="loading">
  54. <lucide-icon class="is-spinning" [img]="icons.loader" [size]="22"></lucide-icon>
  55. <strong>正在加载分析运行</strong>
  56. </div>
  57. <div class="state-block is-error" *ngIf="!loading && error">
  58. <lucide-icon [img]="icons.alert" [size]="22"></lucide-icon>
  59. <strong>{{ error }}</strong>
  60. <button type="button" (click)="refresh()">重试</button>
  61. </div>
  62. <div class="run-table-wrap" *ngIf="!loading && !error && visibleRuns.length">
  63. <table class="run-table">
  64. <thead>
  65. <tr>
  66. <th>状态</th>
  67. <th>分析类型</th>
  68. <th>目标对象</th>
  69. <th class="number-cell">样本 / 证据</th>
  70. <th>模式</th>
  71. <th>请求 / 完成时间</th>
  72. <th>错误</th>
  73. <th><span class="sr-only">查看详情</span></th>
  74. </tr>
  75. </thead>
  76. <tbody>
  77. <tr *ngFor="let run of visibleRuns; trackBy: trackRun" [class.is-selected]="selectedRun?.id === run.id">
  78. <td>
  79. <span class="status-badge" [attr.data-tone]="statusTone(run)">
  80. <span class="status-dot"></span>{{ statusLabel(run) }}
  81. </span>
  82. </td>
  83. <td>
  84. <strong class="primary-cell">{{ typeLabel(run) }}</strong>
  85. <span class="secondary-cell">{{ run.analysisType }}</span>
  86. </td>
  87. <td>
  88. <button class="target-button" type="button" (click)="selectRun(run)">
  89. <span>{{ targetLabel(run) }}</span>
  90. <small>{{ targetKindLabel(run) }}</small>
  91. </button>
  92. </td>
  93. <td class="number-cell">
  94. <strong>{{ sampleCount(run) }}</strong>
  95. <span>/ {{ run.evidenceCount | number }}</span>
  96. </td>
  97. <td>{{ modeLabel(run) }}</td>
  98. <td>
  99. <time class="primary-cell" [attr.datetime]="run.requestedAt">{{ formatDate(run.requestedAt) }}</time>
  100. <time class="secondary-cell" *ngIf="run.completedAt; else missingCompletion"
  101. [attr.datetime]="run.completedAt">{{ formatDate(run.completedAt) }}</time>
  102. <ng-template #missingCompletion><span class="secondary-cell is-missing">完成时间未记录</span></ng-template>
  103. </td>
  104. <td>
  105. <span class="error-cell" [class.is-present]="run.errorSummary">{{ run.errorSummary || '无' }}</span>
  106. </td>
  107. <td class="action-cell">
  108. <button class="row-action" type="button" title="查看运行详情" [attr.aria-label]="'查看运行 ' + run.id"
  109. (click)="selectRun(run)">
  110. <lucide-icon [img]="icons.eye" [size]="15"></lucide-icon>
  111. <lucide-icon [img]="icons.chevron" [size]="14"></lucide-icon>
  112. </button>
  113. </td>
  114. </tr>
  115. </tbody>
  116. </table>
  117. </div>
  118. <div class="state-block" *ngIf="!loading && !error && !visibleRuns.length">
  119. <lucide-icon [img]="icons.clock" [size]="22"></lucide-icon>
  120. <strong>{{ runs.length ? '没有匹配当前搜索的运行' : '当前筛选下没有分析运行' }}</strong>
  121. </div>
  122. <footer class="table-footer" *ngIf="!loading && !error && runs.length">
  123. <span>{{ nextCursor ? '仍有更多运行记录' : '已到达当前记录末尾' }}</span>
  124. <button type="button" *ngIf="nextCursor" [disabled]="loadingMore" (click)="loadMore()">
  125. <lucide-icon [img]="loadingMore ? icons.loader : icons.chevron" [size]="15"
  126. [class.is-spinning]="loadingMore"></lucide-icon>
  127. {{ loadingMore ? '加载中' : '加载更多' }}
  128. </button>
  129. </footer>
  130. </section>
  131. <app-analysis-run-detail *ngIf="selectedRun" [run]="selectedRun" [workspaceId]="workspaceId"
  132. (closed)="closeDetail()"></app-analysis-run-detail>