增强系统级实体覆盖摘要与工作台索引
这个提交包含在:
@@ -65,6 +65,7 @@ const DATA_HUB_ITEMS = [
|
||||
{ title: "entity-queues.json", href: "/data/entity-queues.json", description: "discovery/history/latest/workflow 四类队列摘要。", badge: "json" },
|
||||
{ title: "runs.json", href: "/runs.json", description: "最近运行的结构化详情,可用于 UI 和调试。", badge: "json" },
|
||||
{ title: "systems.json", href: "/systems.json", description: "系统级覆盖、分类、更新时间和浏览器证据统计。", badge: "json" },
|
||||
{ title: "entities.json", href: "/entities.json", description: "分层实体索引、实体状态和系统归属。", badge: "json" },
|
||||
{ title: "advisories.json", href: "/advisories.json", description: "漏洞条目元数据、来源和 secure-code 主题。", badge: "json" },
|
||||
{ title: "profiles.json", href: "/profiles.json", description: "复现档案元数据、成功判据和 browser assertions。", badge: "json" },
|
||||
{ title: "architecture.json", href: "/architecture.json", description: "当前架构库的结构化真值。", badge: "json" },
|
||||
@@ -94,6 +95,7 @@ const state = {
|
||||
summary: null,
|
||||
runs: [],
|
||||
systems: [],
|
||||
entities: [],
|
||||
advisories: {},
|
||||
profiles: {},
|
||||
architecture: null,
|
||||
@@ -599,6 +601,9 @@ function renderSystemCards(items, compact = false) {
|
||||
const total = Math.max(Number(system.total || 0), 1);
|
||||
const verified = Number(system.verified_real || 0) + Number(system.verified_synthetic || 0);
|
||||
const coverage = Math.round((verified / total) * 100);
|
||||
const entitySummary = system.entity_summary || {};
|
||||
const topEntities = system.top_entities || [];
|
||||
const backlogPreview = system.backlog_preview || [];
|
||||
return `
|
||||
<article class="system-card ${compact ? "system-card-compact" : ""}">
|
||||
<div class="timeline-head">
|
||||
@@ -610,8 +615,28 @@ function renderSystemCards(items, compact = false) {
|
||||
<span class="tag">真实 ${escapeHtml(system.verified_real || 0)}</span>
|
||||
<span class="tag">合成 ${escapeHtml(system.verified_synthetic || 0)}</span>
|
||||
<span class="tag">阻塞 ${escapeHtml(system.blocked || 0)}</span>
|
||||
<span class="tag">实体 ${escapeHtml(entitySummary.cataloged_entity_total || 0)}</span>
|
||||
<span class="tag">backlog ${escapeHtml(entitySummary.candidate_entity_total || 0)}</span>
|
||||
</div>
|
||||
<div class="meter"><span style="--fill:${coverage}%"></span></div>
|
||||
${compact ? "" : `
|
||||
<div class="plan-grid" style="margin-top:12px;">
|
||||
<article class="plan-card">
|
||||
<span class="plan-label">实体覆盖</span>
|
||||
<div class="plan-copy">cataloged ${escapeHtml(entitySummary.cataloged_entity_total || 0)} · child ${escapeHtml(entitySummary.child_entity_total || 0)} · plugins ${escapeHtml(entitySummary.plugin_total || 0)}</div>
|
||||
</article>
|
||||
<article class="plan-card">
|
||||
<span class="plan-label">队列与缺口</span>
|
||||
<div class="plan-copy">history complete ${escapeHtml(entitySummary.history_full_complete_count || 0)} · latest green ${escapeHtml(entitySummary.latest_green_count || 0)} · version gap ${escapeHtml(entitySummary.version_gap_entity_count || 0)}</div>
|
||||
</article>
|
||||
</div>
|
||||
${(topEntities.length || backlogPreview.length) ? `
|
||||
<div class="tag-row" style="margin-top:10px;">
|
||||
${topEntities.map((item) => `<span class="tag">${escapeHtml(item.entity_type)} · ${escapeHtml(item.display_name)} · ${escapeHtml(item.advisory_count || 0)}</span>`).join("")}
|
||||
${backlogPreview.map((item) => `<span class="tag">${escapeHtml(item.entity_type)} backlog · ${escapeHtml(item.display_name)}</span>`).join("")}
|
||||
</div>
|
||||
` : ""}
|
||||
`}
|
||||
<div class="detail-actions" style="margin-top:12px;">
|
||||
<button class="button button-secondary button-small" type="button" data-filter-key="system" data-filter-value="${escapeHtml(system.system_id)}">锁定系统</button>
|
||||
<a class="button button-secondary button-small" href="${escapeHtml(buildUrl("runs", { system: system.system_id, run: null }))}">查看运行</a>
|
||||
@@ -1609,10 +1634,11 @@ async function loadData(preserveSelection = true) {
|
||||
renderSyncState("loading", "刷新中", `本地时间 ${new Date().toLocaleTimeString("zh-CN", { hour12: false })}`);
|
||||
|
||||
try {
|
||||
const [summary, runs, systems, advisories, profiles, architecture, completeness, entityCompleteness, sourceHealth, alerts, monitorSummary] = await Promise.all([
|
||||
const [summary, runs, systems, entities, advisories, profiles, architecture, completeness, entityCompleteness, sourceHealth, alerts, monitorSummary] = await Promise.all([
|
||||
fetchJson("/summary.json"),
|
||||
fetchJson("/runs.json"),
|
||||
fetchJson("/systems.json"),
|
||||
fetchJson("/entities.json"),
|
||||
fetchJson("/advisories.json"),
|
||||
fetchJson("/profiles.json"),
|
||||
fetchJson("/architecture.json"),
|
||||
@@ -1626,6 +1652,7 @@ async function loadData(preserveSelection = true) {
|
||||
state.summary = summary;
|
||||
state.runs = runs;
|
||||
state.systems = systems;
|
||||
state.entities = entities;
|
||||
state.advisories = advisories;
|
||||
state.profiles = profiles;
|
||||
state.architecture = architecture;
|
||||
|
||||
在新工单中引用
屏蔽一个用户