// HiddenSolve.js - 隐患解决页面组件 import React from 'react'; import { Select, Table } from 'antd'; import styles from './../fullinter.less'; import echarts from 'echarts'; const { Option } = Select; class HiddenSolve extends React.Component { constructor(props) { super(props); this.echartsInstances = { hiddenBarChart: null, // 各公司隐患统计柱状图(使用 hiddenList) hiddenRectifyChart: null, // 隐患整改情况柱状图(使用 hiddenRectifyList) }; this.chartResizeHandlers = {}; this.isUnmounted = false; // 添加缓存,用于比较数据是否真正变化 this.lastHiddenList = null; this.lastHiddenRectifyList = null; } // 获取公司选项(使用 props 传入的 companyData,与 TrainingContent 一致) getCompanyOptions = () => { const { companyData } = this.props; if (!companyData || companyData.length === 0) { return []; } return companyData.map((company, index) => ( )); }; // 根据选中的公司ID获取公司名称(用于筛选模拟数据) getSelectedCompanyName = () => { const { companyData, selectedCompany } = this.props; if (!selectedCompany || !companyData || companyData.length === 0) { return null; } const selectedCompanyObj = companyData.find((company) => company.ID === selectedCompany); return selectedCompanyObj ? selectedCompanyObj.NAME : null; }; waitForElement = (elementId, maxRetries = 10) => { return new Promise((resolve) => { let retries = 0; const checkInterval = setInterval(() => { const element = document.getElementById(elementId); if (element || retries >= maxRetries) { clearInterval(checkInterval); resolve(!!element); } retries++; }, 50); }); }; // 图表1: 各公司隐患统计柱状图(使用 hiddenList 数据) renderHiddenBarChart = async () => { if (this.isUnmounted) return; const elementExists = await this.waitForElement('hiddenBarChart'); if (!elementExists || this.isUnmounted) return; if (this.echartsInstances.hiddenBarChart) { this.echartsInstances.hiddenBarChart.dispose(); this.echartsInstances.hiddenBarChart = null; } const chartDom = document.getElementById('hiddenBarChart'); if (!chartDom) return; this.echartsInstances.hiddenBarChart = echarts.init(chartDom); const { hiddenSubData } = this.props; let hiddenList = hiddenSubData?.hiddenList || []; if (hiddenList.length === 0) { this.echartsInstances.hiddenBarChart.setOption({ title: { text: '各公司累计隐患统计数据', x: 'center', y: '25%', textStyle: { fontSize: 16, color: '#999' }, }, graphic: { type: 'text', left: 'center', top: 'middle', style: { text: '暂无数据', fill: '#999', fontSize: 14, }, }, }); return; } const companyNames = hiddenList.map((item) => item.companyName); const majorCounts = hiddenList.map((item) => item.majorCount); const generalCounts = hiddenList.map((item) => item.generalCount); const option = { title: { text: '各公司累计隐患统计数据', x: 'center', y: '5%', textStyle: { fontSize: 16, color: '#000', fontWeight: 'bold' }, }, tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' }, formatter: function (params) { let result = `${params[0].axisValue}
`; params.forEach((param) => { result += `${param.marker}${param.seriesName}: ${param.value}
`; }); return result; }, }, legend: { data: ['重大隐患', '一般隐患'], right: '3%', top: '10%', itemGap: 12, itemWidth: 16, itemHeight: 10, textStyle: { color: '#000', fontSize: 12 }, }, grid: { left: '8%', right: '5%', top: '28%', bottom: '8%', containLabel: true, }, xAxis: [ { type: 'category', data: companyNames, axisLine: { show: false }, axisTick: { show: false }, axisLabel: { textStyle: { color: '#000' }, rotate: companyNames.length > 4 ? 15 : 0, interval: 0, fontSize: 12, }, }, ], yAxis: [ { type: 'value', show: true, axisLine: { show: false }, axisTick: { show: false }, axisLabel: { show: true, textStyle: { color: '#000' }, }, splitLine: { show: false }, name: '隐患数量', nameTextStyle: { fontSize: 12 }, }, ], series: [ { name: '重大隐患', type: 'bar', data: majorCounts, itemStyle: { normal: { color: '#c92a2a', // 红色 }, }, label: { show: true, position: 'top', textStyle: { color: '#c92a2a', fontSize: 12 }, formatter: (params) => `${params.value}`, }, barWidth: '35%', }, { name: '一般隐患', type: 'bar', data: generalCounts, itemStyle: { normal: { color: '#4285F4', // 蓝色 }, }, label: { show: true, position: 'top', textStyle: { color: '#4285F4', fontSize: 12 }, formatter: (params) => `${params.value}`, }, barWidth: '35%', }, ], }; this.echartsInstances.hiddenBarChart.setOption(option); this.setupResizeHandler('hiddenBarChart', this.renderHiddenBarChart); }; // 图表2: 隐患整改情况柱状图(使用 hiddenRectifyList 数据) renderHiddenRectifyChart = async () => { if (this.isUnmounted) return; const elementExists = await this.waitForElement('hiddenRectifyChart'); if (!elementExists || this.isUnmounted) return; if (this.echartsInstances.hiddenRectifyChart) { this.echartsInstances.hiddenRectifyChart.dispose(); this.echartsInstances.hiddenRectifyChart = null; } const chartDom = document.getElementById('hiddenRectifyChart'); if (!chartDom) return; this.echartsInstances.hiddenRectifyChart = echarts.init(chartDom); const { hiddenSubData } = this.props; let hiddenRectifyList = hiddenSubData?.hiddenRectifyList || []; if (hiddenRectifyList.length === 0) { this.echartsInstances.hiddenRectifyChart.setOption({ title: { text: '当月各公司隐患统计数据', x: 'center', y: '25%', textStyle: { fontSize: 16, color: '#999' }, }, graphic: { type: 'text', left: 'center', top: 'middle', style: { text: '暂无数据', fill: '#999', fontSize: 14, }, }, }); return; } const companyNames = hiddenRectifyList.map((item) => item.companyName); const majorTotal = hiddenRectifyList.map((item) => item.majorCount); const majorRectified = hiddenRectifyList.map((item) => item.majorCountNo); const generalTotal = hiddenRectifyList.map((item) => item.generalCount); const generalRectified = hiddenRectifyList.map((item) => item.generalCountNo); const option = { title: { text: '当月各公司隐患统计数据', x: 'center', y: '5%', textStyle: { fontSize: 16, color: '#000', fontWeight: 'bold' }, }, tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' }, formatter: function (params) { let result = `${params[0].axisValue}
`; params.forEach((param) => { result += `${param.marker}${param.seriesName}: ${param.value}
`; }); return result; }, }, legend: { data: ['重大隐患量', '重大隐患未整改量', '一般隐患量', '一般隐患未整改量'], right: '3%', top: '10%', itemGap: 12, itemWidth: 16, itemHeight: 10, textStyle: { color: '#000', fontSize: 12 }, }, grid: { left: '8%', right: '5%', top: '28%', bottom: '8%', containLabel: true, }, xAxis: [ { type: 'category', data: companyNames, axisLine: { show: false }, axisTick: { show: false }, axisLabel: { textStyle: { color: '#000' }, rotate: companyNames.length > 4 ? 15 : 0, interval: 0, fontSize: 12, }, }, ], yAxis: [ { type: 'value', show: true, axisLine: { show: false }, axisTick: { show: false }, axisLabel: { show: true, textStyle: { color: '#000' }, }, splitLine: { show: false }, name: '隐患数量', nameTextStyle: { fontSize: 12 }, }, ], series: [ { name: '重大隐患量', type: 'bar', data: majorTotal, itemStyle: { normal: { color: '#c92a2a', // 红色 }, }, label: { show: true, position: 'top', textStyle: { color: '#c92a2a', fontSize: 11 }, formatter: (params) => `${params.value}`, }, barWidth: '20%', }, { name: '重大隐患未整改量', type: 'bar', data: majorRectified, itemStyle: { normal: { color: '#ffa94d', // 橙色 }, }, label: { show: true, position: 'top', textStyle: { color: '#ffa94d', fontSize: 11 }, formatter: (params) => `${params.value}`, }, barWidth: '20%', }, { name: '一般隐患量', type: 'bar', data: generalTotal, itemStyle: { normal: { color: '#4285F4', // 蓝色 }, }, label: { show: true, position: 'top', textStyle: { color: '#4285F4', fontSize: 11 }, formatter: (params) => `${params.value}`, }, barWidth: '20%', }, { name: '一般隐患未整改量', type: 'bar', data: generalRectified, itemStyle: { normal: { color: '#ffe066', // 黄色 }, }, label: { show: true, position: 'top', textStyle: { color: '#d4a000', fontSize: 11 }, formatter: (params) => `${params.value}`, }, barWidth: '20%', }, ], }; this.echartsInstances.hiddenRectifyChart.setOption(option); this.setupResizeHandler('hiddenRectifyChart', this.renderHiddenRectifyChart); }; // 排名列表组件(支持公司筛选) renderRankingList = () => { const { hiddenSubData, selectedCompany, onCompanyChange, companyData } = this.props; let hiddenRanking = hiddenSubData?.hiddenRanking || []; // 根据选中的公司筛选数据(前端筛选) const selectedCompanyName = this.getSelectedCompanyName(); let filteredRanking = hiddenRanking; if (selectedCompanyName) { filteredRanking = hiddenRanking.filter((item) => item.companyName === selectedCompanyName); } // 如果没选中公司或筛选后没有数据,显示全部或空状态 if (!selectedCompanyName || filteredRanking.length === 0) { filteredRanking = selectedCompanyName ? [] : hiddenRanking; } // 表格列配置(与 RiskControl 样式保持一致) const columns = [ { title: '序号', dataIndex: 'index', key: 'index', align: 'center', width: 80, render: (text, record, index) => {index + 1}, }, { title: '隐患名称', dataIndex: 'hiddenName', key: 'hiddenName', align: 'center', // 中间列自适应,不设置固定宽度 render: (text) => {text}, }, { title: '数量', dataIndex: 'qty', key: 'qty', align: 'center', width: 80, render: (text) => {text}, }, ]; const tableData = filteredRanking.map((item, index) => ({ key: index, index: index + 1, hiddenName: item.hiddenName, qty: item.qty, })); const scrollConfig = filteredRanking.length > 5 ? { y: 300 } : {}; return (
隐患次数排名列表
选择公司:
); }; // 添加 shouldComponentUpdate 优化性能 shouldComponentUpdate(nextProps, nextState) { // 只有当这些 props 变化时才重新渲染 if ( this.props.hiddenSubData?.hiddenRanking !== nextProps.hiddenSubData?.hiddenRanking || this.props.selectedCompany !== nextProps.selectedCompany || this.props.companyData !== nextProps.companyData ) { return true; } return false; } setupResizeHandler = (chartName, renderMethod) => { const resizeHandler = () => { if (this.echartsInstances[chartName] && !this.isUnmounted) { this.echartsInstances[chartName].resize(); } }; this.chartResizeHandlers[chartName] = resizeHandler; window.addEventListener('resize', resizeHandler); }; initAllCharts = () => { if (this.isUnmounted) return; setTimeout(() => { if (this.isUnmounted) return; this.renderHiddenBarChart(); this.renderHiddenRectifyChart(); }, 100); }; disposeAllCharts = () => { Object.keys(this.echartsInstances).forEach((key) => { if (this.echartsInstances[key]) { try { this.echartsInstances[key].dispose(); } catch (e) { console.warn(`Dispose chart ${key} error:`, e); } this.echartsInstances[key] = null; } }); Object.keys(this.chartResizeHandlers).forEach((key) => { if (this.chartResizeHandlers[key]) { window.removeEventListener('resize', this.chartResizeHandlers[key]); } }); this.chartResizeHandlers = {}; }; componentDidMount() { this.isUnmounted = false; this.initAllCharts(); } componentDidUpdate(prevProps) { const prevHiddenList = prevProps.hiddenSubData?.hiddenList; const currentHiddenList = this.props.hiddenSubData?.hiddenList; const prevHiddenRectifyList = prevProps.hiddenSubData?.hiddenRectifyList; const currentHiddenRectifyList = this.props.hiddenSubData?.hiddenRectifyList; // 检查 hiddenList 是否变化 const hiddenListChanged = JSON.stringify(prevHiddenList) !== JSON.stringify(currentHiddenList); // 检查 hiddenRectifyList 是否变化 const hiddenRectifyListChanged = JSON.stringify(prevHiddenRectifyList) !== JSON.stringify(currentHiddenRectifyList); // 只在数据真正变化时重新渲染图表 if (hiddenListChanged) { this.renderHiddenBarChart(); } if (hiddenRectifyListChanged) { this.renderHiddenRectifyChart(); } } componentWillUnmount() { this.isUnmounted = true; this.disposeAllCharts(); } render() { const { selectedCompany, onCompanyChange } = this.props; return (
{/* 第一行 - 柱状图(left)+ 排名列表(right) */}
{/* 添加公司筛选器(左上角,与 TrainingContent 样式一致) */}
{this.renderRankingList()}
{/* 第二行 - 隐患整改情况柱状图 */}
); } } export default HiddenSolve;