初始提交

This commit is contained in:
2026-06-22 10:48:35 +08:00
commit d254377951
42 changed files with 3662 additions and 0 deletions
+376
View File
@@ -0,0 +1,376 @@
/**
* 看板全局配置模块。
* 这里集中维护日期、外链、接口注册、兜底数据和运行时状态,其他 JS 模块只读取这些常量。
* 新增业务接口时优先注册到 apiRegistry,再通过 core 模块的统一请求方法调用,避免在视图层散落接口地址和 token。
*/
const TODAY = "2026-04-27";
const PREVIOUS_DAY = "2026-04-26";
const INDICATOR_MORE_URL = "https://psecc.cncecoa.com/webroot/decision/v10/entry/access/e6251c34-31ea-4a35-8269-b83074bd9c64?preview=true";
const ENTERPRISE_INDICATOR_MORE_URL = "https://psecc.cncecoa.com/webroot/decision/view/report?viewlet=%252F%25E6%2595%25B0%25E7%25A7%2591%25E5%2585%25AC%25E5%258F%25B8%252F%25E5%25AE%2589%25E8%25B4%25A8%25E9%2583%25A8%25E6%2595%25B0%25E6%258D%25AE%25E6%25BA%25AF%25E6%25BA%2590%252F%25E5%25AE%2589%25E5%2585%25A8%25E6%2595%25B0%25E6%258D%25AE%25E5%25B1%2595%25E7%25A4%25BA_%25E4%25BC%2581%25E4%25B8%259A%25E7%25BA%25A7.cpt&op=view&__parameters__=%257B%2522__pi__%2522%253Atrue%252C%2522fine_hyperlink%2522%253A%2522ec19fc0a-9bfe-44f8-ba96-8402ba9b7bf2%2522%257D&_=1777453619793";
const GROUP_USAGE_REPORT_URL = "https://lygcgs.com.cn:8078/QHSEDataExChange/res/report/%E6%95%B0%E6%8D%AE%E6%B2%BB%E7%90%86%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%E5%8F%8A%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%E6%8A%A5%E5%91%8A.pdf";
const OFFICE_PREVIEW_BASE_URL = "https://view.officeapps.live.com/op/embed.aspx?src=";
const REPORT_FILE_BASE_URL = "https://sggl.sedin.com.cn/res/report/";
/**
* 接口注册表。
* 当前集团项目上线率卡片和“集团项目上线统计”弹窗依赖 projectMasterDataAnalysis。
* Header 中仅保留后端要求的 token 和 Accept,浏览器侧不主动写 Host/Cookie/Connection 等受限头。
*/
const apiRegistry = {
projectMasterDataAnalysis: {
method: "GET",
url: "https://qhse.cncecoa.com/qhse_webapi/api/Common/GetProjectMasterDataAnalysis?unitId=",
headers: {
token: "AF17168B-87BD-4GLY-1111-F0A0A1158F9B",
Accept: "*/*"
}
}
};
/**
* 本地兜底表头和行数据。
* 接口加载失败或跨域被拦截时仍展示旧 Excel 口径,避免主卡片和弹窗空白。
*/
const usageReportHeaders = ["\u5e8f\u53f7", "\u5355\u4f4d", "\u4e3b\u6570\u636e\u9879\u76ee\u603b\u6570", "\u7533\u8bf7QHSE\u672a\u5efa\u9879\u76ee\u6570", "QHSE\u9879\u76ee\u603b\u6570\u6570", "QHSE\u4e0e\u4e3b\u6570\u636e\u5173\u8054\u9879\u76ee\u6570", "QHSE\u9879\u76ee\u5173\u8054\u4e0d\u5230\u4e3b\u6570\u636e\u9879\u76ee\u6570"];
const projectMasterDataHeaders = ["序号", "单位", "主数据项目数", "申请不用项目数", "QHSE使用项目数", "已关联", "待建", "预立项", "上报日期"];
const usageReportRows = [["1","\u5929\u8fb0","67","34","42","33","9"],["2","\u8d5b\u9f0e","33","3","52","30","22"],["3","\u4e1c\u534e","40","11","33","29","4"],["4","\u4e94\u73af","51","22","29","29","0"],["5","\u534e\u9646","38","4","34","34","0"],["6","\u6210\u8fbe","24","6","19","18","1"],["7","\u4e8c\u5316\u5efa","234","78","166","156","10"],["8","\u4e09\u5316\u5efa","167","36","151","131","20"],["9","\u56db\u5316\u5efa","117","46","84","71","13"],["10","\u516d\u5316\u5efa","263","90","199","173","26"],["11","\u4e03\u5316\u5efa","24","4","22","20","2"],["12","\u4e5d\u5316\u5efa","36","19","19","17","2"],["13","\u5341\u4e00\u5316\u5efa","69","17","57","52","5"],["14","\u5341\u4e09\u5316\u5efa","90","27","70","63","7"],["15","\u5341\u56db\u5316\u5efa","74","1","78","73","5"],["16","\u5341\u516d\u5316\u5efa","177","78","110","99","11"],["17","\u571f\u6728","42","11","33","31","2"],["18","\u88c5\u5907","14","5","9","9","0"],["19","\u534e\u8c0a","9","2","9","7","2"],["20","\u56fd\u9645","1","0","1","1","0"],["21","\u91cd\u673a","51","10","44","41","3"],["22","\u5317\u5efa\u6295","18","5","16","13","3"],["23","\u5357\u5efa\u6295","83","24","60","59","1"],["24","\u57ce\u6295","12","4","12","8","4"],["25","\u4ea4\u5efa","21","5","27","16","11"],["26","\u751f\u6001","31","0","31","31","0"],["27","\u897f\u5357","9","2","18","7","11"],["\u5408\u8ba1","","1795","544","1425","1251","174"]];
/**
* 集团主数据接口运行态。
* rows 直接供弹窗表格读取,summary 供集团上线率卡片读取;二者必须成对更新。
* loaded/error/loading 用于视图层展示“接口数据/兜底数据/加载中”的状态差异。
*/
const projectMasterDataState = {
loading: false,
loaded: false,
error: "",
rows: usageReportRows,
summary: null,
updatedAt: ""
};
/**
* 单位一览表文件名映射。
* 弹窗“预览”按钮只通过单位简称查表,不直接拼猜文件名,避免单位顺序或文件命名变化时打开错误附件。
*/
const usageReportFiles = {"\u516d\u5316\u5efa":"10\u3001\u516d\u5316\u5efa~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u4e03\u5316\u5efa":"11\u3001\u4e03\u5316\u5efa~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u4e5d\u5316\u5efa":"12\u3001\u4e5d\u5316\u5efa~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u5341\u4e00\u5316\u5efa":"13\u3001\u5341\u4e00\u5316\u5efa~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u5341\u4e09\u5316\u5efa":"14\u3001\u5341\u4e09\u5316\u5efa~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u5341\u56db\u5316\u5efa":"15\u3001\u5341\u56db\u5316\u5efa~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u5341\u516d\u5316\u5efa":"16\u3001\u5341\u516d\u5316\u5efa~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u571f\u6728":"17\u3001\u571f\u6728~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u88c5\u5907":"18\u3001\u88c5\u5907~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u534e\u8c0a":"19\u3001\u534e\u8c0a~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u5929\u8fb0":"1\u3001\u5929\u8fb0~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u91cd\u673a":"21\u3001\u91cd\u673a~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u5317\u5efa\u6295":"22\u3001\u5317\u5efa\u6295~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u5357\u5efa\u6295":"23\u3001\u5357\u5efa\u6295~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u57ce\u6295":"24\u3001\u57ce\u6295~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u4ea4\u5efa":"25\u3001\u4ea4\u5efa~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u897f\u5357":"27\u3001\u897f\u5357~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u8d5b\u9f0e":"2\u3001\u8d5b\u9f0e~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u4e1c\u534e":"3\u3001\u4e1c\u534e~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u4e94\u73af":"4\u3001\u4e94\u73af~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u534e\u9646":"5\u3001\u534e\u9646~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u6210\u8fbe":"6\u3001\u6210\u8fbe~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u4e8c\u5316\u5efa":"7\u3001\u4e8c\u5316\u5efa~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u4e09\u5316\u5efa":"8\u3001\u4e09\u5316\u5efa~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx","\u56db\u5316\u5efa":"9\u3001\u56db\u5316\u5efa~\u4e3b\u6570\u636e\u9879\u76ee\u4e0eQHSE\u9879\u76ee\u4e00\u89c8\u88682026.6.3.xlsx"};
/**
* 图表和状态标签共用色板。
* 图表模块只引用这里的语义色,不在 SVG 字符串中硬编码业务颜色。
*/
const COLORS = {
online: "#5d93ff",
usage: "#5ee1b5",
accuracy: "#ffc857",
warning: "#ff5c66",
cyan: "#49d6ff",
muted: "#91b8d0"
};
/**
* 企业级模拟基础数据。
* 企业/项目/指标多层页面都会从这里派生统计值;真实接口只接入集团主数据时,仍保留该数据支撑其他模块演示。
*/
const enterprises = [
{
name: "天辰公司",
owner: "张海",
stats: {
all: { projectCount: 40, onlineRate: 92, usageRate: 84, accuracyRate: 88, warningProjects: 4, warningItems: 39 },
new: { projectCount: 7, onlineRate: 86, usageRate: 78, accuracyRate: 82, warningProjects: 2, warningItems: 8 }
},
trend: { online: [88, 89, 90, 90, 91, 92, 92], usage: [78, 79, 80, 81, 82, 83, 84], accuracy: [84, 84, 85, 86, 86, 87, 88] }
},
{
name: "赛鼎公司",
owner: "刘明",
stats: {
all: { projectCount: 28, onlineRate: 83, usageRate: 69, accuracyRate: 70, warningProjects: 6, warningItems: 39 },
new: { projectCount: 6, onlineRate: 72, usageRate: 58, accuracyRate: 63, warningProjects: 4, warningItems: 12 }
},
trend: { online: [80, 80, 81, 82, 82, 83, 83], usage: [64, 64, 65, 66, 67, 68, 69], accuracy: [73, 72, 72, 71, 70, 70, 70] }
},
{
name: "东华公司",
owner: "王斌",
stats: {
all: { projectCount: 32, onlineRate: 88, usageRate: 76, accuracyRate: 79, warningProjects: 5, warningItems: 39 },
new: { projectCount: 3, onlineRate: 85, usageRate: 67, accuracyRate: 72, warningProjects: 2, warningItems: 7 }
},
trend: { online: [85, 85, 86, 86, 87, 88, 88], usage: [72, 72, 73, 74, 75, 76, 76], accuracy: [78, 78, 78, 79, 79, 79, 79] }
},
{
name: "五环公司",
owner: "赵宁",
stats: {
all: { projectCount: 24, onlineRate: 86, usageRate: 72, accuracyRate: 75, warningProjects: 4, warningItems: 32 },
new: { projectCount: 0, onlineRate: 0, usageRate: 0, accuracyRate: 0, warningProjects: 0, warningItems: 0 }
},
trend: { online: [82, 83, 84, 85, 85, 86, 86], usage: [68, 69, 70, 70, 71, 72, 72], accuracy: [72, 73, 74, 74, 74, 75, 75] }
},
{
name: "华陆公司",
owner: "陈哲",
stats: {
all: { projectCount: 25, onlineRate: 91, usageRate: 81, accuracyRate: 86, warningProjects: 3, warningItems: 28 },
new: { projectCount: 2, onlineRate: 90, usageRate: 74, accuracyRate: 80, warningProjects: 1, warningItems: 4 }
},
trend: { online: [89, 89, 90, 90, 91, 91, 91], usage: [76, 77, 78, 79, 80, 80, 81], accuracy: [83, 84, 84, 85, 85, 86, 86] }
},
{
name: "成达公司",
owner: "李强",
stats: {
all: { projectCount: 13, onlineRate: 95, usageRate: 88, accuracyRate: 90, warningProjects: 1, warningItems: 16 },
new: { projectCount: 0, onlineRate: 0, usageRate: 0, accuracyRate: 0, warningProjects: 0, warningItems: 0 }
},
trend: { online: [93, 93, 94, 94, 95, 95, 95], usage: [84, 85, 86, 86, 87, 88, 88], accuracy: [88, 88, 89, 89, 90, 90, 90] }
},
{
name: "二建",
owner: "周亮",
stats: {
all: { projectCount: 112, onlineRate: 84, usageRate: 73, accuracyRate: 80, warningProjects: 9, warningItems: 42 },
new: { projectCount: 13, onlineRate: 79, usageRate: 66, accuracyRate: 70, warningProjects: 5, warningItems: 10 }
},
trend: { online: [82, 82, 83, 83, 84, 84, 84], usage: [68, 69, 70, 71, 72, 73, 73], accuracy: [78, 78, 79, 79, 80, 80, 80] }
},
{
name: "三建",
owner: "孙越",
stats: {
all: { projectCount: 130, onlineRate: 78, usageRate: 64, accuracyRate: 66, warningProjects: 14, warningItems: 48 },
new: { projectCount: 12, onlineRate: 75, usageRate: 58, accuracyRate: 61, warningProjects: 7, warningItems: 13 }
},
trend: { online: [75, 75, 76, 76, 77, 78, 78], usage: [61, 61, 62, 62, 63, 64, 64], accuracy: [68, 67, 67, 66, 66, 66, 66] }
},
{
name: "四建",
owner: "马骏",
stats: {
all: { projectCount: 71, onlineRate: 87, usageRate: 78, accuracyRate: 82, warningProjects: 6, warningItems: 24 },
new: { projectCount: 5, onlineRate: 82, usageRate: 74, accuracyRate: 76, warningProjects: 2, warningItems: 6 }
},
trend: { online: [85, 85, 86, 86, 87, 87, 87], usage: [74, 75, 76, 76, 77, 78, 78], accuracy: [79, 80, 80, 81, 81, 82, 82] }
},
{
name: "六建",
owner: "韩伟",
stats: {
all: { projectCount: 192, onlineRate: 84, usageRate: 61, accuracyRate: 60, warningProjects: 22, warningItems: 55 },
new: { projectCount: 22, onlineRate: 78, usageRate: 52, accuracyRate: 56, warningProjects: 10, warningItems: 18 }
},
trend: { online: [81, 82, 82, 83, 83, 84, 84], usage: [58, 58, 59, 60, 60, 61, 61], accuracy: [63, 62, 62, 61, 61, 60, 60] }
},
{
name: "十一建",
owner: "郑一",
stats: {
all: { projectCount: 62, onlineRate: 89, usageRate: 77, accuracyRate: 78, warningProjects: 5, warningItems: 21 },
new: { projectCount: 5, onlineRate: 84, usageRate: 70, accuracyRate: 70, warningProjects: 2, warningItems: 5 }
},
trend: { online: [86, 87, 87, 88, 88, 89, 89], usage: [73, 74, 75, 76, 76, 77, 77], accuracy: [76, 76, 77, 77, 78, 78, 78] }
},
{
name: "十四建",
owner: "沈涛",
stats: {
all: { projectCount: 64, onlineRate: 82, usageRate: 68, accuracyRate: 69, warningProjects: 8, warningItems: 35 },
new: { projectCount: 9, onlineRate: 76, usageRate: 57, accuracyRate: 62, warningProjects: 5, warningItems: 9 }
},
trend: { online: [80, 80, 81, 81, 82, 82, 82], usage: [65, 65, 66, 67, 67, 68, 68], accuracy: [72, 71, 70, 70, 69, 69, 69] }
},
{
name: "十六建",
owner: "蒋峰",
stats: {
all: { projectCount: 81, onlineRate: 85, usageRate: 71, accuracyRate: 73, warningProjects: 7, warningItems: 31 },
new: { projectCount: 6, onlineRate: 80, usageRate: 65, accuracyRate: 67, warningProjects: 3, warningItems: 6 }
},
trend: { online: [82, 83, 83, 84, 84, 85, 85], usage: [67, 68, 69, 69, 70, 71, 71], accuracy: [75, 74, 74, 73, 73, 73, 73] }
},
{
name: "装备科技",
owner: "何平",
stats: {
all: { projectCount: 1, onlineRate: 100, usageRate: 100, accuracyRate: 100, warningProjects: 0, warningItems: 2 },
new: { projectCount: 0, onlineRate: 0, usageRate: 0, accuracyRate: 0, warningProjects: 0, warningItems: 0 }
},
trend: { online: [100, 100, 100, 100, 100, 100, 100], usage: [100, 100, 100, 100, 100, 100, 100], accuracy: [100, 100, 100, 100, 100, 100, 100] }
},
{
name: "南投",
owner: "梁旭",
stats: {
all: { projectCount: 29, onlineRate: 74, usageRate: 55, accuracyRate: 66, warningProjects: 6, warningItems: 18 },
new: { projectCount: 2, onlineRate: 70, usageRate: 50, accuracyRate: 55, warningProjects: 1, warningItems: 3 }
},
trend: { online: [72, 72, 73, 73, 74, 74, 74], usage: [53, 53, 54, 54, 55, 55, 55], accuracy: [66, 66, 66, 66, 66, 66, 66] }
},
{
name: "交建",
owner: "秦毅",
stats: {
all: { projectCount: 26, onlineRate: 80, usageRate: 69, accuracyRate: 72, warningProjects: 4, warningItems: 17 },
new: { projectCount: 2, onlineRate: 75, usageRate: 60, accuracyRate: 62, warningProjects: 1, warningItems: 2 }
},
trend: { online: [78, 78, 79, 79, 80, 80, 80], usage: [66, 67, 67, 68, 68, 69, 69], accuracy: [71, 71, 72, 72, 72, 72, 72] }
},
{
name: "生态",
owner: "郭晨",
stats: {
all: { projectCount: 17, onlineRate: 76, usageRate: 62, accuracyRate: 64, warningProjects: 5, warningItems: 22 },
new: { projectCount: 1, onlineRate: 70, usageRate: 55, accuracyRate: 55, warningProjects: 1, warningItems: 3 }
},
trend: { online: [73, 74, 74, 75, 75, 76, 76], usage: [59, 60, 60, 61, 61, 62, 62], accuracy: [66, 65, 65, 64, 64, 64, 64] }
}
];
/**
* 当前准确率口径尚未接入正式数据,统一置 0,避免不同层级出现不一致的模拟准确率。
*/
enterprises.forEach((enterprise) => {
["all", "new"].forEach((dimension) => {
enterprise.stats[dimension].accuracyRate = 0;
});
enterprise.trend.accuracy = [0, 0, 0, 0, 0, 0, 0];
});
/**
* 系统页签配置。
* URL 参数 type=1/2/3 会映射到 safety/quality/emergency,并影响可见页签与指标库。
*/
const systemLabels = {
safety: "安全",
quality: "质量",
emergency: "应急"
};
const systemTypeMap = {
1: "safety",
2: "quality",
3: "emergency"
};
/**
* 从 URL 解析外部系统允许展示的页签。
* 支持 type、types、system、systems,也兼容纯查询串写法;非法值会回退为全部页签。
*/
function getAllowedSystemsFromUrl() {
const params = new URLSearchParams(window.location.search);
const rawValue = params.get("type") || params.get("types") || params.get("system") || params.get("systems") || window.location.search.replace(/^\?/, "");
if (!rawValue) return Object.values(systemTypeMap);
const allowed = rawValue
.split(/[,\s,]+/)
.map((item) => systemTypeMap[item.trim()])
.filter(Boolean);
return allowed.length ? [...new Set(allowed)] : Object.values(systemTypeMap);
}
const allowedSystems = getAllowedSystemsFromUrl();
/**
* 各业务系统的重点指标池。
* 集团页指标卡、指标分析面板、指标穿透弹窗都从当前系统对应数组取数。
*/
const warningIndicatorMap = {
safety: [
{ name: "专职安全管理人员(含分包)总数", projects: 150, enterprises: 18, usageRate: 72 },
{ name: "特种作业人员数量", projects: 138, enterprises: 16, usageRate: 74 },
{ name: "危大工程进行中个数", projects: 121, enterprises: 15, usageRate: 69 },
{ name: "重大风险", projects: 116, enterprises: 14, usageRate: 76 },
{ name: "较大风险", projects: 104, enterprises: 13, usageRate: 68 },
{ name: "高风险作业许可进行中数量", projects: 98, enterprises: 12, usageRate: 71 },
{ name: "专项培训", projects: 92, enterprises: 12, usageRate: 66 },
{ name: "三级安全教育培训人次", projects: 86, enterprises: 11, usageRate: 70 }
],
quality: [
{ name: "项目质量管理人数", projects: 136, enterprises: 17, usageRate: 70 },
{ name: "人员报验数", projects: 128, enterprises: 16, usageRate: 68 },
{ name: "培训人次", projects: 112, enterprises: 15, usageRate: 73 },
{ name: "技术交底人次", projects: 105, enterprises: 14, usageRate: 71 },
{ name: "企业及分支机构检查数", projects: 96, enterprises: 13, usageRate: 65 },
{ name: "项目质量检查数", projects: 91, enterprises: 12, usageRate: 69 },
{ name: "施工方案企业审批总数", projects: 83, enterprises: 11, usageRate: 63 },
{ name: "施工方案项目审批总数", projects: 80, enterprises: 11, usageRate: 66 }
],
emergency: [
{ name: "应急预案备案", projects: 118, enterprises: 16, usageRate: 69 },
{ name: "应急演练记录", projects: 111, enterprises: 15, usageRate: 64 },
{ name: "应急物资台账", projects: 103, enterprises: 14, usageRate: 67 },
{ name: "应急队伍配置", projects: 96, enterprises: 13, usageRate: 70 },
{ name: "重大风险告警", projects: 88, enterprises: 12, usageRate: 62 },
{ name: "专项应急培训", projects: 81, enterprises: 11, usageRate: 66 },
{ name: "应急联络人员", projects: 76, enterprises: 10, usageRate: 71 },
{ name: "现场处置方案", projects: 72, enterprises: 10, usageRate: 63 },
{ name: "应急响应记录", projects: 66, enterprises: 9, usageRate: 60 },
{ name: "复盘整改闭环", projects: 61, enterprises: 8, usageRate: 58 }
]
};
/**
* 项目明细页字段模板。
* buildIndicatorRows 会结合项目使用率和滞后天数生成“是否启用、三日值、是否预警”等派生字段。
*/
const indicatorTemplates = [
{ name: "预警项数", field: "warningCount", base: 48 },
{ name: "参建人数", field: "participants", base: 215 },
{ name: "在施危大工程数", field: "dangerWorks", base: 3 },
{ name: "安全技术交底数", field: "safetyDisclosure", base: 69 },
{ name: "三级安全教育培训数", field: "safetyTraining", base: 555 },
{ name: "专项培训数", field: "specialTraining", base: 25 },
{ name: "特种作业培训数", field: "specialWorkTraining", base: 3 },
{ name: "项目总监人数", field: "directorCount", base: 1 },
{ name: "项目专职人数", field: "fulltimeCount", base: 5 },
{ name: "项目安全监护人数", field: "guardianCount", base: 2 },
{ name: "在岗执业注册师", field: "registeredEngineer", base: 4 },
{ name: "A证人员", field: "certA", base: 1 },
{ name: "B证人员", field: "certB", base: 2 },
{ name: "C证人员", field: "certC", base: 4 },
{ name: "特种作业人员", field: "specialWorkers", base: 57 },
{ name: "项目安全领导小组会议数", field: "safetyMeeting", base: 2 },
{ name: "项目安全例会数", field: "regularMeeting", base: 21 },
{ name: "项目负责人带班检查次数", field: "leaderInspection", base: 3 },
{ name: "项目专项检查次数", field: "specialInspection", base: 46 },
{ name: "项目专业检查次数", field: "professionInspection", base: 132 }
];
/**
* 项目名称池。
* generateProjects 用企业简称加这些后缀生成稳定项目名,保证同一企业在不同渲染中项目顺序一致。
*/
const projectNamePool = [
"精细化工材料项目",
"煤炭深加工基地项目",
"全场系统工程",
"新材料园区工程",
"装置检修项目",
"安全提升改造工程",
"数字化施工项目",
"生产运行保障项目",
"罐区扩能工程",
"绿色低碳改造项目",
"配套管廊工程",
"污水处理优化项目",
"储运系统升级项目",
"消防能力提升项目",
"基础设施完善项目",
"智能工地试点项目",
"综合楼建设项目",
"设备更新项目"
];
/**
* 单页看板运行时状态。
* view 控制主区域层级,drillOpen/drillView 控制弹窗层级;事件模块只改 state,再统一触发 render。
*/
const state = {
view: "group",
dimension: "all",
system: "safety",
enterpriseName: "",
projectId: "",
selectedIndicator: "",
drillOpen: false,
drillView: "trend",
drillEnterpriseName: "",
drillListType: ""
};