function kpiCard(label, value, unit, desc, trend, widthPercent, tone = "up") {
/**
* 集团级页面渲染模块。
* 负责集团总览、集团上线率卡片、企业分析、指标分析和集团上线统计弹窗。
*/
return `
${trend ? `${trend}
` : ""}
${label}
${value}${unit}
${desc}
`;
}
function clickableKpiCard(label, value, unit, desc, action, widthPercent, trend = "") {
return `
${trend ? `${trend}
` : ""}
${label}
${value}${unit}
${desc}
`;
}
/**
* 集团项目上线率卡片。
* 数值只来自集团监控接口,接口失败时显示错误状态。
*/
function onlineKpiCard(summary) {
const trendText = projectMasterDataState.loading ? "加载中" : `${toSafeNumber(summary.onlineRate).toFixed(2)}%`;
const statusText = projectMasterDataState.error
? `接口请求失败:${projectMasterDataState.error}`
: "上线项目/申请不用/应使用项目/项目总数";
return `
${trendText}
集团项目上线率
${summary.proInfoText || `${summary.onlineActual}/${summary.noNeedProjectCount}/${summary.onlineExpected}`}
${statusText}
`;
}
/**
* 面包屑渲染。
* 根据 state.view 组合集团、企业、项目、指标穿透层级,并附带当前维度和系统,方便用户确认筛选上下文。
*/
function renderBreadcrumbs() {
const parts = [`集团总览`];
if (state.view === "enterprise" || state.view === "project") {
parts.push(`›${state.enterpriseName}`);
}
if (state.view === "project") {
const projectName = projectMonitoringState.data?.MetricProjectInfo?.ProjectShortName
|| projectMonitoringState.data?.MetricProjectInfo?.ProjectName
|| "项目明细";
parts.push(`›${projectName}`);
}
if (state.view === "indicatorTrend" || state.view === "indicatorEnterprise" || state.view === "indicatorProject") {
const indicator = getSelectedIndicator();
parts.push(`›${indicator.name}`);
}
if (state.view === "indicatorProject") {
parts.push(`›${state.enterpriseName}`);
}
parts.push(`当前维度:${dimLabel()}`);
parts.push(`当前系统:${systemLabel()}`);
breadcrumbs.innerHTML = parts.join("");
}
/**
* 全局主渲染入口。
* 事件模块只改 state,然后调用 render;这里集中决定当前应该渲染哪个视图,避免分散刷新局部 DOM。
*/
function render() {
applySystemVisibility();
document.querySelectorAll("[data-dim]").forEach((button) => {
button.classList.toggle("active", button.dataset.dim === state.dimension);
});
document.querySelectorAll("[data-system]").forEach((button) => {
button.classList.toggle("active", button.dataset.system === state.system);
});
renderBreadcrumbs();
updateDataDateDisplay();
if (state.view === "group") renderGroupView();
if (state.view === "enterprise") renderEnterpriseView();
if (state.view === "project") renderProjectView();
if (state.view === "indicatorTrend") app.innerHTML = renderIndicatorTrendView();
if (state.view === "indicatorProject") app.innerHTML = renderIndicatorProjectView();
renderDrillModal();
}
/**
* 集团总览主视图。
* 顶部卡片展示集团汇总,中部图表支持企业下钻,底部指标区支持指标穿透和集团报告预览。
*/
function renderGroupView() {
const summary = groupSummary();
const indicators = getWarningIndicators();
const analysisIndicators = projectMasterDataState.metricDatas.length ? projectMasterDataState.metricDatas : indicators;
const activeEnterprises = getGroupEnterpriseModels();
app.innerHTML = `
${onlineKpiCard(summary)}
${clickableKpiCard("预立项项目数", fmtNumber(summary.preProjectTotal), "个", "点击查看集团项目上线统计。", "group-online-stats", clamp(summary.preProjectTotal / 2, 0, 100))}
${clickableKpiCard("待建项目数", fmtNumber(summary.pendingTotal), "个", "点击查看集团项目上线统计。", "group-online-stats", clamp(summary.pendingTotal, 0, 100))}
${clickableKpiCard("未达标项目数", fmtNumber(summary.belowStandardProjects), "个", "指标使用率低于 80% 的项目。", "below-standard-projects", clamp(100 - summary.belowStandardProjects, 0, 100))}
${clickableKpiCard("项目指标使用率", fmtPercent(summary.usageRate), "", "点击查看单位项目指标使用情况。", "group-unit-metric-usages", summary.usageRate)}
${kpiCard("项目指标准确率", fmtPercent(summary.accuracyRate), "", "", "", summary.accuracyRate)}
${renderFocusIndicators(indicators.slice(0, 8), 0, { highlightHigh: false })}
${renderGroupTrendChart(activeEnterprises)}
${activeEnterprises.length ? renderGroupedRateChart(activeEnterprises, "enterprise", { height: 132 }) : '
暂无企业分析数据
'}
${renderIndicatorAnalysis(analysisIndicators)}
`;
}
/**
* 顶部重点指标条。
* 每张指标卡都带 data-indicator,事件代理会据此打开指标趋势或企业内项目穿透弹窗。
*/
function renderFocusIndicators(items, offset, options = {}) {
const highlightHigh = options.highlightHigh !== false;
return items.map((item, index) => `
${item.name}
指标使用率:${item.usageRate}%
使用项目数:${item.projects}
`).join("");
}
/**
* 指标分析中的迷你进度条。
* value 控制条宽,displayValue 控制右侧展示文案,便于同一组件同时展示百分比和项目数量。
*/
function miniRate(label, value, color, displayValue = `${Math.round(value)}%`) {
return `
${label}
${displayValue}
`;
}
/**
* 集团指标分析列表。
* 以项目覆盖量、使用率、准确率三条迷你进度条展示指标风险,用于快速挑出需要穿透的指标。
*/
function renderIndicatorAnalysis(indicators) {
const maxProjects = Math.max(...indicators.map((item) => item.projects), 1);
return `
${indicators.slice(0, 8).map((item) => {
return `
${item.name}
${miniRate("项目", Math.round((item.projects / maxProjects) * 100), COLORS.online, item.projects)}
${miniRate("使用", item.usageRate, COLORS.usage)}
${miniRate("准确", indicatorAccuracy(item), COLORS.accuracy)}
`;
}).join("")}
`;
}
/**
* 企业指标分析列表。
* 与集团指标列表共用展示结构,但风险文案更偏整改和跟踪,用于企业页面的责任短板展示。
*/
function renderEnterpriseIndicatorAnalysis(items) {
const maxProjects = Math.max(...items.map((item) => item.projects), 1);
return `
${items.map((item) => {
return `
${item.name}
${miniRate("项目", Math.round((item.projects / maxProjects) * 100), COLORS.online, item.projects)}
${miniRate("使用", item.usageRate, COLORS.usage)}
${miniRate("准确", item.accuracyRate, COLORS.accuracy)}
`;
}).join("")}
`;
}
/**
* 集团上线统计弹窗表格。
* 表格行统一从 getProjectMasterRecords 读取接口数据。
* 国际、生态单位在这里加 green-row,高亮规则集中在表格渲染层。
*/
function renderUsageReportTable(list) {
const rows = getProjectMasterRecords();
const summary = getProjectMasterSummary();
const statusText = projectMasterDataState.loading
? `正在获取接口数据...
`
: projectMasterDataState.error
? `接口请求失败:${projectMasterDataState.error}
`
: "";
if (!rows.length) {
return `${statusText}暂无集团项目上线统计数据
`;
}
const bodyRows = rows.map((row) => ({
unit: row.name,
cells: [
row.onlineAutoTotal,
row.onlineReportedTotal,
fmtFixedPercent(row.onlineRate || projectMasterOnlineRate(row), 2),
row.total,
row.linkedTotal,
row.preProjectTotal,
row.pendingTotal,
Math.max(row.total - row.linkedTotal - row.preProjectTotal - row.pendingTotal, 0),
row.noNeedTotal,
row.noNeedCompletedTotal,
row.noNeedStoppedTotal,
row.noNeedRestrictedTotal,
row.masterProjectCount
],
webUrl: resolveProjectMasterWebUrl(row)
}));
return `
${statusText}
| 企业简称 |
上线项目数 |
上线率 |
应使用项目数 |
申请不用 |
主数据项目数 |
| 自动取值 |
定期填报 |
总数 |
已关联项目 |
预立项项目 |
待建项目 |
条件受限 |
总数 |
已完工 |
停缓建 |
条件受限 |
${bodyRows.map((row) => {
const unit = row.unit || "";
const rowClass = [
unit.includes("国际") || unit.includes("生态") ? "green-row" : ""
].filter(Boolean).join(" ");
const unitCell = /^https?:\/\//i.test(row.webUrl)
? `${unit}`
: unit;
return `
| ${unitCell} |
${row.cells.map((cell) => `${cell} | `).join("")}
`;
}).join("")}
| 合计 |
${["onlineAutoTotal", "onlineReportedTotal"].map((key) => `${rows.reduce((sum, row) => sum + toSafeNumber(row[key]), 0)} | `).join("")}
${fmtFixedPercent(summary.onlineRate, 2)} |
${rows.reduce((sum, row) => sum + toSafeNumber(row.total), 0)} |
${rows.reduce((sum, row) => sum + toSafeNumber(row.linkedTotal), 0)} |
${summary.preProjectTotal} |
${summary.pendingTotal} |
${rows.reduce((sum, row) => sum + Math.max(row.total - row.linkedTotal - row.preProjectTotal - row.pendingTotal, 0), 0)} |
${summary.noNeedProjectCount} |
${rows.reduce((sum, row) => sum + toSafeNumber(row.noNeedCompletedTotal), 0)} |
${rows.reduce((sum, row) => sum + toSafeNumber(row.noNeedStoppedTotal), 0)} |
${rows.reduce((sum, row) => sum + toSafeNumber(row.noNeedRestrictedTotal), 0)} |
${rows.reduce((sum, row) => sum + toSafeNumber(row.masterProjectCount), 0)} |
`;
}
function renderBelowStandardProjectListModal() {
const enterprise = state.enterpriseName ? getEnterprise(state.enterpriseName) : null;
const rows = getBelowStandardProjects(enterprise);
const title = enterprise ? `${enterprise.name} · 未达标项目清单` : "集团未达标项目清单";
if (!rows.length) {
return `
`;
}
return `
| 单位 |
项目名称 |
指标使用率 |
是否上线 |
最近更新 |
责任人 |
${rows.map(({ enterprise: item, project }) => `
| ${item.name} |
${project.name} |
${fmtPercent(project.usageRate)} |
${project.created ? '已上线' : '未上线'} |
${project.lastUpdate} |
${project.owner} |
`).join("")}
`;
}
function renderUnitMetricUsageModal() {
const rows = getUnitMetricUsageRecords();
if (!rows.length) {
return `
`;
}
return `
| 单位简称 |
QHSE在建项目数 |
活跃项目数 |
使用率 |
日期 |
${rows.map((row) => {
const unitName = row.abbreviation || row.unitName || "";
const webUrl = resolveUnitMetricUsageWebUrl(row);
const unitCell = /^https?:\/\//i.test(webUrl)
? `${unitName}`
: unitName;
return `
| ${unitCell} |
${row.qhseTotal} |
${row.activeNum} |
${fmtPercent(row.usageRate)} |
${formatApiDate(row.date)} |
`;
}).join("")}
`;
}
/**
* “集团项目上线统计”弹窗内容。
* 弹窗标题由 core 模块 renderDrillModal 设置,这里只负责面板主体和表格。
*/
function renderGroupOnlineStatsModal() {
return `
${renderUsageReportTable()}
`;
}