/** * 看板全局配置模块。 * 这里集中维护日期、外链、接口注册、兜底数据和运行时状态,其他 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: "" };