2026-04-28 16:52:44 +08:00
|
|
|
|
// HiddenSolve.js - 隐患解决页面组件
|
|
|
|
|
|
import React from 'react';
|
|
|
|
|
|
import { Select } 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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取公司选项(使用 props 传入的 companyData,与 TrainingContent 一致)
|
|
|
|
|
|
getCompanyOptions = () => {
|
|
|
|
|
|
const { companyData } = this.props;
|
|
|
|
|
|
if (!companyData || companyData.length === 0) {
|
|
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
return companyData.map((company, index) => (
|
|
|
|
|
|
<Option key={company.ID || index} value={company.ID}>
|
|
|
|
|
|
{company.NAME}
|
|
|
|
|
|
</Option>
|
|
|
|
|
|
));
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 根据选中的公司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: {
|
2026-04-29 11:11:23 +08:00
|
|
|
|
text: '各公司累计隐患统计数据',
|
2026-04-28 16:52:44 +08:00
|
|
|
|
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: {
|
2026-04-29 11:11:23 +08:00
|
|
|
|
text: '各公司累计隐患统计数据',
|
2026-04-28 16:52:44 +08:00
|
|
|
|
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}<br/>`;
|
|
|
|
|
|
params.forEach((param) => {
|
|
|
|
|
|
result += `${param.marker}${param.seriesName}: ${param.value}<br/>`;
|
|
|
|
|
|
});
|
|
|
|
|
|
return result;
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
legend: {
|
|
|
|
|
|
data: ['重大隐患', '一般隐患'],
|
|
|
|
|
|
orient: 'vertical',
|
|
|
|
|
|
right: '3%',
|
|
|
|
|
|
top: '5%',
|
|
|
|
|
|
itemGap: 16,
|
|
|
|
|
|
itemWidth: 18,
|
|
|
|
|
|
itemHeight: 12,
|
|
|
|
|
|
textStyle: { color: '#000', fontSize: 14 },
|
|
|
|
|
|
},
|
|
|
|
|
|
grid: {
|
|
|
|
|
|
left: '8%',
|
|
|
|
|
|
right: '5%',
|
|
|
|
|
|
top: '18%',
|
|
|
|
|
|
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: {
|
2026-04-29 11:11:23 +08:00
|
|
|
|
text: '当月各公司隐患统计数据',
|
2026-04-28 16:52:44 +08:00
|
|
|
|
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.majorCount || 0) - (item.majorCountNo || 0));
|
|
|
|
|
|
const generalTotal = hiddenRectifyList.map((item) => item.generalCount);
|
|
|
|
|
|
const generalRectified = hiddenRectifyList.map((item) => (item.generalCount || 0) - (item.generalCountNo || 0));
|
|
|
|
|
|
|
|
|
|
|
|
const option = {
|
|
|
|
|
|
title: {
|
2026-04-29 11:11:23 +08:00
|
|
|
|
text: '当月各公司隐患统计数据',
|
2026-04-28 16:52:44 +08:00
|
|
|
|
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}<br/>`;
|
|
|
|
|
|
params.forEach((param) => {
|
|
|
|
|
|
result += `${param.marker}${param.seriesName}: ${param.value}<br/>`;
|
|
|
|
|
|
});
|
|
|
|
|
|
return result;
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
legend: {
|
2026-04-29 11:11:23 +08:00
|
|
|
|
data: ['重大隐患量', '重大隐患未整改量', '一般隐患量', '一般隐患未整改量'],
|
2026-04-28 16:52:44 +08:00
|
|
|
|
orient: 'vertical',
|
|
|
|
|
|
right: '3%',
|
|
|
|
|
|
top: '5%',
|
|
|
|
|
|
itemGap: 12,
|
|
|
|
|
|
itemWidth: 18,
|
|
|
|
|
|
itemHeight: 12,
|
|
|
|
|
|
textStyle: { color: '#000', fontSize: 12 },
|
|
|
|
|
|
},
|
|
|
|
|
|
grid: {
|
|
|
|
|
|
left: '8%',
|
|
|
|
|
|
right: '5%',
|
|
|
|
|
|
top: '18%',
|
|
|
|
|
|
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: [
|
|
|
|
|
|
{
|
2026-04-29 11:11:23 +08:00
|
|
|
|
name: '重大隐患量',
|
2026-04-28 16:52:44 +08:00
|
|
|
|
type: 'bar',
|
|
|
|
|
|
data: majorTotal,
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
normal: {
|
|
|
|
|
|
color: '#c92a2a', // 红色
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
label: {
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
position: 'top',
|
|
|
|
|
|
textStyle: { color: '#c92a2a', fontSize: 11 },
|
|
|
|
|
|
formatter: (params) => `${params.value}`,
|
|
|
|
|
|
},
|
|
|
|
|
|
barWidth: '20%',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
2026-04-29 11:11:23 +08:00
|
|
|
|
name: '重大隐患未整改量',
|
2026-04-28 16:52:44 +08:00
|
|
|
|
type: 'bar',
|
|
|
|
|
|
data: majorRectified,
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
normal: {
|
|
|
|
|
|
color: '#ffa94d', // 橙色
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
label: {
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
position: 'top',
|
|
|
|
|
|
textStyle: { color: '#ffa94d', fontSize: 11 },
|
|
|
|
|
|
formatter: (params) => `${params.value}`,
|
|
|
|
|
|
},
|
|
|
|
|
|
barWidth: '20%',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
2026-04-29 11:11:23 +08:00
|
|
|
|
name: '一般隐患量',
|
2026-04-28 16:52:44 +08:00
|
|
|
|
type: 'bar',
|
|
|
|
|
|
data: generalTotal,
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
normal: {
|
|
|
|
|
|
color: '#4285F4', // 蓝色
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
label: {
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
position: 'top',
|
|
|
|
|
|
textStyle: { color: '#4285F4', fontSize: 11 },
|
|
|
|
|
|
formatter: (params) => `${params.value}`,
|
|
|
|
|
|
},
|
|
|
|
|
|
barWidth: '20%',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
2026-04-29 11:11:23 +08:00
|
|
|
|
name: '一般隐患未整改量',
|
2026-04-28 16:52:44 +08:00
|
|
|
|
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();
|
|
|
|
|
|
if (selectedCompanyName) {
|
|
|
|
|
|
hiddenRanking = hiddenRanking.filter((item) => item.companyName === selectedCompanyName);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-29 11:11:23 +08:00
|
|
|
|
// if (hiddenRanking.length === 0) {
|
|
|
|
|
|
// return (
|
|
|
|
|
|
// <div style={{ textAlign: 'center', padding: '50px', color: '#999' }}>
|
|
|
|
|
|
// {selectedCompanyName ? `${selectedCompanyName} 暂无隐患排名数据` : '暂无隐患排名数据'}
|
|
|
|
|
|
// </div>
|
|
|
|
|
|
// );
|
|
|
|
|
|
// }
|
2026-04-28 16:52:44 +08:00
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
|
|
|
|
|
|
<div
|
|
|
|
|
|
style={{
|
|
|
|
|
|
textAlign: 'center',
|
|
|
|
|
|
padding: '20px 0 0 0',
|
|
|
|
|
|
fontWeight: 'bold',
|
|
|
|
|
|
fontSize: '17px',
|
|
|
|
|
|
color: '#000',
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
2026-04-29 11:11:23 +08:00
|
|
|
|
隐患次数排名列表
|
2026-04-28 16:52:44 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div style={{ textAlign: 'right', padding: '10px 20px' }}>
|
|
|
|
|
|
<span style={{ marginRight: '8px', fontSize: '14px', color: '#000' }}>选择公司:</span>
|
|
|
|
|
|
<Select
|
|
|
|
|
|
value={selectedCompany || undefined}
|
|
|
|
|
|
onChange={onCompanyChange}
|
|
|
|
|
|
style={{ width: 150 }}
|
|
|
|
|
|
allowClear
|
|
|
|
|
|
placeholder="全部公司"
|
|
|
|
|
|
>
|
|
|
|
|
|
{this.getCompanyOptions()}
|
|
|
|
|
|
</Select>
|
|
|
|
|
|
</div>
|
2026-04-29 11:11:23 +08:00
|
|
|
|
{/* 公司筛选器 - 与 TrainingContent 样式保持一致 */}
|
|
|
|
|
|
|
2026-04-28 16:52:44 +08:00
|
|
|
|
<div style={{ flex: 1, overflow: 'auto', padding: '0 20px 20px 20px' }}>
|
|
|
|
|
|
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
|
|
|
|
|
|
<thead>
|
|
|
|
|
|
<tr style={{ backgroundColor: '#f5f5f5', borderBottom: '2px solid #e8e8e8' }}>
|
2026-04-29 11:11:23 +08:00
|
|
|
|
<th style={{ padding: '12px 8px', textAlign: 'center', fontWeight: 'bold', color: '#000' }}>序号</th>
|
2026-04-28 16:52:44 +08:00
|
|
|
|
<th style={{ padding: '12px 8px', textAlign: 'center', fontWeight: 'bold', color: '#000' }}>
|
|
|
|
|
|
隐患名称
|
|
|
|
|
|
</th>
|
|
|
|
|
|
<th style={{ padding: '12px 8px', textAlign: 'center', fontWeight: 'bold', color: '#000' }}>数量</th>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody>
|
2026-04-29 11:11:23 +08:00
|
|
|
|
{hiddenRanking.length > 0 ? (
|
|
|
|
|
|
hiddenRanking.map((item, index) => (
|
|
|
|
|
|
<tr
|
|
|
|
|
|
key={index}
|
|
|
|
|
|
style={{
|
|
|
|
|
|
borderBottom: '1px solid #e8e8e8',
|
|
|
|
|
|
backgroundColor: index % 2 === 0 ? '#fafafa' : '#fff',
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
<td style={{ padding: '10px 8px', textAlign: 'center', color: '#000' }}>
|
|
|
|
|
|
<span
|
|
|
|
|
|
style={{
|
|
|
|
|
|
padding: '10px 8px',
|
|
|
|
|
|
textAlign: 'center',
|
|
|
|
|
|
color: '#000',
|
|
|
|
|
|
fontWeight: 'bold',
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
{index + 1}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td style={{ padding: '10px 8px', textAlign: 'center', color: '#000' }}>{item.hiddenName}</td>
|
|
|
|
|
|
<td style={{ padding: '10px 8px', textAlign: 'center', color: '#000' }}>
|
|
|
|
|
|
<span style={{ color: '#4285F4', fontWeight: 'bold' }}>{item.qty}</span>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
))
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<div style={{ textAlign: 'center', padding: '50px', color: '#999' }}>{'暂无隐患排名数据'}</div>
|
|
|
|
|
|
)}
|
2026-04-28 16:52:44 +08:00
|
|
|
|
</tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
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) {
|
|
|
|
|
|
// 当 hiddenSubData 或 selectedCompany 变化时重新渲染图表
|
|
|
|
|
|
if (
|
|
|
|
|
|
prevProps.hiddenSubData !== this.props.hiddenSubData ||
|
|
|
|
|
|
prevProps.selectedCompany !== this.props.selectedCompany
|
|
|
|
|
|
) {
|
|
|
|
|
|
this.renderHiddenBarChart();
|
|
|
|
|
|
this.renderHiddenRectifyChart();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
|
|
this.isUnmounted = true;
|
|
|
|
|
|
this.disposeAllCharts();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
render() {
|
|
|
|
|
|
const { selectedCompany, onCompanyChange } = this.props;
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div className={styles.trainingContentWrapper}>
|
|
|
|
|
|
<div className={styles.trainingGrid}>
|
|
|
|
|
|
{/* 第一行 - 柱状图(left)+ 排名列表(right) */}
|
|
|
|
|
|
<div className={styles.trainingRow}>
|
|
|
|
|
|
<div className={styles.trainingCard} style={{ flex: '0 0 70%' }}>
|
|
|
|
|
|
{/* 添加公司筛选器(左上角,与 TrainingContent 样式一致) */}
|
|
|
|
|
|
<div id="hiddenBarChart" className={styles.trainingChartContainer}></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div className={styles.trainingCard} style={{ flex: '0 0 30%' }}>
|
|
|
|
|
|
{this.renderRankingList()}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{/* 第二行 - 隐患整改情况柱状图 */}
|
|
|
|
|
|
<div className={styles.trainingRow}>
|
|
|
|
|
|
<div className={styles.trainingCard}>
|
|
|
|
|
|
<div id="hiddenRectifyChart" className={styles.trainingChartContainer}></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default HiddenSolve;
|