| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- <section class="analysis-runs-page" aria-labelledby="analysis-runs-title">
- <header class="page-header">
- <div class="title-group">
- <span class="title-icon" aria-hidden="true">
- <lucide-icon [img]="icons.brain" [size]="19"></lucide-icon>
- </span>
- <div>
- <h1 id="analysis-runs-title">AI 分析运行中心</h1>
- <p>最近更新:{{ loadedAt ? formatDate(loadedAt) : '尚未加载' }}</p>
- </div>
- </div>
- <button class="icon-button" type="button" title="刷新运行列表" aria-label="刷新运行列表"
- [disabled]="loading" (click)="refresh()">
- <lucide-icon [img]="loading ? icons.loader : icons.refresh" [size]="16"
- [class.is-spinning]="loading"></lucide-icon>
- </button>
- </header>
- <div class="run-summary" aria-label="当前已加载运行统计">
- <div>
- <span>已加载</span>
- <strong>{{ runs.length }}</strong>
- </div>
- <div>
- <span class="summary-icon is-info"><lucide-icon [img]="icons.activity" [size]="14"></lucide-icon></span>
- <span>待处理 / 运行中</span>
- <strong>{{ processingCount }}</strong>
- </div>
- <div>
- <span class="summary-icon is-success"><lucide-icon [img]="icons.check" [size]="14"></lucide-icon></span>
- <span>完成 / 部分完成</span>
- <strong>{{ completedCount }}</strong>
- </div>
- <div>
- <span class="summary-icon is-danger"><lucide-icon [img]="icons.alert" [size]="14"></lucide-icon></span>
- <span>失败</span>
- <strong>{{ failedCount }}</strong>
- </div>
- </div>
- <div class="run-toolbar">
- <label class="search-field">
- <lucide-icon [img]="icons.search" [size]="15" aria-hidden="true"></lucide-icon>
- <span class="sr-only">搜索运行</span>
- <input type="search" [(ngModel)]="searchTerm" placeholder="搜索目标、类型、请求人或运行 ID" />
- </label>
- <label class="filter-field">
- <span>状态</span>
- <select [(ngModel)]="statusFilter" (change)="applyStatusFilter()">
- <option *ngFor="let option of statusOptions" [ngValue]="option.value">{{ option.label }}</option>
- </select>
- </label>
- <span class="result-count">{{ visibleRuns.length }} 条可见记录</span>
- </div>
- <div class="state-block" *ngIf="loading">
- <lucide-icon class="is-spinning" [img]="icons.loader" [size]="22"></lucide-icon>
- <strong>正在加载分析运行</strong>
- </div>
- <div class="state-block is-error" *ngIf="!loading && error">
- <lucide-icon [img]="icons.alert" [size]="22"></lucide-icon>
- <strong>{{ error }}</strong>
- <button type="button" (click)="refresh()">重试</button>
- </div>
- <div class="run-table-wrap" *ngIf="!loading && !error && visibleRuns.length">
- <table class="run-table">
- <thead>
- <tr>
- <th>状态</th>
- <th>分析类型</th>
- <th>目标对象</th>
- <th class="number-cell">样本 / 证据</th>
- <th>模式</th>
- <th>请求 / 完成时间</th>
- <th>错误</th>
- <th><span class="sr-only">查看详情</span></th>
- </tr>
- </thead>
- <tbody>
- <tr *ngFor="let run of visibleRuns; trackBy: trackRun" [class.is-selected]="selectedRun?.id === run.id">
- <td>
- <span class="status-badge" [attr.data-tone]="statusTone(run)">
- <span class="status-dot"></span>{{ statusLabel(run) }}
- </span>
- </td>
- <td>
- <strong class="primary-cell">{{ typeLabel(run) }}</strong>
- <span class="secondary-cell">{{ run.analysisType }}</span>
- </td>
- <td>
- <button class="target-button" type="button" (click)="selectRun(run)">
- <span>{{ targetLabel(run) }}</span>
- <small>{{ targetKindLabel(run) }}</small>
- </button>
- </td>
- <td class="number-cell">
- <strong>{{ sampleCount(run) }}</strong>
- <span>/ {{ run.evidenceCount | number }}</span>
- </td>
- <td>{{ modeLabel(run) }}</td>
- <td>
- <time class="primary-cell" [attr.datetime]="run.requestedAt">{{ formatDate(run.requestedAt) }}</time>
- <time class="secondary-cell" *ngIf="run.completedAt; else missingCompletion"
- [attr.datetime]="run.completedAt">{{ formatDate(run.completedAt) }}</time>
- <ng-template #missingCompletion><span class="secondary-cell is-missing">完成时间未记录</span></ng-template>
- </td>
- <td>
- <span class="error-cell" [class.is-present]="run.errorSummary">{{ run.errorSummary || '无' }}</span>
- </td>
- <td class="action-cell">
- <button class="row-action" type="button" title="查看运行详情" [attr.aria-label]="'查看运行 ' + run.id"
- (click)="selectRun(run)">
- <lucide-icon [img]="icons.eye" [size]="15"></lucide-icon>
- <lucide-icon [img]="icons.chevron" [size]="14"></lucide-icon>
- </button>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- <div class="state-block" *ngIf="!loading && !error && !visibleRuns.length">
- <lucide-icon [img]="icons.clock" [size]="22"></lucide-icon>
- <strong>{{ runs.length ? '没有匹配当前搜索的运行' : '当前筛选下没有分析运行' }}</strong>
- </div>
- <footer class="table-footer" *ngIf="!loading && !error && runs.length">
- <span>{{ nextCursor ? '仍有更多运行记录' : '已到达当前记录末尾' }}</span>
- <button type="button" *ngIf="nextCursor" [disabled]="loadingMore" (click)="loadMore()">
- <lucide-icon [img]="loadingMore ? icons.loader : icons.chevron" [size]="15"
- [class.is-spinning]="loadingMore"></lucide-icon>
- {{ loadingMore ? '加载中' : '加载更多' }}
- </button>
- </footer>
- </section>
- <app-analysis-run-detail *ngIf="selectedRun" [run]="selectedRun" [workspaceId]="workspaceId"
- (closed)="closeDetail()"></app-analysis-run-detail>
|