feat: add history report switcher dropdown in report detail view
This commit is contained in:
@@ -316,6 +316,24 @@ table.group-table td { border-bottom: 1px solid #f1f5f9; font-variant-numeric: t
|
|||||||
font-size: 13px; display: flex; align-items: center; gap: 6px;
|
font-size: 13px; display: flex; align-items: center; gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---------- 报告历史切换下拉 ---------- */
|
||||||
|
.report-switcher {
|
||||||
|
display: flex; align-items: center; gap: 10px;
|
||||||
|
background: var(--surface); border: 1px solid var(--line);
|
||||||
|
border-radius: var(--radius); padding: 10px 16px;
|
||||||
|
margin-bottom: 14px; box-shadow: var(--shadow);
|
||||||
|
}
|
||||||
|
.report-switcher-label {
|
||||||
|
font-size: 13px; font-weight: 600; color: var(--slate); white-space: nowrap;
|
||||||
|
}
|
||||||
|
.report-switcher-select {
|
||||||
|
flex: 1; min-width: 0;
|
||||||
|
border: 1px solid var(--line); border-radius: 6px; padding: 6px 10px;
|
||||||
|
font-size: 13px; font-family: inherit; background: var(--bg); color: var(--ink);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.report-switcher-select:focus { outline: none; border-color: var(--petrol); }
|
||||||
|
|
||||||
/* ================================================================
|
/* ================================================================
|
||||||
打印样式(导出 PDF 用)
|
打印样式(导出 PDF 用)
|
||||||
浏览器打印时隐藏 UI chrome,保留报告内容,图表 canvas 原样输出
|
浏览器打印时隐藏 UI chrome,保留报告内容,图表 canvas 原样输出
|
||||||
|
|||||||
@@ -103,6 +103,14 @@
|
|||||||
|
|
||||||
<!-- 报告详情视图 -->
|
<!-- 报告详情视图 -->
|
||||||
<section class="view" id="view-report" hidden>
|
<section class="view" id="view-report" hidden>
|
||||||
|
<!-- 历史报告切换下拉(顶部,始终可见) -->
|
||||||
|
<div class="report-switcher no-print" id="report-switcher">
|
||||||
|
<label class="report-switcher-label">切换报告</label>
|
||||||
|
<select class="select report-switcher-select" id="report-switcher-select">
|
||||||
|
<option value="">— 加载中… —</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="empty" id="report-empty">
|
<div class="empty" id="report-empty">
|
||||||
<p>请先从「运行列表」选择一次运行。</p>
|
<p>请先从「运行列表」选择一次运行。</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,11 +4,16 @@ const Report = {
|
|||||||
distChart: null,
|
distChart: null,
|
||||||
currentDetail: null,
|
currentDetail: null,
|
||||||
activeGrouping: null,
|
activeGrouping: null,
|
||||||
|
_switcherLoaded: false,
|
||||||
|
|
||||||
// 加载并渲染指定运行的完整报告。
|
// 加载并渲染指定运行的完整报告。
|
||||||
async render(runId) {
|
async render(runId) {
|
||||||
const empty = document.getElementById("report-empty");
|
const empty = document.getElementById("report-empty");
|
||||||
const content = document.getElementById("report-content");
|
const content = document.getElementById("report-content");
|
||||||
|
|
||||||
|
// 加载历史报告下拉(仅首次)
|
||||||
|
Report._loadSwitcher(runId);
|
||||||
|
|
||||||
if (!runId) {
|
if (!runId) {
|
||||||
empty.hidden = false;
|
empty.hidden = false;
|
||||||
content.hidden = true;
|
content.hidden = true;
|
||||||
@@ -28,6 +33,10 @@ const Report = {
|
|||||||
Report.renderLowest(detail.report);
|
Report.renderLowest(detail.report);
|
||||||
Report.renderAdvice(detail.summary, detail.report);
|
Report.renderAdvice(detail.summary, detail.report);
|
||||||
content.style.opacity = "1";
|
content.style.opacity = "1";
|
||||||
|
|
||||||
|
// 同步下拉选中项
|
||||||
|
const sel = document.getElementById("report-switcher-select");
|
||||||
|
if (sel) sel.value = runId;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
empty.hidden = false;
|
empty.hidden = false;
|
||||||
content.hidden = true;
|
content.hidden = true;
|
||||||
@@ -35,6 +44,55 @@ const Report = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 加载并填充历史报告下拉选择框
|
||||||
|
async _loadSwitcher(currentRunId) {
|
||||||
|
const sel = document.getElementById("report-switcher-select");
|
||||||
|
if (!sel) return;
|
||||||
|
|
||||||
|
// 已加载过就只更新选中值,不重复请求
|
||||||
|
if (Report._switcherLoaded) {
|
||||||
|
if (currentRunId) sel.value = currentRunId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await API.runs();
|
||||||
|
const runs = data.runs || [];
|
||||||
|
sel.innerHTML = "";
|
||||||
|
if (runs.length === 0) {
|
||||||
|
sel.innerHTML = '<option value="">(无历史运行)</option>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
runs.forEach((run) => {
|
||||||
|
const opt = document.createElement("option");
|
||||||
|
opt.value = run.run_id;
|
||||||
|
const timeStr = App.shortTime(run.finished_at);
|
||||||
|
const meanText = run.metric_means
|
||||||
|
? Object.entries(run.metric_means)
|
||||||
|
.filter(([, v]) => v !== null && v !== undefined)
|
||||||
|
.slice(0, 2)
|
||||||
|
.map(([k, v]) => `${App.shortMetric(k)}=${v.toFixed(2)}`)
|
||||||
|
.join(" ")
|
||||||
|
: "";
|
||||||
|
opt.textContent = `${run.scenario_name || run.run_id} ${timeStr}${meanText ? " [" + meanText + "]" : ""}`;
|
||||||
|
sel.appendChild(opt);
|
||||||
|
});
|
||||||
|
Report._switcherLoaded = true;
|
||||||
|
if (currentRunId) sel.value = currentRunId;
|
||||||
|
} catch (_e) {
|
||||||
|
sel.innerHTML = '<option value="">(加载失败)</option>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绑定切换事件(只绑一次)
|
||||||
|
sel.addEventListener("change", () => {
|
||||||
|
const rid = sel.value;
|
||||||
|
if (!rid) return;
|
||||||
|
App.currentRunId = rid;
|
||||||
|
App.enableReportNav();
|
||||||
|
Report.render(rid);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// 顶部元信息条。
|
// 顶部元信息条。
|
||||||
renderMeta(summary) {
|
renderMeta(summary) {
|
||||||
const el = document.getElementById("report-meta");
|
const el = document.getElementById("report-meta");
|
||||||
|
|||||||
Reference in New Issue
Block a user