更新: 109 个文件 - 2026-03-18 10:55:52
这个提交包含在:
@@ -774,6 +774,7 @@ function renderPanel(panelKey, title, meta, iconName, content) {
|
||||
|
||||
function renderCompletenessPanel(panelKey, compact = false) {
|
||||
const completeness = state.completeness || state.summary?.completeness || {};
|
||||
const sourceHealth = state.sourceHealth || completeness.source_health || {};
|
||||
const systems = (state.completeness?.systems || []).map((system) => `
|
||||
<article class="plan-card">
|
||||
<span class="plan-label">${escapeHtml(system.system_id)}</span>
|
||||
@@ -807,12 +808,21 @@ function renderCompletenessPanel(panelKey, compact = false) {
|
||||
<strong>ingest failures</strong>
|
||||
<span>${escapeHtml(state.completeness?.ingest_health?.failure_count || 0)}</span>
|
||||
</article>
|
||||
<article class="detail-stat">
|
||||
<strong>active sources</strong>
|
||||
<span>${escapeHtml(sourceHealth.active_source_count || 0)}</span>
|
||||
</article>
|
||||
<article class="detail-stat">
|
||||
<strong>open alerts</strong>
|
||||
<span>${escapeHtml(sourceHealth.open_alert_count || 0)}</span>
|
||||
</article>
|
||||
</div>
|
||||
<div class="plan-grid" style="margin-top:16px;">${systems || `<div class="empty-state">暂无系统完整度数据。</div>`}</div>
|
||||
${compact ? "" : `
|
||||
<div class="detail-actions" style="margin-top:16px;">
|
||||
<a class="button button-secondary" href="/docs/testing-completeness-report.html" target="_blank" rel="noreferrer">${icon("docs")}<span>打开中文报告</span></a>
|
||||
<a class="button button-secondary" href="/data/completeness.json" target="_blank" rel="noreferrer">${icon("json")}<span>打开 completeness.json</span></a>
|
||||
<a class="button button-secondary" href="/data/source-health.json" target="_blank" rel="noreferrer">${icon("json")}<span>打开 source-health.json</span></a>
|
||||
</div>
|
||||
${failures.length ? `<div class="callout" style="margin-top:16px;"><strong>Ingest 未清零</strong><div class="plan-copy">${escapeHtml(failures.join(" | "))}</div></div>` : ""}
|
||||
`}
|
||||
@@ -820,6 +830,66 @@ function renderCompletenessPanel(panelKey, compact = false) {
|
||||
);
|
||||
}
|
||||
|
||||
function renderSourceHealthPanel(panelKey, compact = false) {
|
||||
const sourceHealth = state.sourceHealth || {};
|
||||
const alerts = state.alerts || [];
|
||||
const failures = (sourceHealth.failures || []).slice(0, 6);
|
||||
const openAlertItems = alerts.filter((item) => item.status === "open");
|
||||
const openAlerts = openAlertItems.slice(0, 6);
|
||||
const failureCards = failures.length
|
||||
? failures.map((item) => `
|
||||
<article class="plan-card">
|
||||
<span class="plan-label">${escapeHtml(item.system_id || "-")} · ${escapeHtml(item.source_name || "-")}</span>
|
||||
<div class="plan-copy">${escapeHtml(item.category || "unknown")} · ${escapeHtml(item.message || item.summary || "-")}</div>
|
||||
</article>
|
||||
`).join("")
|
||||
: `<div class="empty-state">当前 active source 集合全绿。</div>`;
|
||||
const alertCards = openAlerts.length
|
||||
? openAlerts.map((item) => `
|
||||
<article class="plan-card">
|
||||
<span class="plan-label">${escapeHtml(item.system_id || "-")} · ${escapeHtml(item.source_name || "-")}</span>
|
||||
<div class="plan-copy">streak ${escapeHtml(item.failure_streak || 0)} · ${escapeHtml(item.last_category || "-")}</div>
|
||||
</article>
|
||||
`).join("")
|
||||
: `<div class="empty-state">当前没有 open alert。</div>`;
|
||||
return renderPanel(
|
||||
panelKey,
|
||||
"Source Health 与告警",
|
||||
`${escapeHtml(sourceHealth.green_source_count || 0)}/${escapeHtml(sourceHealth.active_source_count || 0)}`,
|
||||
"shield",
|
||||
`
|
||||
<div class="detail-stat-grid">
|
||||
<article class="detail-stat">
|
||||
<strong>green</strong>
|
||||
<span>${escapeHtml(sourceHealth.green_source_count || 0)}</span>
|
||||
</article>
|
||||
<article class="detail-stat">
|
||||
<strong>failures</strong>
|
||||
<span>${escapeHtml(sourceHealth.failure_count || 0)}</span>
|
||||
</article>
|
||||
<article class="detail-stat">
|
||||
<strong>open alerts</strong>
|
||||
<span>${escapeHtml(openAlertItems.length)}</span>
|
||||
</article>
|
||||
<article class="detail-stat">
|
||||
<strong>last fully green</strong>
|
||||
<span>${escapeHtml(sourceHealth.last_fully_green_run ? formatDateTime(sourceHealth.last_fully_green_run) : "-")}</span>
|
||||
</article>
|
||||
</div>
|
||||
${compact ? "" : `
|
||||
<div class="detail-actions" style="margin-top:16px;">
|
||||
<a class="button button-secondary" href="/data/source-health.json" target="_blank" rel="noreferrer">${icon("json")}<span>source-health.json</span></a>
|
||||
<a class="button button-secondary" href="/data/alerts.json" target="_blank" rel="noreferrer">${icon("json")}<span>alerts.json</span></a>
|
||||
<a class="button button-secondary" href="/data/monitor-summary.json" target="_blank" rel="noreferrer">${icon("json")}<span>monitor-summary.json</span></a>
|
||||
<a class="button button-secondary" href="/docs/source-catalog-audit.html" target="_blank" rel="noreferrer">${icon("docs")}<span>source catalog audit</span></a>
|
||||
</div>
|
||||
`}
|
||||
<div class="plan-grid" style="margin-top:16px;">${failureCards}</div>
|
||||
<div class="plan-grid" style="margin-top:16px;">${alertCards}</div>
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
function renderArchitectureFields(fields = []) {
|
||||
if (!fields.length) return "";
|
||||
return `
|
||||
@@ -1197,6 +1267,7 @@ function renderOverviewWorkspace() {
|
||||
<div class="detail-subtitle">根入口保留为概览页,同时新增运行、系统、架构、文档和数据的独立 URL。顶部菜单负责分类切换,搜索与筛选会同步到地址栏。</div>
|
||||
</section>
|
||||
${renderCompletenessPanel("overview_completeness")}
|
||||
${renderSourceHealthPanel("overview_source_health")}
|
||||
${renderPanel("overview_runs", "最新运行", `${escapeHtml(runs.length)} 条`, "queue", renderRunList(runs, "暂无运行数据。"))}
|
||||
${renderPanel("overview_systems", "系统覆盖概览", `${escapeHtml(systems.length)} 个系统`, "systems", `<div class="system-grid">${renderSystemCards(systems)}</div>`)}
|
||||
${renderArchitecturePanel()}
|
||||
@@ -1263,6 +1334,7 @@ function renderDocsWorkspace() {
|
||||
<div class="detail-subtitle">不再把所有入口混在首页链接堆里。这里按说明、设计、真值镜像和 secure-code 索引集中展示。</div>
|
||||
</section>
|
||||
${renderCompletenessPanel("docs_completeness", true)}
|
||||
${renderSourceHealthPanel("docs_source_health", true)}
|
||||
${renderPanel("docs_hub", "文档与镜像页", `${escapeHtml(DOC_HUB_ITEMS.length)} 个入口`, "docs", renderHubCards(DOC_HUB_ITEMS))}
|
||||
</div>
|
||||
`;
|
||||
@@ -1284,6 +1356,7 @@ function renderDataWorkspace() {
|
||||
<div class="detail-subtitle">summary、runs、systems、advisories、profiles、architecture 已单独归入数据中心,避免和文档、运行详情混在一个地址里。</div>
|
||||
</section>
|
||||
${renderCompletenessPanel("data_completeness", true)}
|
||||
${renderSourceHealthPanel("data_source_health")}
|
||||
${renderPanel("data_hub", "JSON 与生成数据", `${escapeHtml(DATA_HUB_ITEMS.length)} 个入口`, "json", renderHubCards(DATA_HUB_ITEMS))}
|
||||
</div>
|
||||
`;
|
||||
@@ -1485,14 +1558,17 @@ async function loadData(preserveSelection = true) {
|
||||
renderSyncState("loading", "刷新中", `本地时间 ${new Date().toLocaleTimeString("zh-CN", { hour12: false })}`);
|
||||
|
||||
try {
|
||||
const [summary, runs, systems, advisories, profiles, architecture, completeness] = await Promise.all([
|
||||
const [summary, runs, systems, advisories, profiles, architecture, completeness, sourceHealth, alerts, monitorSummary] = await Promise.all([
|
||||
fetchJson("/summary.json"),
|
||||
fetchJson("/runs.json"),
|
||||
fetchJson("/systems.json"),
|
||||
fetchJson("/advisories.json"),
|
||||
fetchJson("/profiles.json"),
|
||||
fetchJson("/architecture.json"),
|
||||
fetchJson("/data/completeness.json")
|
||||
fetchJson("/data/completeness.json"),
|
||||
fetchJson("/data/source-health.json"),
|
||||
fetchJson("/data/alerts.json"),
|
||||
fetchJson("/data/monitor-summary.json")
|
||||
]);
|
||||
|
||||
state.summary = summary;
|
||||
@@ -1502,6 +1578,9 @@ async function loadData(preserveSelection = true) {
|
||||
state.profiles = profiles;
|
||||
state.architecture = architecture;
|
||||
state.completeness = completeness;
|
||||
state.sourceHealth = sourceHealth;
|
||||
state.alerts = alerts;
|
||||
state.monitorSummary = monitorSummary;
|
||||
|
||||
const filtered = filteredRuns();
|
||||
const candidate = preserveSelection ? (state.selectedRunId || previousRunId) : state.selectedRunId;
|
||||
|
||||
在新工单中引用
屏蔽一个用户