mh_jy_safe_web/src/layout/FullOther/HomeContent.js
2026-05-11 09:27:49 +08:00

989 lines
32 KiB
JavaScript

// 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%',
},
],
};
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.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>
<div className={styles.spacer}></div>
<div className={styles.dangerCard}>
<div id="dangerOperationChart" className={styles.fullChartContainer}></div>
</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;