feat: 指标统计(执行时长/成功率/复审通过率/重试率/额度估算)tsk_lDx6zd-EbA00

从 runs/tasks/events 聚合健康度与成本指标,看板新增指标小面板。

- Store.metrics(projectId?):执行时长(avg/p50/p95,未结束与负时长不计)、
  executor 成功率、复审/安全 verdict 通过率、failed→queued 重试率 +
  needs_attention、按模型额度粗估(时长×档位权重,标注估算)
- src/model/metrics.ts:类型 + 纯函数(percentile/ratio/estimateCostUnits/emptyMetrics)
- API:GET /api/metrics?project=
- web:归档区上方指标面板(数字卡 + 按模型分布),失败/空数据静默隐藏
- test/metrics.test.ts:9 个用例(纯函数/空数据/时长/成功率/复审/重试/按模型/项目过滤)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-13 10:55:56 +08:00
parent 872354cf7c
commit 3696604e13
8 changed files with 582 additions and 2 deletions
+49
View File
@@ -826,3 +826,52 @@ li.ev-updated { --ev: var(--muted); }
.detail-confirm-msg {
font-size: 12px; color: var(--ink);
}
/* ════════ 指标面板(健康度与成本) ════════ */
#metricsSection { margin-top: 28px; }
.metrics-scope { margin-left: 8px; font-size: 11px; color: var(--muted); letter-spacing: .04em; }
.metric-cards {
display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 10px;
}
.metric-card {
border: 1px solid var(--line); background: var(--panel);
padding: 10px 12px; min-width: 0;
}
.metric-card.est { border-style: dashed; }
.metric-val {
font-size: 26px; font-weight: 700; line-height: 1; color: var(--ink);
}
.metric-card.ok .metric-val { color: var(--green); text-shadow: 0 0 14px rgba(95,221,125,.35); }
.metric-card.warn .metric-val { color: var(--amber); text-shadow: 0 0 14px rgba(240,180,41,.3); }
.metric-card.crit .metric-val { color: var(--red); text-shadow: 0 0 14px rgba(255,93,93,.35); }
.metric-unit { font-size: 13px; font-weight: 600; color: var(--muted); margin-left: 2px; }
.metric-label {
margin-top: 6px; font-size: 10px; font-weight: 600;
letter-spacing: .16em; text-transform: uppercase; color: var(--muted);
}
.metric-sub { margin-top: 4px; font-size: 11px; color: var(--faint); }
.metric-est { color: var(--cyan); }
.metric-models {
margin-top: 14px; border: 1px solid var(--line-soft);
background: var(--bg-deep); padding: 10px 12px;
}
.metric-models-head {
font-size: 10px; font-weight: 600; letter-spacing: .14em;
text-transform: uppercase; color: var(--muted); margin-bottom: 8px;
}
.metric-model-row {
display: flex; align-items: center; gap: 10px;
padding: 3px 0; font-size: 11.5px;
}
.metric-model-name { width: 90px; flex: none; color: var(--cyan); }
.metric-model-bar {
flex: 1; height: 8px; min-width: 40px;
background: var(--panel-2); border: 1px solid var(--line-soft); overflow: hidden;
}
.metric-model-fill {
display: block; height: 100%;
background: linear-gradient(90deg, var(--cyan-dim), var(--cyan));
}
.metric-model-num { flex: none; color: var(--muted); white-space: nowrap; }