危险作业
This commit is contained in:
parent
8dd014e583
commit
147baceeb0
@ -1,6 +1,7 @@
|
||||
// DangerJob.js - 危险作业页面组件
|
||||
import React from 'react';
|
||||
import { Table, Select, Pagination } from 'antd';
|
||||
import { Table, Select, Pagination, DatePicker } from 'antd';
|
||||
import echarts from 'echarts';
|
||||
import styles from './../fullinter.less';
|
||||
|
||||
const { Option } = Select;
|
||||
@ -10,9 +11,15 @@ class DangerJob extends React.Component {
|
||||
super(props);
|
||||
this.state = {
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
pageSize: 10,
|
||||
};
|
||||
this.echartsInstances = {
|
||||
dangerOperationChart: null, // 当日工作票统计柱状图
|
||||
};
|
||||
this.chartResizeHandlers = {};
|
||||
this.isUnmounted = false;
|
||||
// 添加缓存,用于比较数据是否真正变化
|
||||
this.lastJobTodayQty = null;
|
||||
}
|
||||
|
||||
// 生成公司选项(与 TrainingContent 保持一致)
|
||||
@ -23,8 +30,6 @@ class DangerJob extends React.Component {
|
||||
}
|
||||
return companyData.map((company, index) => (
|
||||
<Option key={company.ID || index} value={company.ID}>
|
||||
{' '}
|
||||
{/* 使用 ID 作为 value,与 TrainingContent 一致 */}
|
||||
{company.NAME}
|
||||
</Option>
|
||||
));
|
||||
@ -40,14 +45,222 @@ class DangerJob extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
// 处理开始日期变化
|
||||
startChange = (value) => {
|
||||
const { onStartChange } = this.props;
|
||||
this.setState({ currentPage: 1 }, () => {
|
||||
if (onStartChange) {
|
||||
onStartChange(value);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 处理结束日期变化
|
||||
endChange = (value) => {
|
||||
const { onEndChange } = this.props;
|
||||
this.setState({ currentPage: 1 }, () => {
|
||||
if (onEndChange) {
|
||||
onEndChange(value);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 处理页码变化
|
||||
handlePageChange = (page, pageSize) => {
|
||||
this.setState({ currentPage: page, pageSize });
|
||||
};
|
||||
|
||||
// 处理每页条数变化
|
||||
handleShowSizeChange = (current, size) => {
|
||||
this.setState({ currentPage: 1, pageSize: size });
|
||||
// 等待DOM元素加载完成
|
||||
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);
|
||||
});
|
||||
};
|
||||
|
||||
// 设置resize监听
|
||||
setupResizeHandler = (chartName, renderMethod) => {
|
||||
const resizeHandler = () => {
|
||||
if (this.echartsInstances[chartName] && !this.isUnmounted) {
|
||||
this.echartsInstances[chartName].resize();
|
||||
}
|
||||
};
|
||||
this.chartResizeHandlers[chartName] = resizeHandler;
|
||||
window.addEventListener('resize', resizeHandler);
|
||||
};
|
||||
|
||||
// 图表: 当日工作票统计柱状图
|
||||
renderDangerOperationChart = async () => {
|
||||
if (this.isUnmounted) return;
|
||||
const elementExists = await this.waitForElement('dangerOperationChart');
|
||||
if (!elementExists || this.isUnmounted) return;
|
||||
|
||||
if (this.echartsInstances.dangerOperationChart) {
|
||||
this.echartsInstances.dangerOperationChart.dispose();
|
||||
this.echartsInstances.dangerOperationChart = null;
|
||||
}
|
||||
|
||||
const chartDom = document.getElementById('dangerOperationChart');
|
||||
if (!chartDom) return;
|
||||
|
||||
this.echartsInstances.dangerOperationChart = echarts.init(chartDom);
|
||||
|
||||
const { jobTodayQty } = this.props;
|
||||
let linkData = jobTodayQty || [];
|
||||
|
||||
// 如果没有数据,显示“暂无数据”提示
|
||||
if (linkData.length === 0) {
|
||||
this.echartsInstances.dangerOperationChart.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 xAxisData = linkData.map((item) => item.name);
|
||||
const seriesData = linkData.map((item) => item.qty);
|
||||
|
||||
const option = {
|
||||
title: {
|
||||
text: '当日工作票的统计数量',
|
||||
x: 'center',
|
||||
y: '5%',
|
||||
textStyle: { fontSize: 16, color: '#000', fontWeight: 'bold' },
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: { type: 'shadow' },
|
||||
formatter: function (params) {
|
||||
const color = params[0].color;
|
||||
return `<div style="display: flex; align-items: center;">
|
||||
<span style="display: inline-block; width: 12px; height: 12px; background-color: ${color}; margin-right: 8px;"></span>
|
||||
<span>${params[0].name}:</span>
|
||||
<span style="font-weight: bold; margin-left: 8px; font-size: 16px;">${params[0].value}</span>
|
||||
</div>`;
|
||||
},
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.9)',
|
||||
borderColor: '#4285F4',
|
||||
borderWidth: 1,
|
||||
textStyle: { color: '#000', fontSize: 14 },
|
||||
},
|
||||
grid: {
|
||||
left: '8%',
|
||||
right: '5%',
|
||||
top: '18%',
|
||||
bottom: '8%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: xAxisData,
|
||||
axisLine: { show: false },
|
||||
axisTick: { show: false },
|
||||
axisLabel: {
|
||||
textStyle: { color: '#000' },
|
||||
rotate: xAxisData.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: seriesData,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: '#4285F4',
|
||||
borderRadius: [12, 12, 0, 0],
|
||||
},
|
||||
emphasis: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.3)',
|
||||
},
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
textStyle: { color: '#4285F4', fontSize: 12, fontWeight: 'bold' },
|
||||
formatter: (params) => `${params.value}`,
|
||||
},
|
||||
barWidth: '50%',
|
||||
barMaxWidth: 60,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
this.echartsInstances.dangerOperationChart.setOption(option);
|
||||
this.setupResizeHandler('dangerOperationChart', this.renderDangerOperationChart);
|
||||
};
|
||||
|
||||
// 初始化所有图表
|
||||
initAllCharts = () => {
|
||||
if (this.isUnmounted) return;
|
||||
setTimeout(() => {
|
||||
if (this.isUnmounted) return;
|
||||
this.renderDangerOperationChart();
|
||||
}, 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 = {};
|
||||
};
|
||||
|
||||
// 获取过滤后的数据(添加类型检查和默认值)
|
||||
@ -88,35 +301,35 @@ class DangerJob extends React.Component {
|
||||
};
|
||||
};
|
||||
|
||||
// 添加 shouldComponentUpdate 优化性能
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
// 检查状态变化
|
||||
if (this.state.currentPage !== nextState.currentPage || this.state.pageSize !== nextState.pageSize) {
|
||||
return true;
|
||||
}
|
||||
// 检查 props 变化
|
||||
if (
|
||||
this.props.jobTodayQty !== nextProps.jobTodayQty ||
|
||||
this.props.dangerSubData !== nextProps.dangerSubData ||
|
||||
this.props.selectedCompany !== nextProps.selectedCompany ||
|
||||
this.props.selectedStartDate !== nextProps.selectedStartDate ||
|
||||
this.props.selectedEndDate !== nextProps.selectedEndDate ||
|
||||
this.props.companyData !== nextProps.companyData
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 渲染危险作业表格
|
||||
renderDangerTable = () => {
|
||||
const { selectedCompany, companyData } = this.props;
|
||||
const { currentPage, pageSize } = this.state;
|
||||
const { data: tableData, total } = this.getCurrentPageData();
|
||||
|
||||
// 如果没有数据,返回空
|
||||
if (!tableData || tableData.length === 0) {
|
||||
// 获取选中的公司名称用于显示
|
||||
let companyName = '';
|
||||
if (selectedCompany && companyData) {
|
||||
const selectedCompanyObj = companyData.find((company) => company.ID === selectedCompany);
|
||||
companyName = selectedCompanyObj?.NAME || '';
|
||||
}
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
padding: '50px',
|
||||
color: '#999',
|
||||
fontSize: '26px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
{selectedCompany ? `${companyName}暂无危险作业数据` : '暂无危险作业数据'}
|
||||
</div>
|
||||
);
|
||||
return <div style={{ textAlign: 'center', padding: '50px', color: '#999' }}>暂无危险作业数据</div>;
|
||||
}
|
||||
|
||||
// 表格列配置
|
||||
@ -196,10 +409,8 @@ class DangerJob extends React.Component {
|
||||
},
|
||||
];
|
||||
|
||||
// 计算横向滚动宽度(如果列数过多)
|
||||
const scrollX = columns.reduce((sum, col) => sum + (col.width || 120), 0);
|
||||
const scrollConfig = scrollX > 1200 ? { x: scrollX } : {};
|
||||
|
||||
// 不设置 y 滚动,让表格自然高度,由外层容器控制滚动
|
||||
const scrollConfig = { x: columns.length * 100, y: 320 };
|
||||
// 表格数据转换(添加唯一key)
|
||||
const dataSource = tableData.map((item, index) => ({
|
||||
key: `${item.companyName}_${item.startDate}_${index}`,
|
||||
@ -215,6 +426,7 @@ class DangerJob extends React.Component {
|
||||
}));
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
|
||||
<div
|
||||
style={{
|
||||
@ -227,13 +439,13 @@ class DangerJob extends React.Component {
|
||||
>
|
||||
当日各公司危险作业清单
|
||||
</div>
|
||||
<div style={{ flex: 1, padding: '10px' }}>
|
||||
<div style={{ flex: 1, minHeight: 0, padding: '10px' }}>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={dataSource}
|
||||
pagination={false}
|
||||
scroll={scrollConfig}
|
||||
size="small"
|
||||
size="middle"
|
||||
bordered
|
||||
className={styles.certificateTable}
|
||||
/>
|
||||
@ -247,9 +459,9 @@ class DangerJob extends React.Component {
|
||||
padding: '12px 16px',
|
||||
borderTop: '1px solid #f0f0f0',
|
||||
backgroundColor: '#fff',
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
{/* 自定义每页条数选择器 */}
|
||||
<div>
|
||||
<span style={{ marginRight: '8px' }}>每页显示:</span>
|
||||
<Select
|
||||
@ -267,20 +479,19 @@ class DangerJob extends React.Component {
|
||||
current={currentPage}
|
||||
pageSize={pageSize}
|
||||
total={total}
|
||||
// showSizeChanger
|
||||
showQuickJumper
|
||||
showTotal={(total) => `共 ${total} 条记录`}
|
||||
onChange={this.handlePageChange}
|
||||
onShowSizeChange={false}
|
||||
// pageSizeOptions={['10', '20']}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.isUnmounted = false;
|
||||
this.initAllCharts();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
@ -288,6 +499,13 @@ class DangerJob extends React.Component {
|
||||
if (prevProps.selectedCompany !== this.props.selectedCompany) {
|
||||
this.setState({ currentPage: 1 });
|
||||
}
|
||||
if (prevProps.selectedStartDate !== this.props.selectedStartDate) {
|
||||
this.setState({ currentPage: 1 });
|
||||
}
|
||||
if (prevProps.selectedEndDate !== this.props.selectedEndDate) {
|
||||
this.setState({ currentPage: 1 });
|
||||
}
|
||||
|
||||
// 当数据变化时,如果当前页没有数据且不是第一页,重置到第一页
|
||||
if (prevProps.dangerSubData !== this.props.dangerSubData) {
|
||||
const { currentPage } = this.state;
|
||||
@ -298,21 +516,31 @@ class DangerJob extends React.Component {
|
||||
this.setState({ currentPage: 1 });
|
||||
}
|
||||
}
|
||||
|
||||
// 检查 jobTodayQty 是否变化,只在数据真正变化时重新渲染图表
|
||||
const prevJobTodayQty = prevProps.jobTodayQty;
|
||||
const currentJobTodayQty = this.props.jobTodayQty;
|
||||
const jobTodayQtyChanged = JSON.stringify(prevJobTodayQty) !== JSON.stringify(currentJobTodayQty);
|
||||
|
||||
if (jobTodayQtyChanged) {
|
||||
this.renderDangerOperationChart();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.isUnmounted = true;
|
||||
this.disposeAllCharts();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { companyData, selectedCompany } = this.props;
|
||||
const { companyData, selectedCompany, selectedStartDate, selectedEndDate } = this.props;
|
||||
|
||||
return (
|
||||
<div className={styles.trainingContentWrapper}>
|
||||
<div className={styles.trainingGrid}>
|
||||
<div className={styles.trainingRow}>
|
||||
<div className={styles.trainingCard}>
|
||||
{/* 公司筛选器 */}
|
||||
{/* 筛选器 */}
|
||||
<div className={styles.monthSelectorWrapper}>
|
||||
<span className={styles.monthSelectorLabel}>选择公司:</span>
|
||||
<Select
|
||||
@ -325,10 +553,24 @@ class DangerJob extends React.Component {
|
||||
>
|
||||
{this.getCompanyOptions()}
|
||||
</Select>
|
||||
<span className={styles.monthSelectorLabel} style={{ margin: '0 20px' }}>
|
||||
开始日期:
|
||||
</span>
|
||||
<DatePicker value={selectedStartDate} format="YYYY-MM-DD" onChange={this.startChange} />
|
||||
<span className={styles.monthSelectorLabel} style={{ margin: '0 20px' }}>
|
||||
结束日期:
|
||||
</span>
|
||||
<DatePicker value={selectedEndDate} format="YYYY-MM-DD" onChange={this.endChange} />
|
||||
</div>
|
||||
{this.renderDangerTable()}
|
||||
</div>
|
||||
</div>
|
||||
{/* 第二行 - 当日工作票统计柱状图 */}
|
||||
<div className={styles.trainingRow}>
|
||||
<div className={styles.trainingCard}>
|
||||
<div id="dangerOperationChart" className={styles.trainingChartContainer}></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -575,7 +575,7 @@ class HomeContent extends React.Component {
|
||||
if (this.isUnmounted) return;
|
||||
this.riskLevel();
|
||||
this.safeCheckChart();
|
||||
this.dangerOperation();
|
||||
// this.dangerOperation();
|
||||
this.backLog();
|
||||
}, 100);
|
||||
};
|
||||
@ -970,15 +970,15 @@ class HomeContent extends React.Component {
|
||||
>
|
||||
<div className={styles.infoSpan}>
|
||||
<span>露天矿</span>
|
||||
<span>1家</span>
|
||||
<span>--家</span>
|
||||
</div>
|
||||
<div className={styles.infoSpan}>
|
||||
<span>地下矿</span>
|
||||
<span>12家</span>
|
||||
<span>--家</span>
|
||||
</div>
|
||||
<div className={styles.infoSpan}>
|
||||
<span>尾矿库</span>
|
||||
<span>13家</span>
|
||||
<span>--家</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -14,6 +14,7 @@ import RiskControl from './FullOther/RiskControl';
|
||||
import ClassBuild from './FullOther/ClassBuild';
|
||||
import DangerJob from './FullOther/DangerJob';
|
||||
import HiddenSolve from './FullOther/HiddenSolve';
|
||||
import moment from 'moment'; // 添加这一行
|
||||
|
||||
const getScale = () => {
|
||||
const width = 1920,
|
||||
@ -30,7 +31,7 @@ class FullScreen extends React.Component {
|
||||
nowDate: '',
|
||||
riskTypeRate: [],
|
||||
riskTotal: [],
|
||||
jobTodayQty: [],
|
||||
// jobTodayQty: [],
|
||||
hiddenSummary: [],
|
||||
taskTop3: [],
|
||||
scale: getScale(),
|
||||
@ -77,8 +78,11 @@ class FullScreen extends React.Component {
|
||||
riskSubData: {},
|
||||
classSubData: [],
|
||||
dangerSubData: {},
|
||||
jobTodayQty: [],
|
||||
dangerCompanyData: [],
|
||||
selectedDangerCompany: '',
|
||||
selectedStartDate: moment(),
|
||||
selectedEndDate: moment(),
|
||||
|
||||
announcementDetail: null,
|
||||
announcementDetailLoading: false,
|
||||
@ -289,7 +293,7 @@ class FullScreen extends React.Component {
|
||||
if (ret && !this.isUnmounted) {
|
||||
this.setState({
|
||||
riskTypeRate: ret.riskTypeRate || [],
|
||||
jobTodayQty: ret.jobTodayQty || [],
|
||||
// jobTodayQty: ret.jobTodayQty || [],
|
||||
hiddenSummary: ret.hiddenSummary || [],
|
||||
taskTop3: ret.taskTop3 || [],
|
||||
});
|
||||
@ -589,17 +593,29 @@ class FullScreen extends React.Component {
|
||||
this.getDangerSubData();
|
||||
});
|
||||
};
|
||||
handleStartDateChange = (startDate) => {
|
||||
this.setState({ selectedStartDate: startDate }, () => {
|
||||
this.getDangerSubData();
|
||||
});
|
||||
};
|
||||
handleEndDateChange = (endDate) => {
|
||||
this.setState({ selectedEndDate: endDate }, () => {
|
||||
this.getDangerSubData();
|
||||
});
|
||||
};
|
||||
|
||||
getDangerSubData = () => {
|
||||
const orgId = storage('lacal').getItem('webOrgId')?.val;
|
||||
const json = initFilter(orgId);
|
||||
json.Parameter1 = this.state.selectedStartDate.format('YYYY-MM-DD');
|
||||
json.Parameter2 = this.state.selectedEndDate.format('YYYY-MM-DD');
|
||||
this.props.dispatch({
|
||||
type: 'app/getDataByPost',
|
||||
payload: json,
|
||||
url: 'BI/BIKanBanController/JobManage',
|
||||
onComplete: (ret) => {
|
||||
if (ret && !this.isUnmounted) {
|
||||
let filteredData = ret;
|
||||
let filteredData = ret.jobList;
|
||||
if (this.state.selectedDangerCompany) {
|
||||
const selectedCompanyObj = this.state.dangerCompanyData?.find(
|
||||
(company) => company.ID === this.state.selectedDangerCompany
|
||||
@ -612,6 +628,7 @@ class FullScreen extends React.Component {
|
||||
|
||||
this.setState({
|
||||
dangerSubData: filteredData,
|
||||
jobTodayQty: ret.jobTodayQty,
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -670,9 +687,14 @@ class FullScreen extends React.Component {
|
||||
return (
|
||||
<DangerJob
|
||||
dangerSubData={this.state.dangerSubData}
|
||||
jobTodayQty={this.state.jobTodayQty}
|
||||
companyData={this.state.dangerCompanyData}
|
||||
selectedCompany={this.state.selectedDangerCompany}
|
||||
onCompanyChange={this.handleDangerCompanyChange}
|
||||
selectedStartDate={this.state.selectedStartDate}
|
||||
onStartChange={this.handleStartDateChange}
|
||||
selectedEndDate={this.state.selectedEndDate}
|
||||
onEndChange={this.handleEndDateChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -761,7 +783,7 @@ class FullScreen extends React.Component {
|
||||
riskTypeRate={riskTypeRate}
|
||||
riskTotal={riskTotal}
|
||||
hiddenSummary={hiddenSummary}
|
||||
jobTodayQty={jobTodayQty}
|
||||
// jobTodayQty={jobTodayQty}
|
||||
taskTop3={taskTop3}
|
||||
mediaList={mediaList}
|
||||
announcementList={announcementList}
|
||||
|
||||
@ -174,7 +174,7 @@
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
color: #000;
|
||||
margin-bottom: 24px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.infoCard {
|
||||
display: flex;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user