mh_jy_safe_web/src/layout/FullOther/HomeContent.js
2026-05-21 17:10:47 +08:00

1057 lines
36 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// HomeContent.js
import React, { useEffect, useRef } from 'react';
import { Row, Col, Icon, Modal, Button } from 'antd';
import Slider from 'react-slick';
import styles from './../fullinter.less';
import echarts from 'echarts';
import configc from '../../config';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
import { extendRule, showFileModal, showFiles, GetFileModel } from '../../utils/common';
import FormPage from '../../components/FormPage';
class HomeContent extends React.Component {
constructor(props) {
super(props);
this.sliderRef = React.createRef();
this.echartsInstances = {
riskLevel: null,
safeCheckChart: null,
dangerOperation: null,
backLogChart: null,
};
this.chartResizeHandlers = {};
this.isUnmounted = false;
this.autoplayTimer = null;
this.state = {
fileForm: {
title: '',
visible: false,
},
};
}
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);
});
};
riskLevel = async () => {
if (this.isUnmounted) return;
const elementExists = await this.waitForElement('riskLevelFull');
if (!elementExists || this.isUnmounted) return;
if (this.echartsInstances.riskLevel) {
this.echartsInstances.riskLevel.dispose();
this.echartsInstances.riskLevel = null;
}
const riskLevels = document.getElementById('riskLevelFull');
if (!riskLevels) return;
this.echartsInstances.riskLevel = echarts.init(riskLevels);
const data = this.props.riskTypeRate || [];
const option = {
color: ['#c92a2a', '#ffa94d', '#ffe066', '#4285F4'],
title: [
{
text: '风险分级占比',
x: 'center',
y: '5%',
textStyle: { fontSize: 16, color: '#000' },
},
],
tooltip: {
trigger: 'item',
formatter: function (params) {
const color = params.color;
return `<div style="display: flex; align-items: center;">
<span style="display: inline-block; width: 12px; height: 12px; border-radius: 50%; background-color: ${color}; margin-right: 8px;"></span>
<span>${params.name}:</span>
<span style="font-weight: bold; margin-left: 8px; font-size: 16px;">${params.value}</span>
</div>`;
},
backgroundColor: 'rgba(255, 255, 255, 0.5)',
borderColor: '#FFFFFF',
borderWidth: 2,
textStyle: { color: '#000', fontSize: 14 },
},
series: [
{
name: '访问来源',
type: 'pie',
minAngle: 20,
radius: ['55%', '80%'],
center: ['50%', '50%'],
clockwise: true,
avoidLabelOverlap: true,
hoverOffset: 15,
label: {
show: true,
position: 'inside',
formatter: '{d}%', // 添加 \n 换行符
color: '#000',
textBorderWidth: 0,
rich: {
a: { padding: [-15, 0, 0, 0], fontSize: 15, color: '#000', textBorderWidth: 0 },
e: { fontSize: 14, color: '#000', padding: [-15, 0, 0, 5], textBorderWidth: 0 },
},
},
labelLine: { normal: { show: false } },
data: data.map((item) => ({ name: item.riskType, value: item.count })),
},
],
};
this.echartsInstances.riskLevel.setOption(option);
const resizeHandler = () => {
if (this.echartsInstances.riskLevel && !this.isUnmounted) {
this.echartsInstances.riskLevel.resize();
}
};
this.chartResizeHandlers.riskLevel = resizeHandler;
window.addEventListener('resize', resizeHandler);
};
safeCheckChart = async () => {
if (this.isUnmounted) return;
const elementExists = await this.waitForElement('safeCheckChart');
if (!elementExists || this.isUnmounted) return;
if (this.echartsInstances.safeCheckChart) {
this.echartsInstances.safeCheckChart.dispose();
this.echartsInstances.safeCheckChart = null;
}
let safeCheckCharts = document.getElementById('safeCheckChart');
if (!safeCheckCharts) return;
const hiddenSummary = this.props.hiddenSummary || {};
// 检查是否有有效数据
const hasData =
hiddenSummary.monthMajorQty !== undefined ||
hiddenSummary.unfinishMonthMajorQty !== undefined ||
hiddenSummary.monthGeneralQty !== undefined ||
hiddenSummary.unfinishMonthGeneralQty !== undefined;
if (!hasData) {
this.echartsInstances.safeCheckChart = echarts.init(safeCheckCharts);
this.echartsInstances.safeCheckChart.setOption({
title: {
text: '当月隐患统计',
x: 'center',
y: '25%',
textStyle: { fontSize: 16, color: '#fff' },
},
graphic: {
type: 'text',
left: 'center',
top: 'middle',
style: {
text: '暂无数据',
fill: '#999',
fontSize: 14,
},
},
});
return;
}
// 定义图例和数据
const legendData = ['重大隐患数', '重大隐患未整改数', '一般隐患数', '一般隐患未整改数'];
const seriesData = [
{ name: '重大隐患数', value: hiddenSummary.monthMajorQty || 0, color: '#c92a2a' },
{ name: '重大隐患未整改数', value: hiddenSummary.unfinishMonthMajorQty || 0, color: '#ffa94d' },
{ name: '一般隐患数', value: hiddenSummary.monthGeneralQty || 0, color: '#ffe066' },
{ name: '一般隐患未整改数', value: hiddenSummary.unfinishMonthGeneralQty || 0, color: '#4285F4' },
];
this.echartsInstances.safeCheckChart = echarts.init(safeCheckCharts);
this.echartsInstances.safeCheckChart.setOption({
title: {
text: '当月隐患统计',
x: 'center',
y: '5%',
textStyle: { fontSize: 16, color: '#000' },
},
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
formatter: function (params) {
if (!params || params.length === 0) return '';
let result = `${params[0].axisValue}<br/>`;
params.forEach((param) => {
result += `${param.marker}${param.seriesName}: ${param.value}<br/>`;
});
return result;
},
},
legend: {
data: legendData,
right: '3%',
top: '10%',
itemGap: 12,
itemWidth: 16,
itemHeight: 10,
textStyle: { color: '#000', fontSize: 12 },
},
color: seriesData.map((item) => item.color),
grid: {
left: '5%',
right: '8%',
top: '28%',
bottom: '5%',
containLabel: true,
},
xAxis: [
{
type: 'category',
data: ['当月隐患'],
axisLine: { lineStyle: { color: '#c4c6c9' } },
axisLabel: { textStyle: { color: '#000', fontSize: 14 } },
axisTick: { show: false },
},
],
yAxis: [
{
type: 'value',
name: '数量',
nameTextStyle: { color: '#000' },
axisLine: { show: false },
axisTick: { show: false },
splitLine: { show: false },
axisLabel: { textStyle: { color: '#000' } },
},
],
series: seriesData.map((item) => ({
name: item.name,
type: 'bar',
data: [item.value],
itemStyle: {
normal: {
color: item.color,
barBorderRadius: [8, 8, 0, 0],
},
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)',
},
},
label: {
show: true,
position: 'top',
textStyle: { color: '#000', fontSize: 12 },
formatter: '{c}',
},
barWidth: '10%',
barGap: '30%',
barCategoryGap: '20%',
})),
});
const resizeHandler = () => {
if (this.echartsInstances.safeCheckChart && !this.isUnmounted) {
this.echartsInstances.safeCheckChart.resize();
}
};
this.chartResizeHandlers.safeCheckChart = resizeHandler;
window.addEventListener('resize', resizeHandler);
};
dangerOperation = async () => {
if (this.isUnmounted) return;
const elementExists = await this.waitForElement('dangerOperationChart');
if (!elementExists || this.isUnmounted) return;
if (this.echartsInstances.dangerOperation) {
this.echartsInstances.dangerOperation.dispose();
this.echartsInstances.dangerOperation = null;
}
const dangerOperationCharts = document.getElementById('dangerOperationChart');
if (!dangerOperationCharts) return;
const linkData = this.props.jobTodayQty || [];
// 如果没有数据,显示“暂无数据”提示
if (linkData.length === 0) {
this.echartsInstances.dangerOperation = echarts.init(dangerOperationCharts);
this.echartsInstances.dangerOperation.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;
}
// 有数据时正常渲染图表
this.echartsInstances.dangerOperation = echarts.init(dangerOperationCharts);
const xAxisData = linkData.map((item) => item.name);
const seriesData = linkData.map((item) => item.qty);
const option = {
color: ['#4285F4'],
title: [
{
text: '当日工作票的统计数量',
x: 'center',
y: '5%',
textStyle: { fontSize: 16, color: '#000' },
},
],
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.5)',
borderColor: '#FFFFFF',
borderWidth: 2,
textStyle: { color: '#000', fontSize: 14 },
},
grid: { left: '10%', right: '5%', top: '15%', bottom: '10%', containLabel: true },
xAxis: [
{
type: 'category',
data: xAxisData,
axisLine: { lineStyle: { color: '#c4c6c9' } },
axisTick: { show: false },
axisLabel: { textStyle: { color: '#000' }, rotate: 30, interval: 0 },
},
],
yAxis: [
{
type: 'value',
name: '',
nameTextStyle: { color: '#000' },
axisLine: { show: false },
axisTick: { show: false },
axisLabel: { textStyle: { color: '#000' } },
splitLine: { show: false },
},
],
series: [
{
name: '危险作业数量',
type: 'bar',
data: seriesData,
itemStyle: {
normal: { color: '#4285F4', barBorderRadius: 12 },
emphasis: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' },
},
label: { show: true, position: 'top', textStyle: { color: '#000', fontSize: 12 }, formatter: '{c}' },
barWidth: '60%',
barMaxWidth: 40,
},
],
};
this.echartsInstances.dangerOperation.setOption(option);
const resizeHandler = () => {
if (this.echartsInstances.dangerOperation && !this.isUnmounted) {
this.echartsInstances.dangerOperation.resize();
}
};
this.chartResizeHandlers.dangerOperation = resizeHandler;
window.addEventListener('resize', resizeHandler);
};
backLog = async () => {
if (this.isUnmounted) return;
const elementExists = await this.waitForElement('backLogChart');
if (!elementExists || this.isUnmounted) return;
if (this.echartsInstances.backLogChart) {
this.echartsInstances.backLogChart.dispose();
this.echartsInstances.backLogChart = null;
}
let backLogCharts = document.getElementById('backLogChart');
if (!backLogCharts) return;
// 使用培训数据
const { trainingData } = this.props;
const listNAME = trainingData?.listNAME || [];
const monthRecordCount = trainingData?.MonthRecordCount || []; // 培训场次
const monthPersonCount = trainingData?.MonthPersonCount || []; // 培训人次
if (listNAME.length === 0) {
this.echartsInstances.backLogChart = echarts.init(backLogCharts);
this.echartsInstances.backLogChart.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;
}
this.echartsInstances.backLogChart = echarts.init(backLogCharts);
const option = {
title: {
text: '当月培训统计数量',
x: 'center',
y: '5%',
textStyle: { fontSize: 16, color: '#000' },
},
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: ['培训人次', '培训场次'],
right: '3%',
top: '10%',
itemGap: 12,
itemWidth: 16,
itemHeight: 10,
textStyle: { color: '#000', fontSize: 12 },
},
grid: {
left: '5%',
right: '5%',
top: '28%',
bottom: '5%',
containLabel: true,
},
xAxis: [
{
type: 'category',
data: listNAME,
axisLine: { lineStyle: { color: '#c4c6c9' } },
axisTick: { show: false },
axisLabel: {
textStyle: { color: '#000' },
rotate: listNAME.length > 4 ? 15 : 0,
interval: 0,
},
},
],
yAxis: [
{
type: 'value',
show: true,
axisLine: { show: false },
axisTick: { show: false },
axisLabel: {
show: true,
textStyle: { color: '#000' },
},
splitLine: { show: false },
name: '',
nameTextStyle: { show: false },
},
],
series: [
{
name: '培训人次',
type: 'bar',
data: monthPersonCount,
itemStyle: {
normal: {
color: '#4285F4',
barBorderRadius: 12,
},
},
label: {
show: true,
position: 'top',
textStyle: { color: '#4285F4', fontSize: 12 },
formatter: '{c}',
},
barWidth: '35%',
},
{
name: '培训场次',
type: 'bar',
data: monthRecordCount,
itemStyle: {
normal: {
color: '#ffe066',
barBorderRadius: 12,
},
},
label: {
show: true,
position: 'top',
textStyle: { color: '#ffe066', fontSize: 12 },
formatter: '{c}',
},
barWidth: '35%',
},
],
};
this.echartsInstances.backLogChart.setOption(option);
const resizeHandler = () => {
if (this.echartsInstances.backLogChart && !this.isUnmounted) {
this.echartsInstances.backLogChart.resize();
}
};
this.chartResizeHandlers.backLogChart = resizeHandler;
window.addEventListener('resize', resizeHandler);
};
// 启动自动轮播
startAutoplay = (intervalTime) => {
this.stopAutoplay();
if (!intervalTime || intervalTime <= 0) return;
this.autoplayTimer = setInterval(() => {
if (this.sliderRef.current && !this.isUnmounted) {
const nextIndex = (this.props.currentMediaIndex + 1) % (this.props.trainingData?.listVideoImg?.length || 1);
this.props.onCarouselChange?.(nextIndex);
this.sliderRef.current.slickGoTo(nextIndex);
}
}, intervalTime);
};
// 停止自动轮播
stopAutoplay = () => {
if (this.autoplayTimer) {
clearInterval(this.autoplayTimer);
this.autoplayTimer = null;
}
};
initAllCharts = () => {
if (this.isUnmounted) return;
setTimeout(() => {
if (this.isUnmounted) return;
this.riskLevel();
this.safeCheckChart();
// this.dangerOperation();
this.backLog();
}, 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 = {};
};
handlePrev = () => {
if (this.sliderRef.current) {
this.sliderRef.current.slickPrev();
const nextIndex = this.props.currentMediaIndex - 1;
if (nextIndex >= 0) {
this.props.onCarouselChange?.(nextIndex);
}
// 鼠标点击时重启自动播放计时器
this.restartAutoplay();
}
};
handleNext = () => {
if (this.sliderRef.current) {
this.sliderRef.current.slickNext();
const nextIndex = this.props.currentMediaIndex + 1;
const total = this.props.trainingData?.listVideoImg?.length || 0;
if (nextIndex < total) {
this.props.onCarouselChange?.(nextIndex);
}
// 鼠标点击时重启自动播放计时器
this.restartAutoplay();
}
};
// 重启自动播放
restartAutoplay = () => {
const playSet = this.props.trainingData?.playSet || {};
const isAutoplay = playSet.IMG_ISRE !== undefined ? playSet.IMG_ISRE : true;
const autoplaySpeed = playSet.IMG_TIMESPAN ? playSet.IMG_TIMESPAN * 1000 : 5000;
if (isAutoplay && autoplaySpeed > 0) {
this.startAutoplay(autoplaySpeed);
}
};
handleDotClick = (index) => {
this.props.onDotClick?.(index);
if (this.sliderRef.current) {
this.sliderRef.current.slickGoTo(index);
}
// 点击圆点时重启自动播放
this.restartAutoplay();
};
handleCarouselChange = (current) => {
this.props.onCarouselChange?.(current);
};
componentDidMount() {
this.isUnmounted = false;
this.initAllCharts();
}
componentDidUpdate(prevProps) {
// 当 trainingData 变化时,重新初始化自动播放
if (
prevProps.trainingData?.playSet?.IMG_ISRE !== this.props.trainingData?.playSet?.IMG_ISRE ||
prevProps.trainingData?.playSet?.IMG_TIMESPAN !== this.props.trainingData?.playSet?.IMG_TIMESPAN
) {
this.restartAutoplay();
}
if (
prevProps.riskTypeRate !== this.props.riskTypeRate ||
prevProps.hiddenSummary !== this.props.hiddenSummary ||
prevProps.jobTodayQty !== this.props.jobTodayQty ||
prevProps.taskTop3 !== this.props.taskTop3 ||
prevProps.trainingData !== this.props.trainingData
) {
this.disposeAllCharts();
this.initAllCharts();
}
}
componentWillUnmount() {
this.isUnmounted = true;
this.stopAutoplay();
this.disposeAllCharts();
}
// 新增:下载附件方法
handleDownload = (file) => {
const fileUrl = configc.picServerHost + file.Nav_ImgFile.FILE_PATH;
const link = document.createElement('a');
link.href = fileUrl;
link.download = file.Nav_ImgFile.FILE_NAME;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
// 新增:预览附件方法
handlePreview = (file) => {
const fileUrl = configc.picServerHost + file.Nav_ImgFile.FILE_PATH;
window.open(fileUrl, '_blank');
};
// 新增:渲染公告弹窗内容
renderAnnouncementModal = () => {
const { currentAnnouncement, announcementDetailLoading } = this.props;
if (announcementDetailLoading) {
return (
<div style={{ textAlign: 'center', padding: '50px' }}>
<Icon type="loading" style={{ fontSize: '32px' }} />
</div>
);
}
if (!currentAnnouncement) return null;
const { TITLE, ABSTRACT, START, END, CONTENT, CREATE_USER_NAME, Nav_Files = [] } = currentAnnouncement;
return (
<div>
{/* 标题 */}
<div style={{ textAlign: 'center', fontSize: '16px', color: '#333', marginBottom: '16px', fontWeight: 'bold' }}>
{TITLE}
</div>
{/* 摘要 */}
<div
style={{
fontSize: '14px',
color: '#676767',
wordBreak: 'break-all',
wordWrap: 'break-word',
marginBottom: '12px',
lineHeight: '1.5',
}}
>
{ABSTRACT}
</div>
{/* 日期 */}
<div style={{ fontSize: '12px', color: '#999', marginBottom: '16px', textAlign: 'center' }}>
{START ? START : '--'} {END ? END : '--'}
<span style={{ marginLeft: '20px' }}>{CREATE_USER_NAME ? CREATE_USER_NAME : ''}</span>
</div>
{/* 分割线 */}
<div style={{ borderTop: '1px solid #e8e8e8', marginBottom: '16px' }}></div>
{/* 正文内容 */}
<div
className={styles.announcementContent}
dangerouslySetInnerHTML={{ __html: CONTENT || '' }}
style={{
fontSize: '14px',
lineHeight: '1.6',
color: '#333',
marginBottom: '16px',
}}
/>
{/* 附件列表 */}
{Nav_Files && Nav_Files.length > 0 && (
<div style={{ marginTop: '16px' }}>
<div style={{ fontWeight: 'bold', marginBottom: '12px', fontSize: '14px', color: '#333' }}>
附件 ({Nav_Files.length})
</div>
{showFiles(Nav_Files, configc.picServerHost, this)}
{GetFileModel(Modal, FormPage, this, this.state.fileForm.visible)}
<FormPage {...this.state.tmpData} />
</div>
)}
</div>
);
};
render() {
const {
riskTypeRate = [],
currentMediaIndex = 0,
hiddenSummary = {},
trainingData = {}, // 新增 props
onAnnouncementClick,
announcementModalVisible,
onAnnouncementModalClose,
} = this.props;
// 获取播放配置,提供默认值
const playSet = trainingData.playSet || {};
const videoConfig = {
autoPlay: playSet.V_ISAUTO !== undefined ? playSet.V_ISAUTO : true,
loop: playSet.V_ISRE !== undefined ? playSet.V_ISRE : true,
muted: playSet.V_ISSILENT !== undefined ? playSet.V_ISSILENT : true,
controls: playSet.V_ISSHOWCONTROL !== undefined ? playSet.V_ISSHOWCONTROL : false,
};
const isAutoplay = playSet.IMG_ISRE !== undefined ? playSet.IMG_ISRE : true;
const autoplaySpeed = playSet.IMG_TIMESPAN ? playSet.IMG_TIMESPAN * 1000 : 5000;
const slickSettings = {
dots: false,
arrows: false, // 🔑 隐藏默认箭头 ← 添加这一行
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
autoplay: isAutoplay,
autoplaySpeed: autoplaySpeed,
fade: true,
pauseOnHover: true,
afterChange: this.handleCarouselChange,
};
return (
<div className={styles.homeContentWrapper}>
<Row className={styles.homeContentRow} gutter={0}>
{/* 左侧区域 */}
<Col span={7} className={styles.leftCol}>
<div className={styles.riskCard}>
<Row className={styles.riskRow}>
<Col span={8} className={styles.riskStatsCol}>
{riskTypeRate.map((item, index) => (
<div key={index} className={`${styles.riskStatItem} ${styles['riskLevel' + item.riskType]}`}>
<div className={styles.riskStatName}>{item.riskType}</div>
<div className={styles.riskStatValue}>{item.count}</div>
</div>
))}
</Col>
<Col span={16} className={styles.chartCol}>
<div id="riskLevelFull" className={styles.chartContainer}></div>
</Col>
</Row>
</div>
<div className={styles.spacer}></div>
<div className={styles.hiddenCard}>
<Row className={styles.riskRow}>
<Col span={8} className={styles.hiddenStatsCol}>
<div className={styles.hiddenTitle}>年度隐患数据</div>
<div className={styles.hiddenStatItem}>
<div className={styles.hiddenStatName}>年度重大隐患数量</div>
<div className={styles.hiddenStatValue}>{hiddenSummary.majorQty}</div>
</div>
<div className={styles.hiddenStatItem}>
<div className={styles.hiddenStatName}>年度一般隐患数量</div>
<div className={styles.hiddenStatValue}>{hiddenSummary.generalQty}</div>
</div>
<div className={styles.hiddenStatItem}>
<div className={styles.hiddenStatName}>未整改隐患数量</div>
<div className={styles.hiddenStatValue}>{hiddenSummary.unfinishQty}</div>
</div>
</Col>
<Col span={16} className={styles.chartCol}>
<div id="safeCheckChart" className={styles.chartContainer}></div>
</Col>
</Row>
</div>
</Col>
{/* 中间区域 */}
<Col span={10} className={styles.middleCol}>
<div className={styles.sloganCard}>
<div className={styles.sloganContent} dangerouslySetInnerHTML={{ __html: trainingData.TITLE }} />
</div>
<div className={styles.carouselCard}>
<div className={styles.carouselWrapper}>
{trainingData.listVideoImg && trainingData.listVideoImg[0] ? (
trainingData.listVideoImg[0].TYPE == 10 ? (
<video
src={configc.picServerHost + trainingData.listVideoImg[0].FILE_PATH}
className={styles.mediaVideo}
autoplay={videoConfig.autoPlay ? 'autoplay' : undefined}
loop={videoConfig.loop ? 'loop' : undefined}
muted={videoConfig.muted ? 'muted' : undefined}
controls={videoConfig.controls ? 'controls' : undefined}
playsInline
/>
) : (
<div>
<Slider ref={this.sliderRef} {...slickSettings} className={styles.carousel}>
{trainingData.listVideoImg?.map((item, index) => (
<div key={index} className={styles.carouselItem}>
<img src={configc.picServerHost + item.FILE_PATH} className={styles.mediaImage} />
</div>
))}
</Slider>
<div className={styles.customArrowLeft} onClick={this.handlePrev}>
<Icon type="left" style={{ fontSize: '24px', color: 'rgba(0, 0, 0, 0.5)' }} />
</div>
<div className={styles.customArrowRight} onClick={this.handleNext}>
<Icon type="right" style={{ fontSize: '24px', color: 'rgba(0, 0, 0, 0.5)' }} />
</div>
<div className={styles.customDots}>
{trainingData.listVideoImg?.map((_, index) => (
<span
key={index}
className={`${styles.dot} ${currentMediaIndex === index ? styles.activeDot : ''}`}
onClick={() => this.handleDotClick(index)}
/>
))}
</div>
</div>
)
) : (
<div></div>
)}
</div>
</div>
<div className={styles.announcementCard}>
<div className={styles.announcementHeader}>
<div className={styles.announcementTitle}>
<Icon type="sound" className={styles.announcementIcon} />
<span>公司公告</span>
</div>
<span className={styles.announcementCount}> {trainingData.listAnnourcement?.length || 0} 条公告</span>
</div>
<div className={styles.announcementList}>
{trainingData.listAnnourcement?.length > 0 ? (
<ul className={styles.announcementUl}>
{trainingData.listAnnourcement.map((item, index) => (
<li
key={item.id || index}
className={styles.announcementItem}
onClick={() => onAnnouncementClick && onAnnouncementClick(item)}
>
<span className={styles.announcementItemTitle} title={item.TITLE}>
{item.TITLE}
</span>
<span className={styles.announcementItemTime}>{item.START}</span>
</li>
))}
</ul>
) : (
<div className={styles.emptyAnnouncement}>
<Icon type="inbox" className={styles.emptyIcon} />
<span>暂无公告</span>
</div>
)}
</div>
</div>
</Col>
{/* 右侧区域 */}
<Col span={7} className={styles.rightCol}>
<div className={styles.dangerCard}>
{/* <div id="dangerOperationChart" className={styles.fullChartContainer}></div> */}
<div className={styles.infoContainer}>
<div className={styles.infoTitle}>集团企业信息汇总</div>
<div className={styles.infoCard}>
<div className={styles.infoCardMark}>集团公司</div>
<div className={styles.infoCardTitle}>吐鲁番金源矿冶有限责任公司</div>
<div className={styles.infoCardDetail}>子公司数量{trainingData?.SumSubCount || '-'}</div>
</div>
<div className={styles.infoBanner}>
{trainingData.listSubTypeCount && Object.keys(trainingData.listSubTypeCount).length > 0 ? (
<>
<div className={styles.bannerScrollContainer} ref={this.bannerScrollRef}>
<div className={styles.bannerScrollContent}>
{Object.entries(trainingData.listSubTypeCount).map(([key, value], index) => (
<div key={index} className={styles.infoSpan}>
<span>{key}</span>
<span>{value}</span>
</div>
))}
</div>
</div>
</>
) : (
// 默认显示当没有数据时保持原有3个的样子
<div
className={styles.bannerScrollContent}
style={{ width: '100%', justifyContent: 'space-around' }}
>
<div className={styles.infoSpan}>
<span>露天矿</span>
<span>--</span>
</div>
<div className={styles.infoSpan}>
<span>地下矿</span>
<span>--</span>
</div>
<div className={styles.infoSpan}>
<span>尾矿库</span>
<span>--</span>
</div>
</div>
)}
</div>
<div className={styles.infoBottom}>
<div className={styles.infoBottomContent}>
<div className={styles.infoBottomImg}>
<img src={require('../../assets/layout/scgm.png')}></img>
</div>
<div className={styles.infoBottomContentRight}>
<div className={styles.infoBottomTitle}>生产规模</div>
<div className={styles.infoBottomNum}>
<span>{trainingData?.SumSubMode || '-'}</span>/
</div>
</div>
</div>
<div className={styles.infoBottomContent}>
<div className={styles.infoBottomImg}>
<img src={require('../../assets/layout/kqmj.png')}></img>
</div>
<div className={styles.infoBottomContentRight}>
<div className={styles.infoBottomTitle}>矿区面积</div>
<div className={styles.infoBottomNum}>
<span>{trainingData?.SumSubArea || '-'}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div className={styles.spacer}></div>
<div className={styles.riskCard}>
<Row className={styles.riskRow}>
<Col span={8} className={styles.trainingStatsCol}>
<div className={styles.trainingTitle}>年度培训数据</div>
{trainingData?.listNAME?.map((name, index) => (
<div key={index} className={styles.trainingStatItem}>
<div className={styles.trainingStatName}>{name}</div>
<div className={styles.trainingStatValue}>{trainingData?.YearCount?.[index] || 0}</div>
</div>
))}
{(!trainingData?.listNAME || trainingData.listNAME.length === 0) && (
<div style={{ textAlign: 'center', color: '#999', padding: '20px 0' }}>暂无培训数据</div>
)}
</Col>
<Col span={16} className={styles.chartCol}>
<div id="backLogChart" className={styles.chartContainer}></div>
</Col>
</Row>
</div>
</Col>
</Row>
{/* 公告详情弹窗 */}
<Modal
title="公告详情"
visible={announcementModalVisible}
onCancel={onAnnouncementModalClose}
footer={[
<Button key="close" onClick={onAnnouncementModalClose}>
关闭
</Button>,
]}
width="80%"
bodyStyle={{ padding: '20px', maxHeight: '70vh', overflowY: 'auto' }}
>
{this.renderAnnouncementModal()}
</Modal>
</div>
);
}
}
export default HomeContent;