diff --git a/src/layout/FullOther/HomeContent.js b/src/layout/FullOther/HomeContent.js index acfb817..15bff2e 100644 --- a/src/layout/FullOther/HomeContent.js +++ b/src/layout/FullOther/HomeContent.js @@ -290,7 +290,7 @@ class HomeContent extends React.Component { type: 'bar', data: seriesData, itemStyle: { - normal: { color: '#4285F4', borderRadius: 12 }, + 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}' }, @@ -323,60 +323,141 @@ class HomeContent extends React.Component { let backLogCharts = document.getElementById('backLogChart'); if (!backLogCharts) return; - const taskData = this.props.taskTop3 || []; - if (taskData.length === 0) return; + // 使用培训数据 + const { trainingData } = this.props; + const listNAME = trainingData?.listNAME || []; + const monthRecordCount = trainingData?.MonthRecordCount || []; // 培训场次 + const monthPersonCount = trainingData?.MonthPersonCount || []; // 培训人次 - const barTopColor = [ - ['#75baf3', '#2177d5'], - ['#ffa94d', '#f76707'], - ['#99ca6e', '#48a447'], - ]; + if (listNAME.length === 0) { + this.echartsInstances.backLogChart = echarts.init(backLogCharts); + this.echartsInstances.backLogChart.setOption({ + title: { + text: '当月工作培训统计数量', + x: 'center', + y: 'center', + 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); - let xdata = this.transformDat(taskData, barTopColor, 2); - const legendColors = barTopColor.map((gradient) => gradient[0]); - this.echartsInstances.backLogChart.setOption({ + const option = { title: { - text: '各事项排名前三名统计', + text: '当月工作培训统计数量', x: 'center', y: '5%', textStyle: { fontSize: 16, color: '#000' }, }, - tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } }, + 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: xdata.legendData.map((name, index) => ({ - name: name, - itemStyle: { color: legendColors[index], borderWidth: 0 }, - textStyle: { color: '#000', fontSize: 14 }, - })), - align: 'right', - top: 10, - right: 10, - itemGap: 16, + data: ['培训人次', '培训场次'], + orient: 'vertical', // 垂直排列 + right: 0, // 水平居中 + top: 'middle', // 垂直居中 + itemGap: 16, // 图例项间隔 itemWidth: 18, itemHeight: 12, + textStyle: { color: '#000', fontSize: 14 }, + }, + grid: { + left: '5%', + right: '5%', // 为右侧垂直图例留出空间 + top: '18%', + bottom: '5%', + containLabel: true, }, - color: legendColors, - grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, xAxis: [ { type: 'category', - data: xdata.companyNames, - axisLine: { lineStyle: { color: '#3eb2e8' } }, - axisLabel: { textStyle: { color: '#000' } }, + data: listNAME, + axisLine: { show: false }, // 隐藏x轴线 + axisTick: { show: false }, // 隐藏x轴刻度线 + axisLabel: { + textStyle: { color: '#000' }, + rotate: listNAME.length > 4 ? 15 : 0, + interval: 0, + }, }, ], yAxis: [ { type: 'value', - axisLine: { show: false }, - axisLabel: { textStyle: { color: '#000' } }, - splitLine: { lineStyle: { color: '#4784e8' } }, + show: true, // 显示y轴 + axisLine: { show: false }, // 隐藏y轴线 + axisTick: { show: false }, // 隐藏y轴刻度线 + axisLabel: { + show: true, // 显示数值标签 + textStyle: { color: '#000' }, + }, + splitLine: { show: false }, // 隐藏横向网格线 + name: '', // 不显示单位名称 + nameTextStyle: { show: false }, // 隐藏单位文字 }, ], - series: xdata.series, - }); + 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) { @@ -451,7 +532,8 @@ class HomeContent extends React.Component { prevProps.riskTypeRate !== this.props.riskTypeRate || prevProps.jobTodayTop3 !== this.props.jobTodayTop3 || prevProps.linkSum !== this.props.linkSum || - prevProps.taskTop3 !== this.props.taskTop3 + prevProps.taskTop3 !== this.props.taskTop3 || + prevProps.trainingData !== this.props.trainingData // 新增 ) { this.disposeAllCharts(); this.initAllCharts(); @@ -602,12 +684,16 @@ class HomeContent extends React.Component {
年度培训数据
- {riskTotal.map((item, index) => ( + {this.props.trainingData?.listNAME?.map((name, index) => (
-
{item.name}
-
{item.value}
+
{name}
+
{this.props.trainingData?.YearCount?.[index] || 0}
))} + {/* 如果 listNAME 为空,显示默认提示 */} + {(!this.props.trainingData?.listNAME || this.props.trainingData.listNAME.length === 0) && ( +
暂无培训数据
+ )}
diff --git a/src/layout/FullOther/TrainingContent.js b/src/layout/FullOther/TrainingContent.js new file mode 100644 index 0000000..ee7dfb1 --- /dev/null +++ b/src/layout/FullOther/TrainingContent.js @@ -0,0 +1,623 @@ +// TrainingContent.js - 安全培训页面组件 +import React from 'react'; +import { Row, Col, Select } from 'antd'; +import styles from './../fullinter.less'; +import echarts from 'echarts'; +const { Option } = Select; + +class TrainingContent extends React.Component { + constructor(props) { + super(props); + this.echartsInstances = { + chart1: null, // 各部门培训统计(柱状图) + chart2: null, // 各部门培训完成率 + chart3: null, // 培训类型分布 + chart4: null, // 月度培训对比 + }; + this.chartResizeHandlers = {}; + this.isUnmounted = 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); + }); + }; + + // 图表1: 各部门培训统计(柱状图)- 使用 trainingSubData 数据 + renderChart1 = async () => { + if (this.isUnmounted) return; + const elementExists = await this.waitForElement('trainingChart1'); + if (!elementExists || this.isUnmounted) return; + + if (this.echartsInstances.chart1) { + this.echartsInstances.chart1.dispose(); + this.echartsInstances.chart1 = null; + } + + const chartDom = document.getElementById('trainingChart1'); + if (!chartDom) return; + + this.echartsInstances.chart1 = echarts.init(chartDom); + + // 使用 props 传入的 trainingSubData 数据(来自 getHomeSESubYear 接口) + const { trainingSubData } = this.props; + const companyNames = trainingSubData?.listNAME || []; // CName 数组 + const personCounts = trainingSubData?.MonthPersonCount || []; // PCount 数组(培训人次) + const recordCounts = trainingSubData?.MonthRecordCount || []; // RCount 数组(培训场次) + + // 如果没有数据,显示暂无数据提示 + if (companyNames.length === 0) { + this.echartsInstances.chart1.setOption({ + title: { + text: '本年度各公司培训分析', + x: 'center', + y: 'center', + textStyle: { fontSize: 16, color: '#999' }, + }, + graphic: { + type: 'text', + left: 'center', + top: 'middle', + style: { + text: '暂无培训数据', + fill: '#999', + fontSize: 14, + }, + }, + }); + return; + } + + 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) => { + const unit = param.seriesName === '培训人次' ? '人次' : '场次'; + result += `${param.marker}${param.seriesName}: ${param.value}${unit}
`; + }); + return result; + }, + }, + legend: { + data: ['培训人次', '培训场次'], + right: '3%', // 靠右 + top: '5%', // 垂直居中 + itemGap: 16, + itemWidth: 18, + itemHeight: 12, + textStyle: { color: '#000', fontSize: 14 }, + }, + grid: { + left: '5%', + 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, + }, + }, + ], + 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: personCounts, + itemStyle: { + normal: { + color: '#4285F4', // 蓝色 + }, + }, + label: { + show: true, + position: 'top', + textStyle: { color: '#4285F4', fontSize: 12 }, + formatter: (params) => `${params.value}`, + }, + barWidth: '35%', + }, + { + name: '培训场次', + type: 'bar', + data: recordCounts, + itemStyle: { + normal: { + color: '#ffe066', // 黄色 + }, + }, + label: { + show: true, + position: 'top', + textStyle: { color: '#d4a000', fontSize: 12 }, + formatter: (params) => `${params.value}`, + }, + barWidth: '35%', + }, + ], + }; + + this.echartsInstances.chart1.setOption(option); + this.setupResizeHandler('chart1', this.renderChart1); + }; + // 生成月份选项(1-12月) + getMonthOptions = () => { + const months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']; + return months.map((month, index) => ( + + )); + }; + + // 图表2: 各部门培训完成率(横向柱状图) + renderChart2 = async () => { + if (this.isUnmounted) return; + const elementExists = await this.waitForElement('trainingChart2'); + if (!elementExists || this.isUnmounted) return; + + if (this.echartsInstances.chart2) { + this.echartsInstances.chart2.dispose(); + this.echartsInstances.chart2 = null; + } + + const chartDom = document.getElementById('trainingChart2'); + if (!chartDom) return; + + this.echartsInstances.chart2 = echarts.init(chartDom); + + // 使用 props 传入的 trainingSubData 数据(来自 getHomeSESubYear 接口) + const { trainingSubDataMonth } = this.props; + const companyNames = trainingSubDataMonth?.listNAME || []; // CName 数组 + const personCounts = trainingSubDataMonth?.MonthPersonCount || []; // PCount 数组(培训人次) + const recordCounts = trainingSubDataMonth?.MonthRecordCount || []; // RCount 数组(培训场次) + + // 如果没有数据,显示暂无数据提示 + if (companyNames.length === 0) { + this.echartsInstances.chart2.setOption({ + title: { + text: '本年度各公司培训分析', + x: 'center', + y: 'center', + textStyle: { fontSize: 16, color: '#999' }, + }, + graphic: { + type: 'text', + left: 'center', + top: 'middle', + style: { + text: '暂无培训数据', + fill: '#999', + fontSize: 14, + }, + }, + }); + return; + } + + 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) => { + const unit = param.seriesName === '培训人次' ? '人次' : '场次'; + result += `${param.marker}${param.seriesName}: ${param.value}${unit}
`; + }); + return result; + }, + }, + legend: { + data: ['培训人次', '培训场次'], + right: '3%', // 靠右 + top: '5%', // 垂直居中 + itemGap: 16, + itemWidth: 18, + itemHeight: 12, + textStyle: { color: '#000', fontSize: 14 }, + }, + grid: { + left: '5%', + 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, + }, + }, + ], + 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: personCounts, + itemStyle: { + normal: { + color: '#4285F4', // 蓝色 + }, + }, + label: { + show: true, + position: 'top', + textStyle: { color: '#4285F4', fontSize: 12 }, + formatter: (params) => `${params.value}`, + }, + barWidth: '35%', + }, + { + name: '培训场次', + type: 'bar', + data: recordCounts, + itemStyle: { + normal: { + color: '#ffe066', // 黄色 + }, + }, + label: { + show: true, + position: 'top', + textStyle: { color: '#d4a000', fontSize: 12 }, + formatter: (params) => `${params.value}`, + }, + barWidth: '35%', + }, + ], + }; + + this.echartsInstances.chart2.setOption(option); + this.setupResizeHandler('chart2', this.renderChart2); + }; + + // 图表3: 培训类型分布(饼图) + renderChart3 = async () => { + if (this.isUnmounted) return; + const elementExists = await this.waitForElement('trainingChart3'); + if (!elementExists || this.isUnmounted) return; + + if (this.echartsInstances.chart3) { + this.echartsInstances.chart3.dispose(); + this.echartsInstances.chart3 = null; + } + + const chartDom = document.getElementById('trainingChart3'); + if (!chartDom) return; + + this.echartsInstances.chart3 = echarts.init(chartDom); + + // 培训类型分布数据 + const trainingTypes = [ + { name: '安全法规培训', value: 35 }, + { name: '操作规程培训', value: 28 }, + { name: '应急演练培训', value: 20 }, + { name: '职业健康培训', value: 12 }, + { name: '其他培训', value: 5 }, + ]; + + const option = { + title: { + text: '培训类型分布', + x: 'center', + y: '5%', + textStyle: { fontSize: 16, color: '#000', fontWeight: 'bold' }, + }, + tooltip: { + trigger: 'item', + formatter: function (params) { + return `${params.name}: ${params.value}场 (${params.percent}%)`; + }, + }, + legend: { + orient: 'vertical', + right: '5%', + top: 'middle', + itemGap: 12, + itemWidth: 14, + itemHeight: 10, + textStyle: { color: '#333', fontSize: 11 }, + formatter: function (name) { + const item = trainingTypes.find((t) => t.name === name); + return `${name} ${item?.value || 0}场`; + }, + }, + color: ['#4285F4', '#66bb6a', '#ffa94d', '#ab47bc', '#ef5350'], + series: [ + { + name: '培训场次', + type: 'pie', + radius: ['45%', '70%'], + center: ['40%', '55%'], + avoidLabelOverlap: false, + label: { + show: true, + position: 'outside', + formatter: '{b}: {d}%', + textStyle: { fontSize: 11, color: '#333' }, + }, + emphasis: { + label: { show: true, fontSize: 14, fontWeight: 'bold' }, + }, + labelLine: { length: 8, length2: 8, smooth: true }, + data: trainingTypes, + }, + ], + }; + + this.echartsInstances.chart3.setOption(option); + this.setupResizeHandler('chart3', this.renderChart3); + }; + + // 图表4: 月度培训对比(分组柱状图) + renderChart4 = async () => { + if (this.isUnmounted) return; + const elementExists = await this.waitForElement('trainingChart4'); + if (!elementExists || this.isUnmounted) return; + + if (this.echartsInstances.chart4) { + this.echartsInstances.chart4.dispose(); + this.echartsInstances.chart4 = null; + } + + const chartDom = document.getElementById('trainingChart4'); + if (!chartDom) return; + + this.echartsInstances.chart4 = echarts.init(chartDom); + + // 近6个月各部门培训场次对比 + const months = ['1月', '2月', '3月', '4月', '5月', '6月']; + const departments = ['安全部', '生产部', '技术部']; + + const seriesData = [ + { name: '安全部', data: [5, 6, 7, 8, 7, 9], color: '#4285F4' }, + { name: '生产部', data: [8, 9, 10, 11, 12, 13], color: '#66bb6a' }, + { name: '技术部', data: [4, 5, 6, 6, 7, 8], color: '#ffa94d' }, + ]; + + 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: seriesData.map((s) => s.name), + orient: 'horizontal', + left: 'center', + top: '15%', + itemGap: 20, + itemWidth: 18, + itemHeight: 12, + textStyle: { color: '#333', fontSize: 12 }, + }, + grid: { + left: '8%', + right: '5%', + top: '25%', + bottom: '8%', + containLabel: true, + }, + xAxis: { + type: 'category', + data: months, + axisLine: { lineStyle: { color: '#666' } }, + axisLabel: { textStyle: { color: '#333' } }, + }, + yAxis: { + type: 'value', + name: '培训场次', + axisLabel: { textStyle: { color: '#666' } }, + splitLine: { lineStyle: { color: '#e0e0e0' } }, + }, + series: seriesData.map((s) => ({ + name: s.name, + type: 'bar', + data: s.data, + itemStyle: { + normal: { + color: s.color, + barBorderRadius: [4, 4, 0, 0], + }, + }, + label: { + show: true, + position: 'top', + textStyle: { fontSize: 10 }, + formatter: '{c}', + }, + barWidth: '25%', + })), + }; + + this.echartsInstances.chart4.setOption(option); + this.setupResizeHandler('chart4', this.renderChart4); + }; + + 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.renderChart1(); + this.renderChart2(); + this.renderChart3(); + this.renderChart4(); + }, 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) { + // 当 trainingSubData 或 trainingSubDataMonth 变化时重新渲染图表 + if ( + prevProps.trainingSubData !== this.props.trainingSubData || + prevProps.trainingSubDataMonth !== this.props.trainingSubDataMonth || + prevProps.selectedMonth !== this.props.selectedMonth + ) { + // this.renderChart1(); + this.renderChart2(); + } + } + + componentWillUnmount() { + this.isUnmounted = true; + this.disposeAllCharts(); + } + + render() { + const { selectedMonth = 1, onMonthChange } = this.props; + return ( +
+
+ {/* 第一行 - 图表1和图表2 */} +
+
+
+
+
+ {/* 添加月份选择器 */} +
+ 选择月份: + +
+
+
+
+ {/* 第二行 - 图表3和图表4 */} +
+
+
+
+
+
+
+
+
+
+ ); + } +} + +export default TrainingContent; diff --git a/src/layout/FullScreenInter.js b/src/layout/FullScreenInter.js index 60d6efa..123da73 100644 --- a/src/layout/FullScreenInter.js +++ b/src/layout/FullScreenInter.js @@ -9,6 +9,7 @@ import debounce from 'lodash.debounce'; import storage from '../utils/storage'; import { initFilter } from '../utils/common'; import HomeContent from './FullOther/HomeContent'; +import TrainingContent from './FullOther/TrainingContent'; // 新增导入 const getScale = () => { const width = 1920, @@ -38,6 +39,28 @@ class FullScreen extends React.Component { currentMediaIndex: 0, announcementList: [], activeTab: '首页', + // 新增:培训数据 + trainingData: { + listNAME: [], + YearCount: [], + MonthRecordCount: [], + MonthPersonCount: [], + }, + // 新增:安全培训页面专用数据 + trainingSubData: { + listNAME: [], + YearCount: [], + MonthRecordCount: [], + MonthPersonCount: [], + }, + trainingSubDataMonth: { + listNAME: [], + YearCount: [], + MonthRecordCount: [], + MonthPersonCount: [], + }, + // 新增:当前选择的月份 + selectedMonth: new Date().getMonth() + 1, // 默认当前月份,1-12 }; this.isUnmounted = false; } @@ -58,7 +81,8 @@ class FullScreen extends React.Component { componentDidMount() { this.isUnmounted = false; window.addEventListener('resize', this.setScale); - this.getHomeDataArray(); + // this.getHomeDataArray(); + this.getYearPXData(); this.loadMediaFiles(); this.getAnnouncementData(); @@ -100,6 +124,11 @@ class FullScreen extends React.Component { handleTabClick = (name) => { this.setState({ activeTab: name }); + // 当点击安全培训tab时,获取对应数据 + if (name === '安全培训') { + this.getHomeSESubYearData(); + this.getHomeSESubYearMonthData(); + } }; handleFullscreenChange = () => { @@ -146,9 +175,112 @@ class FullScreen extends React.Component { }, }); }; + getYearPXData = () => { + const orgId = storage('lacal').getItem('webOrgId')?.val; + const json = initFilter(orgId); + this.props.dispatch({ + type: 'app/getDataByPost', + payload: json, + url: 'BI/BIHeadSE/SEtrInfo', + onComplete: (ret) => { + if (ret && !this.isUnmounted) { + this.setState({ + trainingData: { + listNAME: ret.listNAME || [], + YearCount: ret.YearCount || [], + MonthRecordCount: ret.MonthRecordCount || [], + MonthPersonCount: ret.MonthPersonCount || [], + }, + }); + } + }, + }); + }; + // 获取安全培训页面数据 + getHomeSESubYearData = () => { + const orgId = storage('lacal').getItem('webOrgId')?.val; + const json = initFilter(orgId); + const currentYear = new Date().getFullYear(); // 获取当前年份 + json.Parameter1 = currentYear.toString(); // 设置为当前年份 + this.props.dispatch({ + type: 'app/getDataByPost', + payload: json, + url: 'BI/BIHeadSE/HomeSESubYear', + onComplete: (ret) => { + if (ret && !this.isUnmounted) { + // ret 是数组格式: [{ CName: "邦泰", PCount: 0, RCount: 13 }, ...] + const listNAME = ret.map((item) => item.CName); + const MonthPersonCount = ret.map((item) => item.PCount); // 培训人次 + const MonthRecordCount = ret.map((item) => item.RCount); // 培训场次 + // YearCount 暂时用 PCount 的总和或保持为空数组 + const YearCount = ret.map((item) => item.PCount); + + this.setState({ + trainingSubData: { + listNAME: listNAME, + YearCount: YearCount, + MonthRecordCount: MonthRecordCount, + MonthPersonCount: MonthPersonCount, + }, + }); + } + }, + }); + }; + // 新增:处理月份变化 + handleMonthChange = (month) => { + this.setState({ selectedMonth: month }, () => { + // 重新获取月份数据 + this.getHomeSESubYearMonthData(); + }); + }; + // 获取安全培训页面数据 + getHomeSESubYearMonthData = () => { + const orgId = storage('lacal').getItem('webOrgId')?.val; + const json = initFilter(orgId); + const currentYear = new Date().getFullYear(); // 获取当前年份 + json.Parameter1 = currentYear.toString(); // 设置为当前年份 + json.Parameter2 = this.state.selectedMonth.toString(); // 月份 + this.props.dispatch({ + type: 'app/getDataByPost', + payload: json, + url: 'BI/BIHeadSE/HomeSESubYear', + onComplete: (ret) => { + if (ret && !this.isUnmounted) { + // ret 是数组格式: [{ CName: "邦泰", PCount: 0, RCount: 13 }, ...] + const listNAME = ret.map((item) => item.CName); + const MonthPersonCount = ret.map((item) => item.PCount); // 培训人次 + const MonthRecordCount = ret.map((item) => item.RCount); // 培训场次 + // YearCount 暂时用 PCount 的总和或保持为空数组 + const YearCount = ret.map((item) => item.PCount); + + this.setState({ + trainingSubDataMonth: { + listNAME: listNAME, + YearCount: YearCount, + MonthRecordCount: MonthRecordCount, + MonthPersonCount: MonthPersonCount, + }, + }); + } + }, + }); + }; renderOtherTabContent = () => { - const { activeTab } = this.state; + const { activeTab, trainingData, trainingSubData, trainingSubDataMonth, selectedMonth } = this.state; + // 如果是安全培训,显示专门的培训页面 + if (activeTab === '安全培训') { + return ( + + ); + } return (
@@ -174,6 +306,7 @@ class FullScreen extends React.Component { mediaList, announcementList, currentMediaIndex, + trainingData, } = this.state; return ( @@ -237,6 +370,7 @@ class FullScreen extends React.Component { currentMediaIndex={currentMediaIndex} onCarouselChange={this.handleCarouselChange} onDotClick={this.handleDotClick} + trainingData={trainingData} // 新增传递 /> ) : ( this.renderOtherTabContent() diff --git a/src/layout/fullinter.less b/src/layout/fullinter.less index 0e7a020..7905938 100644 --- a/src/layout/fullinter.less +++ b/src/layout/fullinter.less @@ -590,3 +590,86 @@ height: 100%; } } +// fullinter.less - 在文件末尾添加以下样式 + +// ========== TrainingContent 组件样式 ========== +.trainingContentWrapper { + flex: 1; + width: 100%; + height: 100%; + overflow: hidden; + padding: 0 10px 10px 10px; + box-sizing: border-box; +} + +.trainingGrid { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + gap: 10px; +} + +.trainingRow { + flex: 1; + display: flex; + gap: 10px; + min-height: 0; +} + +.trainingCard { + flex: 1; + min-width: 0; // 防止内容溢出 + background-color: #fff; + border-radius: 8px; + overflow: hidden; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + transition: box-shadow 0.3s ease; + min-height: 0; + display: flex; + flex-direction: column; + + position: relative; + overflow: hidden; + + &:hover { + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12); + } +} + +.trainingChartContainer { + width: 100%; + height: 100%; + min-height: 0; +} +// 月份选择器样式 +.monthSelectorWrapper { + position: absolute; + top: 15px; + left: 20px; + z-index: 10; + display: flex; + align-items: center; + background: rgba(255, 255, 255, 0.9); + padding: 4px 12px; + border-radius: 20px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +.monthSelectorLabel { + font-size: 13px; + color: #333; + margin-right: 8px; + font-weight: 500; +} + +.monthSelect { + .ant-select-selector { + border-radius: 16px !important; + border-color: #4285f4 !important; + + &:hover { + border-color: #66bb6a !important; + } + } +}