diff --git a/package-lock.json b/package-lock.json
index 598a7b5..c68223d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -51,6 +51,7 @@
"react-loadable": "5.5.0",
"react-orgchart": "^1.0.5",
"react-resizable": "^1.10.1",
+ "react-slick": "^0.31.0",
"react-to-print": "^2.0.0-alpha-2",
"react-umeditor": "1.0.12",
"react-websocket": "2.0.1",
@@ -2637,6 +2638,22 @@
"resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-2.1.1.tgz",
"integrity": "sha512-jCH+k2Vjlno4YWl6g535nHR09PwCEmTBKAG6VqF+rhkrSPRLfgpU2maagwbZPLjaHuU5Jd1DFQ2KJpQuI6uG8w=="
},
+ "node_modules/antd/node_modules/react-slick": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmmirror.com/react-slick/-/react-slick-0.25.2.tgz",
+ "integrity": "sha512-8MNH/NFX/R7zF6W/w+FS5VXNyDusF+XDW1OU0SzODEU7wqYB+ZTGAiNJ++zVNAVqCAHdyCybScaUB+FCZOmBBw==",
+ "dependencies": {
+ "classnames": "^2.2.5",
+ "enquire.js": "^2.1.6",
+ "json2mq": "^0.2.0",
+ "lodash.debounce": "^4.0.8",
+ "resize-observer-polyfill": "^1.5.0"
+ },
+ "peerDependencies": {
+ "react": "^0.14.0 || ^15.0.1 || ^16.0.0",
+ "react-dom": "^0.14.0 || ^15.0.1 || ^16.0.0"
+ }
+ },
"node_modules/any-promise": {
"version": "1.3.0",
"resolved": "https://registry.npmmirror.com/any-promise/-/any-promise-1.3.0.tgz",
@@ -21055,19 +21072,18 @@
"license": "BSD-3-Clause"
},
"node_modules/react-slick": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/react-slick/-/react-slick-0.25.2.tgz",
- "integrity": "sha512-8MNH/NFX/R7zF6W/w+FS5VXNyDusF+XDW1OU0SzODEU7wqYB+ZTGAiNJ++zVNAVqCAHdyCybScaUB+FCZOmBBw==",
+ "version": "0.31.0",
+ "resolved": "https://registry.npmmirror.com/react-slick/-/react-slick-0.31.0.tgz",
+ "integrity": "sha512-zo6VLT8wuSBJffg/TFPbzrw2dEnfZ/cUKmYsKByh3AgatRv29m2LoFbq5vRMa3R3A4wp4d8gwbJKO2fWZFaI3g==",
"dependencies": {
"classnames": "^2.2.5",
- "enquire.js": "^2.1.6",
"json2mq": "^0.2.0",
"lodash.debounce": "^4.0.8",
"resize-observer-polyfill": "^1.5.0"
},
"peerDependencies": {
- "react": "^0.14.0 || ^15.0.1 || ^16.0.0",
- "react-dom": "^0.14.0 || ^15.0.1 || ^16.0.0"
+ "react": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/react-test-renderer": {
@@ -22508,7 +22524,6 @@
"version": "1.8.1",
"resolved": "https://registry.npmmirror.com/slick-carousel/-/slick-carousel-1.8.1.tgz",
"integrity": "sha512-XB9Ftrf2EEKfzoQXt3Nitrt/IPbT+f1fgqBdoxO3W/+JYvtEOW6EgxnWfr9GH6nmULv7Y2tPmEX3koxThVmebA==",
- "license": "MIT",
"peerDependencies": {
"jquery": ">=1.8.0"
}
@@ -28673,6 +28688,18 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-2.1.1.tgz",
"integrity": "sha512-jCH+k2Vjlno4YWl6g535nHR09PwCEmTBKAG6VqF+rhkrSPRLfgpU2maagwbZPLjaHuU5Jd1DFQ2KJpQuI6uG8w=="
+ },
+ "react-slick": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmmirror.com/react-slick/-/react-slick-0.25.2.tgz",
+ "integrity": "sha512-8MNH/NFX/R7zF6W/w+FS5VXNyDusF+XDW1OU0SzODEU7wqYB+ZTGAiNJ++zVNAVqCAHdyCybScaUB+FCZOmBBw==",
+ "requires": {
+ "classnames": "^2.2.5",
+ "enquire.js": "^2.1.6",
+ "json2mq": "^0.2.0",
+ "lodash.debounce": "^4.0.8",
+ "resize-observer-polyfill": "^1.5.0"
+ }
}
}
},
@@ -42912,12 +42939,11 @@
}
},
"react-slick": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/react-slick/-/react-slick-0.25.2.tgz",
- "integrity": "sha512-8MNH/NFX/R7zF6W/w+FS5VXNyDusF+XDW1OU0SzODEU7wqYB+ZTGAiNJ++zVNAVqCAHdyCybScaUB+FCZOmBBw==",
+ "version": "0.31.0",
+ "resolved": "https://registry.npmmirror.com/react-slick/-/react-slick-0.31.0.tgz",
+ "integrity": "sha512-zo6VLT8wuSBJffg/TFPbzrw2dEnfZ/cUKmYsKByh3AgatRv29m2LoFbq5vRMa3R3A4wp4d8gwbJKO2fWZFaI3g==",
"requires": {
"classnames": "^2.2.5",
- "enquire.js": "^2.1.6",
"json2mq": "^0.2.0",
"lodash.debounce": "^4.0.8",
"resize-observer-polyfill": "^1.5.0"
diff --git a/package.json b/package.json
index 00e0845..757a26f 100644
--- a/package.json
+++ b/package.json
@@ -52,6 +52,7 @@
"react-loadable": "5.5.0",
"react-orgchart": "^1.0.5",
"react-resizable": "^1.10.1",
+ "react-slick": "^0.31.0",
"react-to-print": "^2.0.0-alpha-2",
"react-umeditor": "1.0.12",
"react-websocket": "2.0.1",
diff --git a/src/layout/FullOther/ClassBuild.js b/src/layout/FullOther/ClassBuild.js
new file mode 100644
index 0000000..293ffd6
--- /dev/null
+++ b/src/layout/FullOther/ClassBuild.js
@@ -0,0 +1,228 @@
+// ClassBuild.js - 班组建设页面组件
+import React from 'react';
+import { Table } from 'antd';
+import styles from './../fullinter.less';
+import echarts from 'echarts';
+
+class ClassBuild extends React.Component {
+ constructor(props) {
+ super(props);
+ this.echartsInstances = {
+ typeBarChart: 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);
+ });
+ };
+
+ // 班组风险类别柱状图
+ renderTypeBarChart = async () => {
+ if (this.isUnmounted) return;
+ const elementExists = await this.waitForElement('typeBarChart');
+ if (!elementExists || this.isUnmounted) return;
+
+ if (this.echartsInstances.typeBarChart) {
+ this.echartsInstances.typeBarChart.dispose();
+ this.echartsInstances.typeBarChart = null;
+ }
+
+ const chartDom = document.getElementById('typeBarChart');
+ if (!chartDom) return;
+
+ this.echartsInstances.typeBarChart = echarts.init(chartDom);
+
+ const { classSubData } = this.props;
+ const companyList = classSubData || [];
+
+ if (companyList.length === 0) {
+ this.echartsInstances.typeBarChart.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;
+ }
+
+ // 注意:数据结构是 { companyName: '邦泰', rate: '52%' }
+ const companyNames = companyList.map((item) => item.companyName);
+ const rates = companyList.map((item) => {
+ // 处理 rate 可能是字符串带百分号的情况
+ const rateValue = typeof item.rate === 'string' ? parseFloat(item.rate.replace('%', '')) : item.rate;
+ return isNaN(rateValue) ? 0 : rateValue;
+ });
+
+ 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;
+ },
+ },
+ grid: {
+ left: '8%',
+ right: '5%',
+ top: '18%',
+ bottom: '8%',
+ containLabel: true,
+ },
+ xAxis: [
+ {
+ type: 'category',
+ data: companyNames,
+ axisLine: { show: false },
+ axisTick: { show: false },
+ axisLabel: {
+ textStyle: { color: '#000' },
+ interval: 0,
+ fontSize: 12,
+ },
+ },
+ ],
+ yAxis: [
+ {
+ type: 'value',
+ show: true,
+ axisLine: { show: false },
+ axisTick: { show: false },
+ axisLabel: {
+ show: true,
+ textStyle: { color: '#000' },
+ formatter: '{value}%',
+ },
+ splitLine: { show: true, lineStyle: { color: '#e0e0e0', type: 'dashed' } },
+ },
+ ],
+ series: [
+ {
+ name: '班组建设完成率',
+ type: 'bar',
+ data: rates,
+ itemStyle: {
+ normal: {
+ color: '#4285F4',
+ borderRadius: [4, 4, 0, 0],
+ },
+ },
+ label: {
+ show: true,
+ position: 'top',
+ textStyle: { color: '#4285F4', fontSize: 12 },
+ formatter: (params) => `${params.value}%`,
+ },
+ barWidth: '50%',
+ },
+ ],
+ };
+
+ this.echartsInstances.typeBarChart.setOption(option);
+ this.setupResizeHandler('typeBarChart', this.renderTypeBarChart);
+ };
+
+ 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.renderTypeBarChart();
+ }, 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();
+ }
+
+ // 修复:监听 classSubData 而不是 riskSubData
+ componentDidUpdate(prevProps) {
+ if (prevProps.classSubData !== this.props.classSubData) {
+ this.renderTypeBarChart();
+ }
+ }
+
+ componentWillUnmount() {
+ this.isUnmounted = true;
+ this.disposeAllCharts();
+ }
+
+ render() {
+ return (
+
+ );
+ }
+}
+
+export default ClassBuild;
diff --git a/src/layout/FullOther/DangerJob.js b/src/layout/FullOther/DangerJob.js
new file mode 100644
index 0000000..e38e3c7
--- /dev/null
+++ b/src/layout/FullOther/DangerJob.js
@@ -0,0 +1,312 @@
+// DangerJob.js - 危险作业页面组件
+import React from 'react';
+import { Table, Select, Pagination } from 'antd';
+import styles from './../fullinter.less';
+
+const { Option } = Select;
+
+class DangerJob extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ currentPage: 1,
+ pageSize: 10,
+ };
+ this.isUnmounted = false;
+ }
+
+ // 生成公司选项(与 TrainingContent 保持一致)
+ getCompanyOptions = () => {
+ const { companyData } = this.props;
+ if (!companyData || companyData.length === 0) {
+ return ;
+ }
+ return companyData.map((company, index) => (
+
+ ));
+ };
+
+ // 处理公司筛选变化
+ handleCompanyChange = (value) => {
+ const { onCompanyChange } = this.props;
+ this.setState({ currentPage: 1 }, () => {
+ if (onCompanyChange) {
+ onCompanyChange(value);
+ }
+ });
+ };
+
+ // 处理页码变化
+ handlePageChange = (page, pageSize) => {
+ this.setState({ currentPage: page, pageSize });
+ };
+
+ // 处理每页条数变化
+ handleShowSizeChange = (current, size) => {
+ this.setState({ currentPage: 1, pageSize: size });
+ };
+
+ // 获取过滤后的数据(添加类型检查和默认值)
+ getFilteredData = () => {
+ const { dangerSubData, selectedCompany, companyData } = this.props;
+
+ // 确保 dangerSubData 是数组
+ let dataArray = Array.isArray(dangerSubData) ? dangerSubData : [];
+
+ if (dataArray.length === 0) {
+ return [];
+ }
+
+ // 根据选中的公司进行过滤(使用 ID 进行匹配)
+ if (selectedCompany) {
+ // 查找选中的公司名称
+ const selectedCompanyObj = companyData?.find((company) => company.ID === selectedCompany);
+ const selectedCompanyName = selectedCompanyObj?.NAME;
+
+ if (selectedCompanyName) {
+ return dataArray.filter((item) => item.companyName === selectedCompanyName);
+ }
+ }
+ return dataArray;
+ };
+
+ // 获取当前页数据
+ getCurrentPageData = () => {
+ const { currentPage, pageSize } = this.state;
+ const filteredData = this.getFilteredData();
+ // 确保 filteredData 是数组
+ const dataArray = Array.isArray(filteredData) ? filteredData : [];
+ const startIndex = (currentPage - 1) * pageSize;
+ const endIndex = startIndex + pageSize;
+ return {
+ data: dataArray.slice(startIndex, endIndex),
+ total: dataArray.length,
+ };
+ };
+
+ // 渲染危险作业表格
+ 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 (
+
+ {selectedCompany ? `${companyName}暂无危险作业数据` : '暂无危险作业数据'}
+
+ );
+ }
+
+ // 表格列配置
+ const columns = [
+ {
+ title: '公司',
+ dataIndex: 'companyName',
+ key: 'companyName',
+ align: 'center',
+ width: 120,
+ fixed: 'left',
+ render: (text) => {text},
+ },
+ {
+ title: '开始时间',
+ dataIndex: 'startDate',
+ key: 'startDate',
+ align: 'center',
+ width: 160,
+ render: (text) => {text || '-'},
+ },
+ {
+ title: '结束时间',
+ dataIndex: 'endDate',
+ key: 'endDate',
+ align: 'center',
+ width: 160,
+ render: (text) => {text || '-'},
+ },
+ {
+ title: '作业名称',
+ dataIndex: 'jobName',
+ key: 'jobName',
+ align: 'center',
+ minWidth: 120,
+ render: (text) => {text || '-'},
+ },
+ {
+ title: '作业区域',
+ dataIndex: 'areaName',
+ key: 'areaName',
+ align: 'center',
+ minWidth: 120,
+ render: (text) => {text || '-'},
+ },
+ {
+ title: '作业地点',
+ dataIndex: 'place',
+ key: 'place',
+ align: 'center',
+ minWidth: 150,
+ render: (text) => {text || '-'},
+ },
+ {
+ title: '作业人员',
+ dataIndex: 'users',
+ key: 'users',
+ align: 'center',
+ minWidth: 150,
+ render: (text) => {text || '-'},
+ },
+ {
+ title: '监护人',
+ dataIndex: 'monitor',
+ key: 'monitor',
+ align: 'center',
+ width: 120,
+ render: (text) => {text || '-'},
+ },
+ {
+ title: '审批领导',
+ dataIndex: 'approveUsers',
+ key: 'approveUsers',
+ align: 'center',
+ minWidth: 150,
+ render: (text) => {text || '-'},
+ },
+ ];
+
+ // 计算横向滚动宽度(如果列数过多)
+ const scrollX = columns.reduce((sum, col) => sum + (col.width || 120), 0);
+ const scrollConfig = scrollX > 1200 ? { x: scrollX } : {};
+
+ // 表格数据转换(添加唯一key)
+ const dataSource = tableData.map((item, index) => ({
+ key: `${item.companyName}_${item.startDate}_${index}`,
+ companyName: item.companyName,
+ startDate: item.startDate,
+ endDate: item.endDate,
+ jobName: item.jobName,
+ areaName: item.areaName,
+ place: item.place,
+ users: item.users,
+ monitor: item.monitor,
+ approveUsers: item.approveUsers,
+ }));
+
+ return (
+
+
+ 当日各公司危险作业清单
+
+
+ {/* 分页组件 */}
+
+
`共 ${total} 条记录`}
+ onChange={this.handlePageChange}
+ onShowSizeChange={this.handleShowSizeChange}
+ pageSizeOptions={['10', '20', '50']}
+ />
+
+
+ );
+ };
+
+ componentDidMount() {
+ this.isUnmounted = false;
+ }
+
+ componentDidUpdate(prevProps) {
+ // 当筛选条件变化时,重置到第一页
+ if (prevProps.selectedCompany !== this.props.selectedCompany) {
+ this.setState({ currentPage: 1 });
+ }
+ // 当数据变化时,如果当前页没有数据且不是第一页,重置到第一页
+ if (prevProps.dangerSubData !== this.props.dangerSubData) {
+ const { currentPage } = this.state;
+ const filteredData = this.getFilteredData();
+ const dataArray = Array.isArray(filteredData) ? filteredData : [];
+ const maxPage = Math.ceil(dataArray.length / this.state.pageSize) || 1;
+ if (currentPage > maxPage) {
+ this.setState({ currentPage: 1 });
+ }
+ }
+ }
+
+ componentWillUnmount() {
+ this.isUnmounted = true;
+ }
+
+ render() {
+ const { companyData, selectedCompany } = this.props;
+
+ return (
+
+
+
+
+ {/* 公司筛选器 */}
+
+ 选择公司:
+
+
+ {this.renderDangerTable()}
+
+
+
+
+ );
+ }
+}
+
+export default DangerJob;
diff --git a/src/layout/FullOther/HiddenSolve.js b/src/layout/FullOther/HiddenSolve.js
new file mode 100644
index 0000000..0fd37fb
--- /dev/null
+++ b/src/layout/FullOther/HiddenSolve.js
@@ -0,0 +1,578 @@
+// HiddenSolve.js - 隐患解决页面组件
+import React from 'react';
+import { Select } from 'antd';
+import styles from './../fullinter.less';
+import echarts from 'echarts';
+
+const { Option } = Select;
+
+class HiddenSolve extends React.Component {
+ constructor(props) {
+ super(props);
+ this.echartsInstances = {
+ hiddenBarChart: null, // 各公司隐患统计柱状图(使用 hiddenList)
+ hiddenRectifyChart: null, // 隐患整改情况柱状图(使用 hiddenRectifyList)
+ };
+ this.chartResizeHandlers = {};
+ this.isUnmounted = false;
+ }
+
+ // 获取公司选项(使用 props 传入的 companyData,与 TrainingContent 一致)
+ getCompanyOptions = () => {
+ const { companyData } = this.props;
+ if (!companyData || companyData.length === 0) {
+ return [];
+ }
+ return companyData.map((company, index) => (
+
+ ));
+ };
+
+ // 根据选中的公司ID获取公司名称(用于筛选模拟数据)
+ getSelectedCompanyName = () => {
+ const { companyData, selectedCompany } = this.props;
+ if (!selectedCompany || !companyData || companyData.length === 0) {
+ return null;
+ }
+ const selectedCompanyObj = companyData.find((company) => company.ID === selectedCompany);
+ return selectedCompanyObj ? selectedCompanyObj.NAME : null;
+ };
+
+ waitForElement = (elementId, maxRetries = 10) => {
+ return new Promise((resolve) => {
+ let retries = 0;
+ const checkInterval = setInterval(() => {
+ const element = document.getElementById(elementId);
+ if (element || retries >= maxRetries) {
+ clearInterval(checkInterval);
+ resolve(!!element);
+ }
+ retries++;
+ }, 50);
+ });
+ };
+
+ // 图表1: 各公司隐患统计柱状图(使用 hiddenList 数据)
+ renderHiddenBarChart = async () => {
+ if (this.isUnmounted) return;
+ const elementExists = await this.waitForElement('hiddenBarChart');
+ if (!elementExists || this.isUnmounted) return;
+
+ if (this.echartsInstances.hiddenBarChart) {
+ this.echartsInstances.hiddenBarChart.dispose();
+ this.echartsInstances.hiddenBarChart = null;
+ }
+
+ const chartDom = document.getElementById('hiddenBarChart');
+ if (!chartDom) return;
+
+ this.echartsInstances.hiddenBarChart = echarts.init(chartDom);
+
+ const { hiddenSubData } = this.props;
+ let hiddenList = hiddenSubData?.hiddenList || [];
+
+ if (hiddenList.length === 0) {
+ this.echartsInstances.hiddenBarChart.setOption({
+ title: {
+ 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 companyNames = hiddenList.map((item) => item.companyName);
+ const majorCounts = hiddenList.map((item) => item.majorCount);
+ const generalCounts = hiddenList.map((item) => item.generalCount);
+
+ 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: ['重大隐患', '一般隐患'],
+ orient: 'vertical',
+ right: '3%',
+ top: '5%',
+ itemGap: 16,
+ itemWidth: 18,
+ itemHeight: 12,
+ textStyle: { color: '#000', fontSize: 14 },
+ },
+ grid: {
+ left: '8%',
+ right: '5%',
+ top: '18%',
+ bottom: '8%',
+ containLabel: true,
+ },
+ xAxis: [
+ {
+ type: 'category',
+ data: companyNames,
+ axisLine: { show: false },
+ axisTick: { show: false },
+ axisLabel: {
+ textStyle: { color: '#000' },
+ rotate: companyNames.length > 4 ? 15 : 0,
+ interval: 0,
+ fontSize: 12,
+ },
+ },
+ ],
+ yAxis: [
+ {
+ type: 'value',
+ show: true,
+ axisLine: { show: false },
+ axisTick: { show: false },
+ axisLabel: {
+ show: true,
+ textStyle: { color: '#000' },
+ },
+ splitLine: { show: false },
+ name: '隐患数量',
+ nameTextStyle: { fontSize: 12 },
+ },
+ ],
+ series: [
+ {
+ name: '重大隐患',
+ type: 'bar',
+ data: majorCounts,
+ itemStyle: {
+ normal: {
+ color: '#c92a2a', // 红色
+ },
+ },
+ label: {
+ show: true,
+ position: 'top',
+ textStyle: { color: '#c92a2a', fontSize: 12 },
+ formatter: (params) => `${params.value}`,
+ },
+ barWidth: '35%',
+ },
+ {
+ name: '一般隐患',
+ type: 'bar',
+ data: generalCounts,
+ itemStyle: {
+ normal: {
+ color: '#4285F4', // 蓝色
+ },
+ },
+ label: {
+ show: true,
+ position: 'top',
+ textStyle: { color: '#4285F4', fontSize: 12 },
+ formatter: (params) => `${params.value}`,
+ },
+ barWidth: '35%',
+ },
+ ],
+ };
+
+ this.echartsInstances.hiddenBarChart.setOption(option);
+ this.setupResizeHandler('hiddenBarChart', this.renderHiddenBarChart);
+ };
+
+ // 图表2: 隐患整改情况柱状图(使用 hiddenRectifyList 数据)
+ renderHiddenRectifyChart = async () => {
+ if (this.isUnmounted) return;
+ const elementExists = await this.waitForElement('hiddenRectifyChart');
+ if (!elementExists || this.isUnmounted) return;
+
+ if (this.echartsInstances.hiddenRectifyChart) {
+ this.echartsInstances.hiddenRectifyChart.dispose();
+ this.echartsInstances.hiddenRectifyChart = null;
+ }
+
+ const chartDom = document.getElementById('hiddenRectifyChart');
+ if (!chartDom) return;
+
+ this.echartsInstances.hiddenRectifyChart = echarts.init(chartDom);
+
+ const { hiddenSubData } = this.props;
+ let hiddenRectifyList = hiddenSubData?.hiddenRectifyList || [];
+
+ if (hiddenRectifyList.length === 0) {
+ this.echartsInstances.hiddenRectifyChart.setOption({
+ title: {
+ 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 companyNames = hiddenRectifyList.map((item) => item.companyName);
+ const majorTotal = hiddenRectifyList.map((item) => item.majorCount);
+ const majorRectified = hiddenRectifyList.map((item) => (item.majorCount || 0) - (item.majorCountNo || 0));
+ const generalTotal = hiddenRectifyList.map((item) => item.generalCount);
+ const generalRectified = hiddenRectifyList.map((item) => (item.generalCount || 0) - (item.generalCountNo || 0));
+
+ const option = {
+ title: {
+ 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: ['重大隐患量', '重大隐患未整改量', '一般隐患量', '一般隐患未整改量'],
+ orient: 'vertical',
+ right: '3%',
+ top: '5%',
+ itemGap: 12,
+ itemWidth: 18,
+ itemHeight: 12,
+ textStyle: { color: '#000', fontSize: 12 },
+ },
+ grid: {
+ left: '8%',
+ right: '5%',
+ top: '18%',
+ bottom: '8%',
+ containLabel: true,
+ },
+ xAxis: [
+ {
+ type: 'category',
+ data: companyNames,
+ axisLine: { show: false },
+ axisTick: { show: false },
+ axisLabel: {
+ textStyle: { color: '#000' },
+ rotate: companyNames.length > 4 ? 15 : 0,
+ interval: 0,
+ fontSize: 12,
+ },
+ },
+ ],
+ yAxis: [
+ {
+ type: 'value',
+ show: true,
+ axisLine: { show: false },
+ axisTick: { show: false },
+ axisLabel: {
+ show: true,
+ textStyle: { color: '#000' },
+ },
+ splitLine: { show: false },
+ name: '隐患数量',
+ nameTextStyle: { fontSize: 12 },
+ },
+ ],
+ series: [
+ {
+ name: '重大隐患量',
+ type: 'bar',
+ data: majorTotal,
+ itemStyle: {
+ normal: {
+ color: '#c92a2a', // 红色
+ },
+ },
+ label: {
+ show: true,
+ position: 'top',
+ textStyle: { color: '#c92a2a', fontSize: 11 },
+ formatter: (params) => `${params.value}`,
+ },
+ barWidth: '20%',
+ },
+ {
+ name: '重大隐患未整改量',
+ type: 'bar',
+ data: majorRectified,
+ itemStyle: {
+ normal: {
+ color: '#ffa94d', // 橙色
+ },
+ },
+ label: {
+ show: true,
+ position: 'top',
+ textStyle: { color: '#ffa94d', fontSize: 11 },
+ formatter: (params) => `${params.value}`,
+ },
+ barWidth: '20%',
+ },
+ {
+ name: '一般隐患量',
+ type: 'bar',
+ data: generalTotal,
+ itemStyle: {
+ normal: {
+ color: '#4285F4', // 蓝色
+ },
+ },
+ label: {
+ show: true,
+ position: 'top',
+ textStyle: { color: '#4285F4', fontSize: 11 },
+ formatter: (params) => `${params.value}`,
+ },
+ barWidth: '20%',
+ },
+ {
+ name: '一般隐患未整改量',
+ type: 'bar',
+ data: generalRectified,
+ itemStyle: {
+ normal: {
+ color: '#ffe066', // 黄色
+ },
+ },
+ label: {
+ show: true,
+ position: 'top',
+ textStyle: { color: '#d4a000', fontSize: 11 },
+ formatter: (params) => `${params.value}`,
+ },
+ barWidth: '20%',
+ },
+ ],
+ };
+
+ this.echartsInstances.hiddenRectifyChart.setOption(option);
+ this.setupResizeHandler('hiddenRectifyChart', this.renderHiddenRectifyChart);
+ };
+
+ // 排名列表组件(支持公司筛选)
+ renderRankingList = () => {
+ const { hiddenSubData, selectedCompany, onCompanyChange, companyData } = this.props;
+ let hiddenRanking = hiddenSubData?.hiddenRanking || [];
+
+ // 根据选中的公司筛选数据
+ const selectedCompanyName = this.getSelectedCompanyName();
+ if (selectedCompanyName) {
+ hiddenRanking = hiddenRanking.filter((item) => item.companyName === selectedCompanyName);
+ }
+
+ // if (hiddenRanking.length === 0) {
+ // return (
+ //
+ // {selectedCompanyName ? `${selectedCompanyName} 暂无隐患排名数据` : '暂无隐患排名数据'}
+ //
+ // );
+ // }
+
+ return (
+
+
+ 隐患次数排名列表
+
+
+ 选择公司:
+
+
+ {/* 公司筛选器 - 与 TrainingContent 样式保持一致 */}
+
+
+
+
+
+ | 序号 |
+
+ 隐患名称
+ |
+ 数量 |
+
+
+
+ {hiddenRanking.length > 0 ? (
+ hiddenRanking.map((item, index) => (
+
+ |
+
+ {index + 1}
+
+ |
+ {item.hiddenName} |
+
+ {item.qty}
+ |
+
+ ))
+ ) : (
+ {'暂无隐患排名数据'}
+ )}
+
+
+
+
+ );
+ };
+
+ setupResizeHandler = (chartName, renderMethod) => {
+ const resizeHandler = () => {
+ if (this.echartsInstances[chartName] && !this.isUnmounted) {
+ this.echartsInstances[chartName].resize();
+ }
+ };
+ this.chartResizeHandlers[chartName] = resizeHandler;
+ window.addEventListener('resize', resizeHandler);
+ };
+
+ initAllCharts = () => {
+ if (this.isUnmounted) return;
+ setTimeout(() => {
+ if (this.isUnmounted) return;
+ this.renderHiddenBarChart();
+ this.renderHiddenRectifyChart();
+ }, 100);
+ };
+
+ disposeAllCharts = () => {
+ Object.keys(this.echartsInstances).forEach((key) => {
+ if (this.echartsInstances[key]) {
+ try {
+ this.echartsInstances[key].dispose();
+ } catch (e) {
+ console.warn(`Dispose chart ${key} error:`, e);
+ }
+ this.echartsInstances[key] = null;
+ }
+ });
+
+ Object.keys(this.chartResizeHandlers).forEach((key) => {
+ if (this.chartResizeHandlers[key]) {
+ window.removeEventListener('resize', this.chartResizeHandlers[key]);
+ }
+ });
+ this.chartResizeHandlers = {};
+ };
+
+ componentDidMount() {
+ this.isUnmounted = false;
+ this.initAllCharts();
+ }
+
+ componentDidUpdate(prevProps) {
+ // 当 hiddenSubData 或 selectedCompany 变化时重新渲染图表
+ if (
+ prevProps.hiddenSubData !== this.props.hiddenSubData ||
+ prevProps.selectedCompany !== this.props.selectedCompany
+ ) {
+ this.renderHiddenBarChart();
+ this.renderHiddenRectifyChart();
+ }
+ }
+
+ componentWillUnmount() {
+ this.isUnmounted = true;
+ this.disposeAllCharts();
+ }
+
+ render() {
+ const { selectedCompany, onCompanyChange } = this.props;
+
+ return (
+
+
+ {/* 第一行 - 柱状图(left)+ 排名列表(right) */}
+
+
+ {/* 添加公司筛选器(左上角,与 TrainingContent 样式一致) */}
+
+
+
+ {this.renderRankingList()}
+
+
+ {/* 第二行 - 隐患整改情况柱状图 */}
+
+
+
+ );
+ }
+}
+
+export default HiddenSolve;
diff --git a/src/layout/FullOther/HomeContent.js b/src/layout/FullOther/HomeContent.js
index 10bdee3..08a095f 100644
--- a/src/layout/FullOther/HomeContent.js
+++ b/src/layout/FullOther/HomeContent.js
@@ -1,13 +1,18 @@
// HomeContent.js
import React, { useEffect, useRef } from 'react';
-import { Row, Col, Icon, Carousel } from 'antd';
+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 } from '../../utils/common';
class HomeContent extends React.Component {
constructor(props) {
super(props);
- this.carouselRef = React.createRef();
+ this.sliderRef = React.createRef();
this.echartsInstances = {
riskLevel: null,
safeCheckChart: null,
@@ -16,6 +21,7 @@ class HomeContent extends React.Component {
};
this.chartResizeHandlers = {};
this.isUnmounted = false;
+ this.autoplayTimer = null;
}
waitForElement = (elementId, maxRetries = 10) => {
@@ -111,46 +117,6 @@ class HomeContent extends React.Component {
window.addEventListener('resize', resizeHandler);
};
- transformDat = (originalData, barTopColor, num) => {
- if (!originalData || !Array.isArray(originalData) || originalData.length === 0) {
- return { companyNames: [], series: [], legendData: [] };
- }
-
- let allTypes = [];
- if (num == 1) {
- allTypes = [...new Set(originalData.flatMap((item) => item.details?.map((detail) => detail.jobName)))];
- } else {
- allTypes = [...new Set(originalData.flatMap((item) => item.details?.map((detail) => detail.name)))];
- }
-
- allTypes = allTypes.filter(Boolean);
- const companyNames = originalData?.map((item) => item.company);
- const series = allTypes?.map((typeName, index) => ({
- name: typeName,
- type: 'bar',
- itemStyle: {
- normal: {
- color: function (params) {
- if (num == 1) {
- return barTopColor[index];
- } else {
- return new echarts.graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: barTopColor[index][0] },
- { offset: 1, color: barTopColor[index][1] },
- ]);
- }
- },
- },
- },
- data: originalData?.map((company) => {
- const detail = company.details?.find((d) => (num == 1 ? d.jobName : d.name) === typeName);
- return detail ? detail.qty : 0;
- }),
- }));
-
- return { companyNames, series, legendData: allTypes };
- };
-
safeCheckChart = async () => {
if (this.isUnmounted) return;
const elementExists = await this.waitForElement('safeCheckChart');
@@ -164,48 +130,130 @@ class HomeContent extends React.Component {
let safeCheckCharts = document.getElementById('safeCheckChart');
if (!safeCheckCharts) return;
- const barTopColor = ['#02c3f1', '#53e568', '#a154e9'];
- const jobData = this.props.jobTodayTop3 || [];
+ const hiddenSummary = this.props.hiddenSummary || {};
- if (jobData.length === 0) return;
+ // 检查是否有有效数据
+ 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);
- let xdata = this.transformDat(jobData, barTopColor, 1);
this.echartsInstances.safeCheckChart.setOption({
title: {
- text: '当日工作票排名前三家的数据',
- textStyle: { fontSize: 16, color: '#fff' },
+ 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}
`;
+ params.forEach((param) => {
+ result += `${param.marker}${param.seriesName}: ${param.value}
`;
+ });
+ return result;
+ },
},
- tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
legend: {
- data: xdata.legendData,
- align: 'right',
- right: 10,
- itemGap: 16,
- itemWidth: 18,
+ data: legendData,
+ right: 0,
+ top: '10%',
+ itemGap: 12,
+ itemWidth: 16,
itemHeight: 10,
- textStyle: { color: '#fff', fontSize: 14 },
+ textStyle: { color: '#000', fontSize: 12 },
+ },
+ color: seriesData.map((item) => item.color),
+ grid: {
+ left: '5%',
+ right: '8%',
+ top: '28%',
+ bottom: '5%',
+ containLabel: true,
},
- color: barTopColor,
- grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: [
{
type: 'category',
- data: xdata.companyNames,
- axisLine: { lineStyle: { color: '#3eb2e8' } },
- axisLabel: { textStyle: { color: '#fff' } },
+ data: ['当月隐患'],
+ axisLine: { lineStyle: { color: '#c4c6c9' } },
+ axisLabel: { textStyle: { color: '#000', fontSize: 14 } },
+ axisTick: { show: false },
},
],
yAxis: [
{
type: 'value',
+ name: '数量',
+ nameTextStyle: { color: '#000' },
axisLine: { show: false },
- axisLabel: { textStyle: { color: '#fff' } },
- splitLine: { lineStyle: { color: '#4784e8' } },
+ axisTick: { show: false },
+ splitLine: { show: false },
+ axisLabel: { textStyle: { color: '#000' } },
},
],
- series: xdata.series,
+ 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 = () => {
@@ -230,9 +278,33 @@ class HomeContent extends React.Component {
const dangerOperationCharts = document.getElementById('dangerOperationChart');
if (!dangerOperationCharts) return;
- const linkData = this.props.linkSum || [];
- if (linkData.length === 0) 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);
@@ -253,10 +325,10 @@ class HomeContent extends React.Component {
formatter: function (params) {
const color = params[0].color;
return `
-
- ${params[0].name}:
- ${params[0].value}
-
`;
+
+ ${params[0].name}:
+ ${params[0].value}
+ `;
},
backgroundColor: 'rgba(255, 255, 255, 0.5)',
borderColor: '#FFFFFF',
@@ -268,7 +340,7 @@ class HomeContent extends React.Component {
{
type: 'category',
data: xAxisData,
- axisLine: { lineStyle: { color: '#000' } },
+ axisLine: { lineStyle: { color: '#c4c6c9' } },
axisTick: { show: false },
axisLabel: { textStyle: { color: '#000' }, rotate: 30, interval: 0 },
},
@@ -374,17 +446,17 @@ class HomeContent extends React.Component {
},
legend: {
data: ['培训人次', '培训场次'],
- orient: 'vertical', // 垂直排列
- right: 0, // 水平居中
- top: 'middle', // 垂直居中
- itemGap: 16, // 图例项间隔
+ orient: 'vertical',
+ right: 0,
+ top: 'middle',
+ itemGap: 16,
itemWidth: 18,
itemHeight: 12,
textStyle: { color: '#000', fontSize: 14 },
},
grid: {
left: '5%',
- right: '5%', // 为右侧垂直图例留出空间
+ right: '5%',
top: '18%',
bottom: '5%',
containLabel: true,
@@ -393,8 +465,8 @@ class HomeContent extends React.Component {
{
type: 'category',
data: listNAME,
- axisLine: { show: false }, // 隐藏x轴线
- axisTick: { show: false }, // 隐藏x轴刻度线
+ axisLine: { lineStyle: { color: '#c4c6c9' } },
+ axisTick: { show: false },
axisLabel: {
textStyle: { color: '#000' },
rotate: listNAME.length > 4 ? 15 : 0,
@@ -405,16 +477,16 @@ class HomeContent extends React.Component {
yAxis: [
{
type: 'value',
- show: true, // 显示y轴
- axisLine: { show: false }, // 隐藏y轴线
- axisTick: { show: false }, // 隐藏y轴刻度线
+ show: true,
+ axisLine: { show: false },
+ axisTick: { show: false },
axisLabel: {
- show: true, // 显示数值标签
+ show: true,
textStyle: { color: '#000' },
},
- splitLine: { show: false }, // 隐藏横向网格线
- name: '', // 不显示单位名称
- nameTextStyle: { show: false }, // 隐藏单位文字
+ splitLine: { show: false },
+ name: '',
+ nameTextStyle: { show: false },
},
],
series: [
@@ -424,8 +496,8 @@ class HomeContent extends React.Component {
data: monthPersonCount,
itemStyle: {
normal: {
- color: '#4285F4', // 蓝色
- barBorderRadius: 12, // 柱体圆角
+ color: '#4285F4',
+ barBorderRadius: 12,
},
},
label: {
@@ -442,8 +514,8 @@ class HomeContent extends React.Component {
data: monthRecordCount,
itemStyle: {
normal: {
- color: '#ffe066', // 黄色
- barBorderRadius: 12, // 柱体圆角(上左、上右、下右、下左)
+ color: '#ffe066',
+ barBorderRadius: 12,
},
},
label: {
@@ -468,6 +540,28 @@ class HomeContent extends React.Component {
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(() => {
@@ -500,26 +594,52 @@ class HomeContent extends React.Component {
};
handlePrev = () => {
- if (this.carouselRef.current) {
- this.carouselRef.current.prev();
+ 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.carouselRef.current) {
- this.carouselRef.current.next();
+ 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();
}
};
- handleCarouselChange = (current) => {
- this.props.onCarouselChange?.(current);
+ // 重启自动播放
+ 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.carouselRef.current) {
- this.carouselRef.current.goTo(index);
+ if (this.sliderRef.current) {
+ this.sliderRef.current.slickGoTo(index);
}
+ // 点击圆点时重启自动播放
+ this.restartAutoplay();
+ };
+
+ handleCarouselChange = (current) => {
+ this.props.onCarouselChange?.(current);
};
componentDidMount() {
@@ -528,12 +648,20 @@ class HomeContent extends React.Component {
}
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.jobTodayTop3 !== this.props.jobTodayTop3 ||
- prevProps.linkSum !== this.props.linkSum ||
+ prevProps.hiddenSummary !== this.props.hiddenSummary ||
+ prevProps.jobTodayQty !== this.props.jobTodayQty ||
prevProps.taskTop3 !== this.props.taskTop3 ||
- prevProps.trainingData !== this.props.trainingData // 新增
+ prevProps.trainingData !== this.props.trainingData
) {
this.disposeAllCharts();
this.initAllCharts();
@@ -542,18 +670,170 @@ class HomeContent extends React.Component {
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 (
+
+
+
+ );
+ }
+
+ if (!currentAnnouncement) return null;
+
+ const { TITLE, ABSTRACT, START, END, CONTENT, Nav_Files = [] } = currentAnnouncement;
+
+ return (
+
+ {/* 标题 */}
+
+ {TITLE}
+
+
+ {/* 摘要 */}
+
+ {ABSTRACT}
+
+
+ {/* 日期 */}
+
+ {START} 至 {END}
+
+
+ {/* 分割线 */}
+
+
+ {/* 正文内容 */}
+
+
+ {/* 附件列表 */}
+ {Nav_Files && Nav_Files.length > 0 && (
+
+
+ 附件 ({Nav_Files.length}个)
+
+
+ {Nav_Files.map((file, index) => (
+
+
+
+ {file.Nav_ImgFile?.FILE_NAME || '未知文件'}
+
+
+
+
+
+
+ ))}
+
+
+ )}
+
+ );
+ };
render() {
const {
riskTypeRate = [],
- riskTotal = [],
- mediaList = [],
- announcementList = [],
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 (
@@ -581,12 +861,18 @@ class HomeContent extends React.Component {
年度隐患数据
- {riskTotal.map((item, index) => (
-
-
{item.name}
-
{item.value}
-
- ))}
+
+
年度重大隐患数
+
{hiddenSummary.majorQty}
+
+
+
年度一般隐患数量
+
{hiddenSummary.generalQty}
+
+
+
未整改隐患数量
+
{hiddenSummary.unfinishQty}
+
@@ -598,47 +884,55 @@ class HomeContent extends React.Component {
{/* 中间区域 */}
-
安全方针:以人为本、关注健康、依法治企、安全发展。
-
安全理念:一切风险皆可控,一切事故皆可防!
+
-
- {mediaList.map((item, index) => (
-
- {item.type === 'video' ? (
-
- ) : (
-

- )}
-
- ))}
-
-
-
-
-
-
-
-
- {mediaList.map((_, index) => (
- this.handleDotClick(index)}
+ {trainingData.listVideoImg && trainingData.listVideoImg[0] ? (
+ trainingData.listVideoImg[0].TYPE == 10 ? (
+
- ))}
-
+ ) : (
+
+
+ {trainingData.listVideoImg?.map((item, index) => (
+
+

+
+ ))}
+
+
+
+
+
+
+
+
+ {trainingData.listVideoImg?.map((_, index) => (
+ this.handleDotClick(index)}
+ />
+ ))}
+
+
+ )
+ ) : (
+
+ )}
@@ -648,23 +942,21 @@ class HomeContent extends React.Component {
公司公告
- 共 {announcementList.length} 条公告
+ 共 {trainingData.listAnnourcement?.length || 0} 条公告
- {announcementList.length > 0 ? (
+ {trainingData.listAnnourcement?.length > 0 ? (
- {announcementList.map((item, index) => (
+ {trainingData.listAnnourcement.map((item, index) => (
- item.url && window.open(item.url)}
+ onClick={() => onAnnouncementClick && onAnnouncementClick(item)}
>
-
- {item.title}
-
-
- {item.publishTime || item.createTime || item.date}
+
+ {item.TITLE}
+ {item.START}
))}
@@ -684,14 +976,13 @@ class HomeContent extends React.Component {
年度培训数据
- {this.props.trainingData?.listNAME?.map((name, index) => (
+ {trainingData?.listNAME?.map((name, index) => (
{name}
-
{this.props.trainingData?.YearCount?.[index] || 0}
+
{trainingData?.YearCount?.[index] || 0}
))}
- {/* 如果 listNAME 为空,显示默认提示 */}
- {(!this.props.trainingData?.listNAME || this.props.trainingData.listNAME.length === 0) && (
+ {(!trainingData?.listNAME || trainingData.listNAME.length === 0) && (
暂无培训数据
)}
@@ -708,6 +999,21 @@ class HomeContent extends React.Component {
+ {/* 公告详情弹窗 */}
+
+ 关闭
+ ,
+ ]}
+ width="80%"
+ bodyStyle={{ padding: '20px', maxHeight: '70vh', overflowY: 'auto' }}
+ >
+ {this.renderAnnouncementModal()}
+
);
}
diff --git a/src/layout/FullOther/RiskControl.js b/src/layout/FullOther/RiskControl.js
new file mode 100644
index 0000000..a8232aa
--- /dev/null
+++ b/src/layout/FullOther/RiskControl.js
@@ -0,0 +1,515 @@
+// RiskControl.js - 风险管控页面组件
+import React from 'react';
+import { Table } from 'antd';
+import styles from './../fullinter.less';
+import echarts from 'echarts';
+
+class RiskControl extends React.Component {
+ constructor(props) {
+ super(props);
+ this.echartsInstances = {
+ stackBarChart: null, // 堆叠柱状图
+ typeBarChart: 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);
+ });
+ };
+
+ // 堆叠柱状图: 各公司风险统计(与 trainingContent 样式一致)
+ renderStackBarChart = async () => {
+ if (this.isUnmounted) return;
+ const elementExists = await this.waitForElement('stackBarChart');
+ if (!elementExists || this.isUnmounted) return;
+
+ if (this.echartsInstances.stackBarChart) {
+ this.echartsInstances.stackBarChart.dispose();
+ this.echartsInstances.stackBarChart = null;
+ }
+
+ const chartDom = document.getElementById('stackBarChart');
+ if (!chartDom) return;
+
+ this.echartsInstances.stackBarChart = echarts.init(chartDom);
+
+ const { riskSubData } = this.props;
+ const riskList = riskSubData?.riskList || [];
+
+ if (riskList.length === 0) {
+ this.echartsInstances.stackBarChart.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 companyNames = riskList.map((item) => item.companyName);
+ const majorCounts = riskList.map((item) => item.majorCount);
+ const largerCounts = riskList.map((item) => item.largerCount);
+ const generalCounts = riskList.map((item) => item.generalCount);
+ const lowCounts = riskList.map((item) => item.lowCount);
+
+ 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: ['重大风险', '较大风险', '一般风险', '低风险'],
+ orient: 'vertical',
+ right: '3%',
+ top: '5%',
+ itemGap: 16,
+ itemWidth: 18,
+ itemHeight: 12,
+ textStyle: { color: '#000', fontSize: 14 },
+ },
+ grid: {
+ left: '8%',
+ right: '5%',
+ top: '18%',
+ bottom: '8%',
+ containLabel: true,
+ },
+ xAxis: [
+ {
+ type: 'category',
+ data: companyNames,
+ axisLine: { show: false },
+ axisTick: { show: false },
+ axisLabel: {
+ textStyle: { color: '#000' },
+ rotate: companyNames.length > 4 ? 15 : 0,
+ interval: 0,
+ fontSize: 12,
+ },
+ },
+ ],
+ yAxis: [
+ {
+ type: 'value',
+ show: true,
+ axisLine: { show: false },
+ axisTick: { show: false },
+ axisLabel: {
+ show: true,
+ textStyle: { color: '#000' },
+ },
+ splitLine: { show: false },
+ name: '风险数量',
+ nameTextStyle: { fontSize: 12 },
+ },
+ ],
+ series: [
+ {
+ name: '重大风险',
+ type: 'bar',
+ stack: 'total',
+ data: majorCounts,
+ itemStyle: { normal: { color: '#c92a2a' } },
+ label: {
+ show: true,
+ position: 'inside',
+ textStyle: { color: '#fff', fontSize: 11 },
+ formatter: (params) => (params.value > 0 ? params.value : ''),
+ },
+ barWidth: '35%',
+ },
+ {
+ name: '较大风险',
+ type: 'bar',
+ stack: 'total',
+ data: largerCounts,
+ itemStyle: { normal: { color: '#ffa94d' } },
+ label: {
+ show: true,
+ position: 'inside',
+ textStyle: { color: '#fff', fontSize: 11 },
+ formatter: (params) => (params.value > 0 ? params.value : ''),
+ },
+ barWidth: '35%',
+ },
+ {
+ name: '一般风险',
+ type: 'bar',
+ stack: 'total',
+ data: generalCounts,
+ itemStyle: { normal: { color: '#ffe066' } },
+ label: {
+ show: true,
+ position: 'inside',
+ textStyle: { color: '#fff', fontSize: 11 },
+ formatter: (params) => (params.value > 0 ? params.value : ''),
+ },
+ barWidth: '35%',
+ },
+ {
+ name: '低风险',
+ type: 'bar',
+ stack: 'total',
+ data: lowCounts,
+ itemStyle: { normal: { color: '#4285F4' } },
+ label: {
+ show: true,
+ position: 'inside',
+ textStyle: { color: '#fff', fontSize: 11 },
+ formatter: (params) => (params.value > 0 ? params.value : ''),
+ },
+ barWidth: '35%',
+ },
+ ],
+ };
+
+ this.echartsInstances.stackBarChart.setOption(option);
+ this.setupResizeHandler('stackBarChart', this.renderStackBarChart);
+ };
+
+ // 风险类别柱状图
+ renderTypeBarChart = async () => {
+ if (this.isUnmounted) return;
+ const elementExists = await this.waitForElement('typeBarChart');
+ if (!elementExists || this.isUnmounted) return;
+
+ if (this.echartsInstances.typeBarChart) {
+ this.echartsInstances.typeBarChart.dispose();
+ this.echartsInstances.typeBarChart = null;
+ }
+
+ const chartDom = document.getElementById('typeBarChart');
+ if (!chartDom) return;
+
+ this.echartsInstances.typeBarChart = echarts.init(chartDom);
+
+ const { riskSubData } = this.props;
+ const riskTypeList = riskSubData?.riskTypeList || [];
+
+ if (riskTypeList.length === 0) {
+ this.echartsInstances.typeBarChart.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 typeNames = riskTypeList.map((item) => item.typeName);
+ const quantities = riskTypeList.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) {
+ let result = `${params[0].axisValue}
`;
+ params.forEach((param) => {
+ result += `${param.marker}${param.seriesName}: ${param.value}
`;
+ });
+ return result;
+ },
+ },
+ grid: {
+ left: '8%',
+ right: '5%',
+ top: '18%',
+ bottom: '8%',
+ containLabel: true,
+ },
+ xAxis: [
+ {
+ type: 'category',
+ data: typeNames,
+ axisLine: { show: false },
+ axisTick: { show: false },
+ axisLabel: {
+ textStyle: { color: '#000' },
+ // rotate: typeNames.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 },
+ },
+ ],
+ series: [
+ {
+ name: '风险数量',
+ type: 'bar',
+ data: quantities,
+ itemStyle: {
+ normal: {
+ color: '#4285F4', // 与 trainingContent 一致的蓝色
+ },
+ },
+ label: {
+ show: true,
+ position: 'top',
+ textStyle: { color: '#4285F4', fontSize: 12 },
+ formatter: (params) => `${params.value}`,
+ },
+ barWidth: '50%',
+ },
+ ],
+ };
+
+ this.echartsInstances.typeBarChart.setOption(option);
+ this.setupResizeHandler('typeBarChart', this.renderTypeBarChart);
+ };
+
+ // 表格: 各公司风险统计明细表
+ renderRiskTable = () => {
+ const { riskSubData } = this.props;
+ const riskList = riskSubData?.riskList || [];
+
+ if (riskList.length === 0) {
+ return 暂无风险数据
;
+ }
+
+ // 表格列配置(与 trainingContent 样式保持一致)
+ const columns = [
+ {
+ title: '公司名称',
+ dataIndex: 'companyName',
+ key: 'companyName',
+ align: 'center',
+ width: 120,
+ render: (text) => {text},
+ },
+ {
+ title: '重大风险',
+ dataIndex: 'majorCount',
+ key: 'majorCount',
+ align: 'center',
+ width: 100,
+ render: (text) => {text},
+ },
+ {
+ title: '较大风险',
+ dataIndex: 'largerCount',
+ key: 'largerCount',
+ align: 'center',
+ width: 100,
+ render: (text) => {text},
+ },
+ {
+ title: '一般风险',
+ dataIndex: 'generalCount',
+ key: 'generalCount',
+ align: 'center',
+ width: 100,
+ render: (text) => {text},
+ },
+ {
+ title: '低风险',
+ dataIndex: 'lowCount',
+ key: 'lowCount',
+ align: 'center',
+ width: 100,
+ render: (text) => {text},
+ },
+ {
+ title: '小计',
+ dataIndex: 'totalCount',
+ key: 'totalCount',
+ align: 'center',
+ width: 100,
+ render: (text) => {text},
+ },
+ ];
+
+ const tableData = riskList.map((item, index) => ({
+ key: index,
+ companyName: item.companyName,
+ majorCount: item.majorCount,
+ largerCount: item.largerCount,
+ generalCount: item.generalCount,
+ lowCount: item.lowCount,
+ totalCount: item.totalCount,
+ }));
+
+ // 合计行
+ const summary = {
+ majorTotal: riskList.reduce((sum, item) => sum + (item.majorCount || 0), 0),
+ largerTotal: riskList.reduce((sum, item) => sum + (item.largerCount || 0), 0),
+ generalTotal: riskList.reduce((sum, item) => sum + (item.generalCount || 0), 0),
+ lowTotal: riskList.reduce((sum, item) => sum + (item.lowCount || 0), 0),
+ totalAll: riskList.reduce((sum, item) => sum + (item.totalCount || 0), 0),
+ };
+ const scrollConfig = columns.length > 10 ? { x: columns.length * 100, y: 380 } : {};
+ return (
+
+ );
+ };
+
+ 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.renderStackBarChart();
+ this.renderTypeBarChart();
+ }, 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) {
+ if (prevProps.riskSubData !== this.props.riskSubData) {
+ this.renderStackBarChart();
+ this.renderTypeBarChart();
+ }
+ }
+
+ componentWillUnmount() {
+ this.isUnmounted = true;
+ this.disposeAllCharts();
+ }
+
+ render() {
+ return (
+
+
+ {/* 第一行 - 表格 + 堆叠柱状图 */}
+
+
{this.renderRiskTable()}
+
+
+ {/* 第二行 - 风险类别柱状图 */}
+
+
+
+ );
+ }
+}
+
+export default RiskControl;
diff --git a/src/layout/FullOther/TrainingContent.js b/src/layout/FullOther/TrainingContent.js
index e115a23..f8e7401 100644
--- a/src/layout/FullOther/TrainingContent.js
+++ b/src/layout/FullOther/TrainingContent.js
@@ -226,7 +226,7 @@ class TrainingContent extends React.Component {
if (companyNames.length === 0) {
this.echartsInstances.chart2.setOption({
title: {
- text: '本年度各公司培训分析',
+ text: '各公司月度培训分析',
x: 'center',
y: '25%',
textStyle: { fontSize: 16, color: '#999' },
@@ -247,7 +247,7 @@ class TrainingContent extends React.Component {
const option = {
title: {
- text: '本年度各公司培训分析',
+ text: '各公司月度培训分析',
x: 'center',
y: '5%',
textStyle: { fontSize: 16, color: '#000', fontWeight: 'bold' },
@@ -693,7 +693,7 @@ class TrainingContent extends React.Component {
color: '#000',
}}
>
- 特种作业操作证统计
+ 各公司证件统计
{this.renderCertificateTable()}
diff --git a/src/layout/FullScreenInter.js b/src/layout/FullScreenInter.js
index a7964a5..ecb8356 100644
--- a/src/layout/FullScreenInter.js
+++ b/src/layout/FullScreenInter.js
@@ -2,14 +2,18 @@
import React from 'react';
import { connect } from 'dva';
import { withRouter } from 'dva/router';
-import { Icon, Row, Col } from 'antd';
+import { Icon, Row, Col, message } from 'antd';
import styles from './fullinter.less';
import logo from '../assets/layout/headerno-logo-new.png';
import debounce from 'lodash.debounce';
import storage from '../utils/storage';
-import { initFilter } from '../utils/common';
+import { initFilter, extendRule } from '../utils/common';
import HomeContent from './FullOther/HomeContent';
-import TrainingContent from './FullOther/TrainingContent'; // 新增导入
+import TrainingContent from './FullOther/TrainingContent';
+import RiskControl from './FullOther/RiskControl';
+import ClassBuild from './FullOther/ClassBuild';
+import DangerJob from './FullOther/DangerJob';
+import HiddenSolve from './FullOther/HiddenSolve';
const getScale = () => {
const width = 1920,
@@ -25,13 +29,9 @@ class FullScreen extends React.Component {
this.state = {
nowDate: '',
riskTypeRate: [],
- riskTotal: [
- { name: '年度重大隐患数', value: 1 },
- { name: '年度一般隐患数量', value: 89 },
- { name: '未整改隐患数量', value: 18 },
- ],
- linkSum: [],
- jobTodayTop3: [],
+ riskTotal: [],
+ jobTodayQty: [],
+ hiddenSummary: [],
taskTop3: [],
scale: getScale(),
configBanner: ['首页', '风险管控', '隐患治理', '班组建设', '危险作业', '安全培训'],
@@ -39,14 +39,17 @@ class FullScreen extends React.Component {
currentMediaIndex: 0,
announcementList: [],
activeTab: '首页',
- // 新增:培训数据
+ // 安全培训相关数据
trainingData: {
listNAME: [],
YearCount: [],
MonthRecordCount: [],
MonthPersonCount: [],
+ listAnnourcement: [],
+ TITLE: '',
+ listVideoImg: [],
+ playSet: [],
},
- // 新增:安全培训页面专用数据
trainingSubData: {
listNAME: [],
YearCount: [],
@@ -61,12 +64,29 @@ class FullScreen extends React.Component {
},
trainingSubIDCard: [],
trainingSubBSType: {},
- companyData: [],
- // 新增:当前选择的月份
- selectedMonth: new Date().getMonth() + 1, // 默认当前月份,1-12
- selectedCompany: '',
+ trainingCompanyData: [], // 安全培训专用公司数据
+ selectedTrainingMonth: new Date().getMonth() + 1,
+ selectedTrainingCompany: '',
+
+ // 隐患治理相关数据
+ hiddenSubData: {}, // 隐患治理数据
+ hiddenCompanyData: [], // 隐患治理专用公司数据
+ selectedHiddenCompany: '', // 隐患治理选中的公司
+
+ // 其他页面数据
+ riskSubData: {},
+ classSubData: {},
+ dangerSubData: {},
+ dangerCompanyData: [],
+ selectedDangerCompany: '',
+
+ announcementDetail: null,
+ announcementDetailLoading: false,
+ announcementModalVisible: false,
+ currentAnnouncement: null,
};
this.isUnmounted = false;
+ this.dataTimer = null; // 新增:用于数据定时请求
}
setScale = debounce(() => {
@@ -81,15 +101,56 @@ class FullScreen extends React.Component {
document.exitFullscreen?.();
}
};
+ startDataRefreshTimer = () => {
+ // 清除已有定时器
+ if (this.dataTimer) {
+ clearInterval(this.dataTimer);
+ }
+
+ // 设置新的定时器,每5分钟执行一次
+ this.dataTimer = setInterval(
+ () => {
+ if (!this.isUnmounted) {
+ if (this.state.activeTab === '首页') {
+ this.getHomeDataArray();
+ this.getYearPXData();
+ }
+ // 安全培训 - 参考原有逻辑
+ else if (this.state.activeTab === '安全培训') {
+ this.getTrainingCompanyData(); // 先获取公司列表
+ this.getHomeSESubYearData();
+ this.getHomeSESubYearMonthData();
+ this.getHomeSESubIDCardData();
+ }
+ // 隐患治理 - 参考安全培训的调用顺序
+ else if (this.state.activeTab === '隐患治理') {
+ this.getHiddenCompanyData(); // 先获取公司列表(与安全培训独立)
+ }
+ // 风险管控
+ else if (this.state.activeTab === '风险管控') {
+ this.getRiskSubData();
+ }
+ // 班组建设
+ else if (this.state.activeTab === '班组建设') {
+ this.getClassSubData();
+ }
+ // 危险作业
+ else if (this.state.activeTab === '危险作业') {
+ this.getDangerCompanyData();
+ }
+ }
+ },
+ 5 * 60 * 1000
+ ); // 5分钟 = 300000毫秒
+ };
componentDidMount() {
this.isUnmounted = false;
window.addEventListener('resize', this.setScale);
this.getHomeDataArray();
this.getYearPXData();
- this.loadMediaFiles();
- this.getAnnouncementData();
-
+ // 启动定时刷新
+ this.startDataRefreshTimer();
this.timer = setInterval(() => {
if (!this.isUnmounted) this.setState({ nowDate: this.getDate() });
}, 1000);
@@ -97,24 +158,56 @@ class FullScreen extends React.Component {
document.addEventListener('fullscreenchange', this.handleFullscreenChange);
}
- getAnnouncementData = () => {
- this.setState({
- announcementList: [
- { id: 1, title: '关于2024年安全生产月活动的通知', publishTime: '2024-06-01', url: '' },
- { id: 2, title: '公司第三季度安全培训安排', publishTime: '2024-05-28', url: '' },
- { id: 3, title: '关于开展安全隐患排查整治工作的通知', publishTime: '2024-05-20', url: '' },
- { id: 4, title: '安全生产标准化建设阶段性总结', publishTime: '2024-05-15', url: '' },
- { id: 5, title: '关于表彰2024年第一季度安全生产先进单位的决定', publishTime: '2024-05-10', url: '' },
- ],
+ getAnnouncementDetail = (announcement) => {
+ return new Promise((resolve, reject) => {
+ const orgId = storage('lacal').getItem('webOrgId')?.val;
+ const json = initFilter(orgId);
+ extendRule(json, 'ID', 1, announcement.ID);
+ json.Include = ['Nav_Orgs', 'Nav_Orgs.Nav_OrgSub', 'Nav_Files.Nav_ImgFile'];
+
+ this.setState({ announcementDetailLoading: true, announcementDetail: null });
+
+ this.props.dispatch({
+ type: 'app/getDataByPost',
+ payload: json,
+ url: 'PF/Annourcement/Get',
+ onComplete: (ret) => {
+ if (ret && !this.isUnmounted) {
+ this.setState({
+ announcementDetail: ret,
+ announcementDetailLoading: false,
+ });
+ resolve(ret);
+ } else {
+ message.error('暂无公告详情');
+ this.setState({ announcementDetailLoading: false });
+ reject(new Error('获取公告详情失败'));
+ }
+ },
+ onError: (error) => {
+ this.setState({ announcementDetailLoading: false });
+ reject(error);
+ },
+ });
});
};
- loadMediaFiles = () => {
+ handleAnnouncementClick = async (announcement) => {
+ try {
+ const detail = await this.getAnnouncementDetail(announcement);
+ this.setState({
+ currentAnnouncement: detail,
+ announcementModalVisible: true,
+ });
+ } catch (error) {
+ console.error('获取公告详情失败:', error);
+ }
+ };
+
+ handleAnnouncementModalClose = () => {
this.setState({
- mediaList: [
- { type: 'image', url: 'http://10.2.7.18:28028//WZ_Images/static/smyzw@2x.png' },
- { type: 'video', url: 'http://10.2.7.18:28028/WZ_Images/Img_JFSC/welcom/1.mp4' },
- ],
+ announcementModalVisible: false,
+ currentAnnouncement: null,
});
};
@@ -129,17 +222,31 @@ class FullScreen extends React.Component {
handleTabClick = (name) => {
this.setState({ activeTab: name });
if (name === '首页') {
+ this.getHomeDataArray();
this.getYearPXData();
- this.loadMediaFiles();
- this.getAnnouncementData();
}
- // 当点击安全培训tab时,获取对应数据
+ // 安全培训 - 参考原有逻辑
if (name === '安全培训') {
+ this.getTrainingCompanyData(); // 先获取公司列表
this.getHomeSESubYearData();
this.getHomeSESubYearMonthData();
this.getHomeSESubIDCardData();
- // this.getBSTypeMonthData();
- this.getCompanyData();
+ }
+ // 隐患治理 - 参考安全培训的调用顺序
+ if (name === '隐患治理') {
+ this.getHiddenCompanyData(); // 先获取公司列表(与安全培训独立)
+ }
+ // 风险管控
+ if (name === '风险管控') {
+ this.getRiskSubData();
+ }
+ // 班组建设
+ if (name === '班组建设') {
+ this.getClassSubData();
+ }
+ // 危险作业
+ if (name === '危险作业') {
+ this.getDangerCompanyData();
}
};
@@ -151,6 +258,9 @@ class FullScreen extends React.Component {
this.isUnmounted = true;
window.removeEventListener('resize', this.setScale);
if (this.timer) clearInterval(this.timer);
+ // 清除数据刷新定时器
+ if (this.dataTimer) clearInterval(this.dataTimer);
+
document.removeEventListener('fullscreenchange', this.handleFullscreenChange);
}
@@ -179,14 +289,15 @@ class FullScreen extends React.Component {
if (ret && !this.isUnmounted) {
this.setState({
riskTypeRate: ret.riskTypeRate || [],
- linkSum: ret.linkSum || [],
- jobTodayTop3: ret.jobTodayTop3 || [],
+ jobTodayQty: ret.jobTodayQty || [],
+ hiddenSummary: ret.hiddenSummary || [],
taskTop3: ret.taskTop3 || [],
});
}
},
});
};
+
getYearPXData = () => {
const orgId = storage('lacal').getItem('webOrgId')?.val;
const json = initFilter(orgId);
@@ -202,29 +313,63 @@ class FullScreen extends React.Component {
YearCount: ret.YearCount || [],
MonthRecordCount: ret.MonthRecordCount || [],
MonthPersonCount: ret.MonthPersonCount || [],
+ listAnnourcement: ret.listAnnourcement || [],
+ TITLE: ret.TITLE || '',
+ listVideoImg: ret.listVideoImg || [],
+ playSet: ret.playSet || [],
},
});
}
},
});
};
- // 获取安全培训页面数据
+
+ // ==================== 安全培训相关方法 ====================
+ getTrainingCompanyData = () => {
+ const orgId = storage('lacal').getItem('webOrgId')?.val;
+ const json = initFilter(orgId);
+ this.props.dispatch({
+ type: 'app/getDataByPost',
+ payload: json,
+ url: 'FM/Organization/OrderPaged',
+ onComplete: (ret) => {
+ if (ret && !this.isUnmounted) {
+ // 默认选中邦泰公司
+ const defaultCompany = ret.find((company) => company.ID === '00500000-0000-0000-0000-000000000000');
+ this.setState({
+ trainingCompanyData: ret,
+ });
+ if (defaultCompany && !this.state.selectedTrainingCompany) {
+ this.setState(
+ {
+ selectedTrainingCompany: defaultCompany.ID,
+ },
+ () => {
+ this.getBSTypeMonthData(); // 公司设置完成后获取培训类型数据
+ }
+ );
+ } else {
+ this.getBSTypeMonthData();
+ }
+ }
+ },
+ });
+ };
+
getHomeSESubYearData = () => {
const orgId = storage('lacal').getItem('webOrgId')?.val;
const json = initFilter(orgId);
- const currentYear = new Date().getFullYear(); // 获取当前年份
- json.Parameter1 = currentYear.toString(); // 设置为当前年份
+ 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 MonthPersonCount = ret.map((item) => item.PCount);
+ const MonthRecordCount = ret.map((item) => item.RCount);
const YearCount = ret.map((item) => item.PCount);
this.setState({
@@ -239,38 +384,34 @@ class FullScreen extends React.Component {
},
});
};
- // 新增:处理月份变化
- handleMonthChange = (month) => {
- this.setState({ selectedMonth: month }, () => {
- // 重新获取月份数据
+
+ handleTrainingMonthChange = (month) => {
+ this.setState({ selectedTrainingMonth: month }, () => {
this.getHomeSESubYearMonthData();
});
};
- handleCompanyChange = (company) => {
- console.log(company, '11111');
- this.setState({ selectedCompany: company }, () => {
- // 重新获取月份数据
+
+ handleTrainingCompanyChange = (company) => {
+ this.setState({ selectedTrainingCompany: company }, () => {
this.getBSTypeMonthData();
});
};
- // 获取安全培训页面数据
+
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(); // 月份
+ const currentYear = new Date().getFullYear();
+ json.Parameter1 = currentYear.toString();
+ json.Parameter2 = this.state.selectedTrainingMonth.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 MonthPersonCount = ret.map((item) => item.PCount);
+ const MonthRecordCount = ret.map((item) => item.RCount);
const YearCount = ret.map((item) => item.PCount);
this.setState({
@@ -285,6 +426,7 @@ class FullScreen extends React.Component {
},
});
};
+
getHomeSESubIDCardData = () => {
const orgId = storage('lacal').getItem('webOrgId')?.val;
const json = initFilter(orgId);
@@ -292,9 +434,9 @@ class FullScreen extends React.Component {
const year = currentDate.getFullYear();
const month = String(currentDate.getMonth() + 1).padStart(2, '0');
const day = String(currentDate.getDate()).padStart(2, '0');
- const currentDateStr = `${year}-${month}-${day}`; // 例如:2024-06-15
+ const currentDateStr = `${year}-${month}-${day}`;
- json.Parameter1 = currentDateStr; // 设置为当前日期
+ json.Parameter1 = currentDateStr;
this.props.dispatch({
type: 'app/getDataByPost',
payload: json,
@@ -308,6 +450,7 @@ class FullScreen extends React.Component {
},
});
};
+
getBSTypeMonthData = () => {
const orgId = storage('lacal').getItem('webOrgId')?.val;
const json = initFilter(orgId);
@@ -315,11 +458,11 @@ class FullScreen extends React.Component {
const year = currentDate.getFullYear();
const month = String(currentDate.getMonth() + 1).padStart(2, '0');
const day = String(currentDate.getDate()).padStart(2, '0');
- const currentDateStr = `${year}-${month}-${day}`; // 例如:2024-06-15
+ const currentDateStr = `${year}-${month}-${day}`;
- json.Parameter1 = currentDateStr; // 设置为当前日期
- if (this.state.selectedCompany) {
- json.Parameter2 = this.state.selectedCompany;
+ json.Parameter1 = currentDateStr;
+ if (this.state.selectedTrainingCompany) {
+ json.Parameter2 = this.state.selectedTrainingCompany;
}
this.props.dispatch({
type: 'app/getDataByPost',
@@ -334,7 +477,10 @@ class FullScreen extends React.Component {
},
});
};
- getCompanyData = () => {
+
+ // ==================== 隐患治理相关方法 ====================
+ // 获取隐患治理的公司列表(独立于安全培训)
+ getHiddenCompanyData = () => {
const orgId = storage('lacal').getItem('webOrgId')?.val;
const json = initFilter(orgId);
this.props.dispatch({
@@ -343,18 +489,155 @@ class FullScreen extends React.Component {
url: 'FM/Organization/OrderPaged',
onComplete: (ret) => {
if (ret && !this.isUnmounted) {
- //加载页面默认为绑泰
+ // 默认选中邦泰公司
const defaultCompany = ret.find((company) => company.ID === '00500000-0000-0000-0000-000000000000');
this.setState({
- companyData: ret,
+ hiddenCompanyData: ret,
});
- // 如果找到了默认公司,设置 selectedCompany
- if (defaultCompany && !this.state.selectedCompany) {
+ if (defaultCompany && !this.state.selectedHiddenCompany) {
this.setState({
- selectedCompany: defaultCompany.ID,
+ selectedHiddenCompany: defaultCompany.ID,
});
}
- this.getBSTypeMonthData();
+ this.getHiddenSubData();
+ }
+ },
+ });
+ };
+
+ // 隐患治理公司筛选变化处理
+ handleHiddenCompanyChange = (company) => {
+ this.setState({ selectedHiddenCompany: company }, () => {
+ this.getHiddenSubData();
+ });
+ };
+
+ getHiddenSubData = () => {
+ // 以下是真实的API调用代码,如需使用请取消注释
+ const orgId = storage('lacal').getItem('webOrgId')?.val;
+ const json = initFilter(orgId);
+ this.props.dispatch({
+ type: 'app/getDataByPost',
+ payload: json,
+ url: 'BI/BIKanBanController/HiddenManage',
+ onComplete: (ret) => {
+ if (ret && !this.isUnmounted) {
+ let filteredData = ret;
+ if (this.state.selectedHiddenCompany) {
+ const selectedCompanyObj = this.state.hiddenCompanyData?.find(
+ (company) => company.ID === this.state.selectedHiddenCompany
+ );
+ const selectedCompanyName = selectedCompanyObj?.NAME;
+
+ if (selectedCompanyName) {
+ // 筛选 hiddenRanking
+ filteredData.hiddenRanking = filteredData.hiddenRanking.filter(
+ (item) => item.companyName === selectedCompanyName
+ );
+ }
+ }
+ this.setState({
+ hiddenSubData: filteredData,
+ });
+ }
+ },
+ });
+ };
+
+ // ==================== 其他页面方法 ====================
+ getRiskSubData = () => {
+ const orgId = storage('lacal').getItem('webOrgId')?.val;
+ const json = initFilter(orgId);
+ this.props.dispatch({
+ type: 'app/getDataByPost',
+ payload: json,
+ url: 'BI/BIKanBanController/RiskManage',
+ onComplete: (ret) => {
+ if (ret && !this.isUnmounted) {
+ this.setState({
+ riskSubData: ret,
+ });
+ }
+ },
+ });
+ };
+
+ getClassSubData = () => {
+ const orgId = storage('lacal').getItem('webOrgId')?.val;
+ const json = initFilter(orgId);
+ this.props.dispatch({
+ type: 'app/getDataByPost',
+ payload: json,
+ url: 'BI/BIKanBanController/TeamManage',
+ onComplete: (ret) => {
+ if (ret && !this.isUnmounted) {
+ this.setState({
+ classSubData: ret,
+ });
+ }
+ },
+ });
+ };
+
+ getDangerCompanyData = () => {
+ const orgId = storage('lacal').getItem('webOrgId')?.val;
+ const json = initFilter(orgId);
+ this.props.dispatch({
+ type: 'app/getDataByPost',
+ payload: json,
+ url: 'FM/Organization/OrderPaged',
+ onComplete: (ret) => {
+ if (ret && !this.isUnmounted) {
+ const defaultCompany = ret.find((company) => company.ID === '00500000-0000-0000-0000-000000000000');
+ this.setState({
+ dangerCompanyData: ret,
+ });
+ if (defaultCompany && !this.state.selectedDangerCompany) {
+ this.setState(
+ {
+ selectedDangerCompany: defaultCompany.ID,
+ },
+ () => {
+ this.getDangerSubData();
+ }
+ );
+ } else {
+ this.getDangerSubData();
+ }
+ }
+ },
+ });
+ };
+
+ handleDangerCompanyChange = (company) => {
+ this.setState({ selectedDangerCompany: company }, () => {
+ this.getDangerSubData();
+ });
+ };
+
+ getDangerSubData = () => {
+ const orgId = storage('lacal').getItem('webOrgId')?.val;
+ const json = initFilter(orgId);
+ this.props.dispatch({
+ type: 'app/getDataByPost',
+ payload: json,
+ url: 'BI/BIKanBanController/JobManage',
+ onComplete: (ret) => {
+ if (ret && !this.isUnmounted) {
+ let filteredData = ret;
+ if (this.state.selectedDangerCompany) {
+ const selectedCompanyObj = this.state.dangerCompanyData?.find(
+ (company) => company.ID === this.state.selectedDangerCompany
+ );
+ const selectedCompanyName = selectedCompanyObj?.NAME;
+ if (selectedCompanyName) {
+ filteredData = filteredData.filter((item) => item.companyName === selectedCompanyName);
+ }
+ }
+
+ this.setState({
+ dangerSubData: filteredData,
+ });
}
},
});
@@ -363,32 +646,61 @@ class FullScreen extends React.Component {
renderOtherTabContent = () => {
const {
activeTab,
- trainingData,
trainingSubData,
- trainingSubDataMonth,
- selectedMonth,
- selectedCompany,
trainingSubBSType,
- companyData,
+ trainingCompanyData,
+ trainingSubDataMonth,
+ selectedTrainingMonth,
+ selectedTrainingCompany,
trainingSubIDCard,
+ riskSubData,
+ classSubData,
+ hiddenSubData,
+ hiddenCompanyData,
+ selectedHiddenCompany,
} = this.state;
- // 如果是安全培训,显示专门的培训页面
+
if (activeTab === '安全培训') {
return (
);
}
+ if (activeTab === '风险管控') {
+ return ;
+ }
+ if (activeTab === '隐患治理') {
+ return (
+
+ );
+ }
+ if (activeTab === '班组建设') {
+ return ;
+ }
+ if (activeTab === '危险作业') {
+ return (
+
+ );
+ }
return (
@@ -408,13 +720,16 @@ class FullScreen extends React.Component {
activeTab,
riskTypeRate,
riskTotal,
- jobTodayTop3,
- linkSum,
+ hiddenSummary,
+ jobTodayQty,
taskTop3,
mediaList,
announcementList,
currentMediaIndex,
trainingData,
+ announcementModalVisible,
+ currentAnnouncement,
+ announcementDetailLoading,
} = this.state;
return (
@@ -470,15 +785,20 @@ class FullScreen extends React.Component {
) : (
this.renderOtherTabContent()
diff --git a/src/layout/fullinter.less b/src/layout/fullinter.less
index b9bccfe..54e5648 100644
--- a/src/layout/fullinter.less
+++ b/src/layout/fullinter.less
@@ -281,7 +281,7 @@
justify-content: center;
font-weight: bold;
color: #fff;
- background-color: #1e2a3a;
+ background-color: #909399;
margin: 10px 20px;
padding: 5px 10px;
border-radius: 4px;
@@ -313,7 +313,7 @@
justify-content: center;
font-weight: bold;
color: #fff;
- background-color: #1e2a3a;
+ background-color: #909399;
margin: 10px 20px;
padding: 5px 10px;
border-radius: 4px;
@@ -492,38 +492,59 @@
margin-bottom: 16px;
}
-// 轮播图控件
.customArrowLeft,
.customArrowRight {
position: absolute;
top: 50%;
transform: translateY(-50%);
- width: 40px;
- height: 60px;
+ width: 44px;
+ height: 64px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
z-index: 10;
transition: all 0.3s ease;
- backdrop-filter: blur(4px);
+ border-radius: 8px;
+
+ // 深色半透明背景,确保在任何背景下都可见
+ background-color: rgba(0, 0, 0, 0.5);
+
+ // 添加白色外发光
+ box-shadow: 0 0 8px rgba(255, 255, 255, 0.3);
+
+ // 图标颜色设为白色
+ i,
+ .anticon {
+ color: #ffffff !important;
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
+ }
&:hover {
- background-color: rgba(0, 0, 0, 0.3);
- transform: translateY(-50%) scale(1.1);
+ background-color: rgba(0, 0, 0, 0.7);
+ transform: translateY(-50%) scale(1.05);
+ box-shadow: 0 0 12px rgba(255, 255, 255, 0.5);
+
+ i,
+ .anticon {
+ color: #ffffff !important;
+ transform: scale(1.1);
+ }
}
&:active {
- transform: translateY(-50%) scale(0.95);
+ transform: translateY(-50%) scale(0.98);
}
}
.customArrowLeft {
- left: 20px;
+ left: 16px;
+ border-radius: 0 8px 8px 0;
}
.customArrowRight {
- right: 20px;
+ right: 16px;
+ border-radius: 8px 0 0 8px;
}
.customDots {
@@ -691,19 +712,89 @@
white-space: nowrap;
}
- // 奇数行背景色
- .ant-table-tbody > tr:nth-child(odd) > td {
- background-color: #d4d5e3;
- }
-
- // 偶数行背景色
- .ant-table-tbody > tr:nth-child(even) > td {
- background-color: #d0cedc;
- }
-
// hover 效果
.ant-table-tbody > tr:hover > td {
background-color: #e6f7ff;
}
}
}
+
+// fullinter.less - 在文件末尾添加
+
+// 公告内容富文本样式
+.announcementContent {
+ font-size: 14px;
+ line-height: 1.6;
+ color: #333;
+
+ // 富文本内容样式
+ h1,
+ h2,
+ h3,
+ h4,
+ h5,
+ h6 {
+ margin: 10px 0;
+ font-weight: bold;
+ }
+
+ p {
+ margin: 8px 0;
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ }
+
+ ul,
+ ol {
+ padding-left: 20px;
+ margin: 8px 0;
+ }
+
+ li {
+ margin: 4px 0;
+ }
+
+ table {
+ border-collapse: collapse;
+ width: 100%;
+ margin: 8px 0;
+ }
+
+ th,
+ td {
+ border: 1px solid #ddd;
+ padding: 6px;
+ text-align: left;
+ }
+
+ th {
+ background-color: #f5f5f5;
+ }
+
+ strong,
+ b {
+ font-weight: bold;
+ }
+
+ em,
+ i {
+ font-style: italic;
+ }
+
+ u {
+ text-decoration: underline;
+ }
+
+ sub {
+ vertical-align: sub;
+ font-size: smaller;
+ }
+
+ sup {
+ vertical-align: super;
+ font-size: smaller;
+ }
+}
diff --git a/yarn.lock b/yarn.lock
index 6ec1f1e..5842eb0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10651,7 +10651,7 @@
"recompose" "^0.27.1"
"shallowequal" "^1.0.2"
-"react-dom@*", "react-dom@^0.14.0 || ^15.0.0 || ^16.0.0", "react-dom@^0.14.0 || ^15.0.0 || ^16.0.0-beta || ^16.0.0", "react-dom@^0.14.0 || ^15.0.0-0 || ^16.0.0", "react-dom@^0.14.0 || ^15.0.0-rc || ^16.0.0-rc || ^16.0.0", "react-dom@^0.14.0 || ^15.0.1 || ^16.0.0", "react-dom@^15.0.0 || ^16.0.0", "react-dom@^15.0.2 || ^16.0.0-rc || ^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^15.0.2|| ^16.0.0-rc || ^16.0.0", "react-dom@^16.0.0", "react-dom@^16.0.0-0", "react-dom@^16.3.0", "react-dom@^16.4.1", "react-dom@^16.6.3", "react-dom@^16.8.0", "react-dom@>=15.0.0", "react-dom@>=15.x", "react-dom@>=16.0.0", "react-dom@>=16.9.0", "react-dom@>0.14.5", "react-dom@0.14.x || 15.x || 16.x", "react-dom@15.x || ^16.0.0-0", "react-dom@16.8.2":
+"react-dom@*", "react-dom@^0.14.0 || ^15.0.0 || ^16.0.0", "react-dom@^0.14.0 || ^15.0.0 || ^16.0.0-beta || ^16.0.0", "react-dom@^0.14.0 || ^15.0.0-0 || ^16.0.0", "react-dom@^0.14.0 || ^15.0.0-rc || ^16.0.0-rc || ^16.0.0", "react-dom@^0.14.0 || ^15.0.1 || ^16.0.0", "react-dom@^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^15.0.0 || ^16.0.0", "react-dom@^15.0.2 || ^16.0.0-rc || ^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^15.0.2|| ^16.0.0-rc || ^16.0.0", "react-dom@^16.0.0", "react-dom@^16.0.0-0", "react-dom@^16.3.0", "react-dom@^16.4.1", "react-dom@^16.6.3", "react-dom@^16.8.0", "react-dom@>=15.0.0", "react-dom@>=15.x", "react-dom@>=16.0.0", "react-dom@>=16.9.0", "react-dom@>0.14.5", "react-dom@0.14.x || 15.x || 16.x", "react-dom@15.x || ^16.0.0-0", "react-dom@16.8.2":
"integrity" "sha512-cPGfgFfwi+VCZjk73buu14pYkYBR1b/SRMSYqkLDdhSEHnSwcuYTPu6/Bh6ZphJFIk80XLvbSe2azfcRzNF+Xg=="
"resolved" "https://registry.npmmirror.com/react-dom/-/react-dom-16.8.2.tgz"
"version" "16.8.2"
@@ -10789,9 +10789,19 @@
"prop-types" "^15.6.1"
"warning" "^4.0.1"
+"react-slick@^0.31.0":
+ "integrity" "sha512-zo6VLT8wuSBJffg/TFPbzrw2dEnfZ/cUKmYsKByh3AgatRv29m2LoFbq5vRMa3R3A4wp4d8gwbJKO2fWZFaI3g=="
+ "resolved" "https://registry.npmmirror.com/react-slick/-/react-slick-0.31.0.tgz"
+ "version" "0.31.0"
+ dependencies:
+ "classnames" "^2.2.5"
+ "json2mq" "^0.2.0"
+ "lodash.debounce" "^4.0.8"
+ "resize-observer-polyfill" "^1.5.0"
+
"react-slick@~0.25.2":
"integrity" "sha512-8MNH/NFX/R7zF6W/w+FS5VXNyDusF+XDW1OU0SzODEU7wqYB+ZTGAiNJ++zVNAVqCAHdyCybScaUB+FCZOmBBw=="
- "resolved" "https://registry.npmjs.org/react-slick/-/react-slick-0.25.2.tgz"
+ "resolved" "https://registry.npmmirror.com/react-slick/-/react-slick-0.25.2.tgz"
"version" "0.25.2"
dependencies:
"classnames" "^2.2.5"
@@ -10834,7 +10844,7 @@
"resolved" "https://registry.npmmirror.com/react-websocket/-/react-websocket-2.0.1.tgz"
"version" "2.0.1"
-"react@*", "react@^0.14 || ^15.0.0 || ^16.0.0-alpha", "react@^0.14.0 || ^15.0.0 || ^16.0.0", "react@^0.14.0 || ^15.0.0 || ^16.0.0-0", "react@^0.14.0 || ^15.0.0 || ^16.0.0-beta || ^16.0.0", "react@^0.14.0 || ^15.0.0-0 || ^16.0.0", "react@^0.14.0 || ^15.0.0-0 || ^16.0.0-0", "react@^0.14.0 || ^15.0.0-rc || ^16.0.0-rc || ^16.0.0", "react@^0.14.0 || ^15.0.1 || ^16.0.0", "react@^15.0.0 || ^16.0.0", "react@^15.0.2 || ^16.0.0-rc || ^16.0.0 || ^17.0.0 || ^18.0.0", "react@^15.0.2|| ^16.0.0-rc || ^16.0.0", "react@^16.0.0", "react@^16.0.0-0", "react@^16.3.0", "react@^16.4.1", "react@^16.6.3", "react@^16.8.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@>= 16.3", "react@>=0.13.2 || ^0.14 || ^15.0.0 || >=16.0.0", "react@>=15", "react@>=15.0.0", "react@>=15.x", "react@>=16.0.0", "react@>=16.9.0", "react@>0.14.5", "react@0.13.x || 0.14.x || ^15.0.0-0 || ^16.0.0-0", "react@0.14.x || 15.x || 16.x", "react@15.x || ^16.0.0-0", "react@16.8.2", "react@16.x":
+"react@*", "react@^0.14 || ^15.0.0 || ^16.0.0-alpha", "react@^0.14.0 || ^15.0.0 || ^16.0.0", "react@^0.14.0 || ^15.0.0 || ^16.0.0-0", "react@^0.14.0 || ^15.0.0 || ^16.0.0-beta || ^16.0.0", "react@^0.14.0 || ^15.0.0-0 || ^16.0.0", "react@^0.14.0 || ^15.0.0-0 || ^16.0.0-0", "react@^0.14.0 || ^15.0.0-rc || ^16.0.0-rc || ^16.0.0", "react@^0.14.0 || ^15.0.1 || ^16.0.0", "react@^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^15.0.0 || ^16.0.0", "react@^15.0.2 || ^16.0.0-rc || ^16.0.0 || ^17.0.0 || ^18.0.0", "react@^15.0.2|| ^16.0.0-rc || ^16.0.0", "react@^16.0.0", "react@^16.0.0-0", "react@^16.3.0", "react@^16.4.1", "react@^16.6.3", "react@^16.8.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@>= 16.3", "react@>=0.13.2 || ^0.14 || ^15.0.0 || >=16.0.0", "react@>=15", "react@>=15.0.0", "react@>=15.x", "react@>=16.0.0", "react@>=16.9.0", "react@>0.14.5", "react@0.13.x || 0.14.x || ^15.0.0-0 || ^16.0.0-0", "react@0.14.x || 15.x || 16.x", "react@15.x || ^16.0.0-0", "react@16.8.2", "react@16.x":
"integrity" "sha512-aB2ctx9uQ9vo09HVknqv3DGRpI7OIGJhCx3Bt0QqoRluEjHSaObJl+nG12GDdYH6sTgE7YiPJ6ZUyMx9kICdXw=="
"resolved" "https://registry.npmmirror.com/react/-/react-16.8.2.tgz"
"version" "16.8.2"