From e8a6d6059cbaaf83e4000e2ba7f361d61fc0ae6c Mon Sep 17 00:00:00 2001 From: wuqun Date: Wed, 8 Mar 2023 17:29:59 +0800 Subject: [PATCH] =?UTF-8?q?(*)=E9=A6=96=E9=A1=B5=E5=9B=BE=E8=A1=A8=20?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=9A=82=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/alarm/alarmStatistics.js | 62 +++++++ .../components/alarm/autorollcomponent.js | 138 +++++++++++++++ .../shouye/components/charts/column.js | 80 +++++++++ .../shouye/components/charts/stackColumn.js | 107 ++++++++++++ .../shouye/components/charts/xColumn.js | 85 ++++++++++ .../src/sections/shouye/containers/shouye.js | 158 +++++++++++------- web/client/src/sections/shouye/style.less | 16 ++ 7 files changed, 590 insertions(+), 56 deletions(-) create mode 100644 web/client/src/sections/shouye/components/alarm/alarmStatistics.js create mode 100644 web/client/src/sections/shouye/components/alarm/autorollcomponent.js create mode 100644 web/client/src/sections/shouye/components/charts/column.js create mode 100644 web/client/src/sections/shouye/components/charts/stackColumn.js create mode 100644 web/client/src/sections/shouye/components/charts/xColumn.js diff --git a/web/client/src/sections/shouye/components/alarm/alarmStatistics.js b/web/client/src/sections/shouye/components/alarm/alarmStatistics.js new file mode 100644 index 0000000..a58b125 --- /dev/null +++ b/web/client/src/sections/shouye/components/alarm/alarmStatistics.js @@ -0,0 +1,62 @@ +'use strict' +import React, { Component } from 'react'; +import { Row, Col, Tooltip } from 'antd'; +import AutoRollComponent from './autorollcomponent'; +class AlarmStatistics extends Component { + constructor(props) { + super(props); + this.state = { + workers: { + wTypePieData: [ + { item: '点位1', count: 214 }, + { item: '点位2', count: 135 }, + { item: '点位3', count: 88 }, + { item: '点位4', count: 63 }, + { item: '点位5', count: 56 }, + { item: '点位6', count: 115 }, + { item: '点位7', count: 67 }, + { item: '点位8', count: 144 }, + { item: '点位9', count: 21 }, + { item: '点位10', count: 83 }, + ] + } + } + } + + render() { + const { height } = this.props; + const { workers } = this.state; + let max = null, content = null; + let data = workers.wTypePieData.sort((a, b) => b.count - a.count); + max = data[0].count; + content =
+ { + workers.wTypePieData.map((wd, i) => { + let cls = i < 3 ? 'alarm-row rank1' : 'alarm-row rank2'; + return + No.{i + 1} + {wd.item} + {wd.count}次 + + }) + } +
+ return ( +
+
+ 告警统计 +
+
+ { + content ? + :
+ 暂无数据 +
+ } +
+
+ ); + } +} + +export default AlarmStatistics; \ No newline at end of file diff --git a/web/client/src/sections/shouye/components/alarm/autorollcomponent.js b/web/client/src/sections/shouye/components/alarm/autorollcomponent.js new file mode 100644 index 0000000..8393743 --- /dev/null +++ b/web/client/src/sections/shouye/components/alarm/autorollcomponent.js @@ -0,0 +1,138 @@ +'use strict' +import React, { Component } from 'react'; +import { Row, Col } from 'antd'; + +export default class AutoRollComponent extends Component { + + constructor(props) { + super(props); + this.scrollElem = null; + this.stopscroll = false; + this.preTop = 0; + this.cloneEle = null; + this.currentTop = 0; + this.marqueesHeight = 0; + this.interval = null; + this.state = { + enabledScroll: false + } + } + + get enabledScroll() { + let scrollElem = document.getElementById(this.props.divId); + let fatherElem = scrollElem?.parentNode || null; + if (scrollElem && fatherElem) { + return scrollElem.scrollHeight > fatherElem.scrollHeight + } + + return false; + } + + + marque = (height) => { + try { + this.scrollElem = document.getElementById(this.props.divId); + this.marqueesHeight = height; + if (this.scrollElem) { + this.scrollElem.style.height = this.marqueesHeight; + this.scrollElem.style.overflow = 'hidden'; + } + this.repeat(); + } catch (e) { console.log(e) } + } + + + repeat = () => { + this.scrollElem.scrollTop = 0; + + this.interval = setInterval(() => { + if (this.stopscroll) return; + this.currentTop = this.currentTop + 1; + this.preTop = this.scrollElem.scrollTop; + this.scrollElem.scrollTop = this.scrollElem.scrollTop + 1; + // console.log(`this.scrollElem.scrollTop:${this.scrollElem.scrollTop} === this.preTop:${this.preTop}`); + if (this.preTop === this.scrollElem.scrollTop) { + this.scrollElem.scrollTop = this.marqueesHeight; + this.scrollElem.scrollTop = this.scrollElem.scrollTop + 1; + } + }, 80); + } + + + componentWillUnmount() { + clearInterval(this.interval); + } + + componentWillReceiveProps(nextProps) { + requestAnimationFrame(() => { + if (this.enabledScroll) { + if (!this.state.enabledScroll) { + this.setState({ enabledScroll: true }, () => { + this.marque(10) + }) + } + + } + }) + } + + componentDidMount() { + if (this.enabledScroll) { + this.setState({ enabledScroll: true }, () => { + this.marque(10) + }) + } + } + + onMouseOver = () => { + this.stopscroll = true; + } + + onMouseOut = () => { + this.stopscroll = false; + } + + + render() { + + const { headStyle = headStyle || {}, changeStyleCol, heads, spans, data, divId, divHeight, content, containerStyle = {} } = this.props; + + return ( +
+ { + heads ? + + {heads.map((c, index) => { + return {c} + }) + } + : '' + } + +
+
+ {content ? content : ''} + {this.state.enabledScroll && content ? content : ''} + { + data ? + data.map((q, idx) => { + return ( +
+ + {heads.map((c, index) => { + return + {index == 1 ? q.data[index] == -1 ? "-" : q.data[index] : index == 2 ? q.data[1] == -1 ? '-' : q.data[index] : q.data[index]} + }) + } + +
+ ) + }) : '' + } +
+
+
+
+ ) + } +} \ No newline at end of file diff --git a/web/client/src/sections/shouye/components/charts/column.js b/web/client/src/sections/shouye/components/charts/column.js new file mode 100644 index 0000000..0e011f5 --- /dev/null +++ b/web/client/src/sections/shouye/components/charts/column.js @@ -0,0 +1,80 @@ +import React, { Component } from 'react'; +import * as echarts from 'echarts'; +class ColumnChart extends Component { + constructor(props) { + super(props); + this.state = { + }; + } + componentDidMount() { + const { xAxis, datas, domId } = this.props; + this.createCharts(xAxis, datas, domId); + } + + componentWillReceiveProps(nextProps) { + let { xAxis, datas, domId } = nextProps; + if (JSON.stringify(xAxis) != JSON.stringify(this.props.xAxis) || JSON.stringify(datas) != JSON.stringify(this.props.datas)) { + this.createCharts(xAxis, datas, domId); + } + } + + createCharts = (xAxis, datas, domId) => { + this.clearEchart(); + let chartDom = document.getElementById(domId); + this.chart = echarts.init(chartDom); + let option = this.getOption(xAxis, datas); + this.chart.setOption(option); + this.onSize = () => { + this.chart.resize(); + } + window.addEventListener("resize", this.onSize); + }; + // 组件销毁删除监听 + componentWillUnmount() { + window.removeEventListener("resize", this.onSize) + } + clearEchart = () => { + if (this.chart) { + this.chart.dispose(); + } + }; + + getOption = (xAxis, datas) => { + const { unit } = this.props + let option = { + title: { + text: '成本分析' + }, + legend: {}, + grid: { + left: '3%', + right: '10%', + bottom: '0%', + containLabel: true + }, + xAxis: { + type: 'category', + data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] + }, + yAxis: { + type: 'value', + name: '单位:万元', + }, + tooltip: {}, + series: [ + { + data: [120, 200, 150, 80, 70, 110, 130], + type: 'bar' + } + ] + } + return option; + }; + + render() { + const { domId, width, height } = this.props; + return
; + } +} + +export default ColumnChart; \ No newline at end of file diff --git a/web/client/src/sections/shouye/components/charts/stackColumn.js b/web/client/src/sections/shouye/components/charts/stackColumn.js new file mode 100644 index 0000000..34cc0e3 --- /dev/null +++ b/web/client/src/sections/shouye/components/charts/stackColumn.js @@ -0,0 +1,107 @@ +import React, { Component } from 'react'; +import * as echarts from 'echarts'; +class StackColumn extends Component { + constructor(props) { + super(props); + this.state = { + }; + } + componentDidMount() { + const { xAxis, datas, domId } = this.props; + this.createCharts(xAxis, datas, domId); + } + + componentWillReceiveProps(nextProps) { + let { xAxis, datas, domId } = nextProps; + if (JSON.stringify(xAxis) != JSON.stringify(this.props.xAxis) || JSON.stringify(datas) != JSON.stringify(this.props.datas)) { + this.createCharts(xAxis, datas, domId); + } + } + + createCharts = (xAxis, datas, domId) => { + this.clearEchart(); + let chartDom = document.getElementById(domId); + this.chart = echarts.init(chartDom); + let option = this.getOption(xAxis, datas); + this.chart.setOption(option); + this.onSize = () => { + this.chart.resize(); + } + window.addEventListener("resize", this.onSize); + }; + // 组件销毁删除监听 + componentWillUnmount() { + window.removeEventListener("resize", this.onSize) + } + clearEchart = () => { + if (this.chart) { + this.chart.dispose(); + } + }; + + getOption = (xAxis, datas) => { + let xAxisData = []; + let data1 = []; + let data2 = []; + for (let i = 0; i < 10; i++) { + xAxisData.push('Class' + i); + data1.push(+(Math.random() * 2).toFixed(2)); + data2.push(+(Math.random() * 5).toFixed(2)); + } + let emphasisStyle = { + itemStyle: { + shadowBlur: 10, + shadowColor: 'rgba(0,0,0,0.3)' + } + }; + let option = { + title: { + text: '设备维修分析' + }, + legend: { + data: ['异常数', '维修数'], + left: '40%' + }, + tooltip: {}, + xAxis: { + data: xAxisData, + axisLine: { onZero: true }, + splitLine: { show: false }, + splitArea: { show: false } + }, + yAxis: { + name: '单位:次数', + }, + grid: { + left: '3%', + right: '10%', + bottom: '0%', + containLabel: true + }, + series: [ + { + name: '异常数', + type: 'bar', + stack: 'one', + emphasis: emphasisStyle, + data: data1 + }, + { + name: '维修数', + type: 'bar', + stack: 'one', + emphasis: emphasisStyle, + data: data2 + } + ] + } + return option; + }; + + render() { + const { domId, width, height } = this.props; + return
; + } +} + +export default StackColumn; \ No newline at end of file diff --git a/web/client/src/sections/shouye/components/charts/xColumn.js b/web/client/src/sections/shouye/components/charts/xColumn.js new file mode 100644 index 0000000..5627d9a --- /dev/null +++ b/web/client/src/sections/shouye/components/charts/xColumn.js @@ -0,0 +1,85 @@ +import React, { Component } from 'react'; +import * as echarts from 'echarts'; +class XColumn extends Component { + constructor(props) { + super(props); + this.state = { + }; + } + componentDidMount() { + const { xAxis, yAxis, domId } = this.props; + this.createCharts(xAxis, yAxis, domId); + } + + componentWillReceiveProps(nextProps) { + let { xAxis, yAxis, domId } = nextProps; + if (JSON.stringify(xAxis) != JSON.stringify(this.props.xAxis) || JSON.stringify(yAxis) != JSON.stringify(this.props.yAxis)) { + this.createCharts(xAxis, yAxis, domId); + } + } + + createCharts = (xAxis, yAxis, domId) => { + this.clearEchart(); + let chartDom = document.getElementById(domId); + this.chart = echarts.init(chartDom); + let option = this.getOption(xAxis, yAxis); + this.chart.setOption(option); + this.onSize = () => { + this.chart.resize(); + } + window.addEventListener("resize", this.onSize); + }; + // 组件销毁删除监听 + componentWillUnmount() { + window.removeEventListener("resize", this.onSize) + } + clearEchart = () => { + if (this.chart) { + this.chart.dispose(); + } + }; + + getOption = (xAxis, yAxis) => { + let option = { + title: { + text: '故障点位分析' + }, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow' + } + }, + legend: {}, + grid: { + left: '3%', + right: '10%', + bottom: '0%', + containLabel: true + }, + xAxis: { + type: 'value', + boundaryGap: [0, 0.01] + }, + yAxis: { + type: 'category', + data: yAxis + }, + series: [ + { + name: '异常数', + type: 'bar', + data: xAxis + } + ] + }; + return option; + }; + + render() { + const { domId, width, height } = this.props; + return
; + } +} + +export default XColumn; \ No newline at end of file diff --git a/web/client/src/sections/shouye/containers/shouye.js b/web/client/src/sections/shouye/containers/shouye.js index a0499c0..1863a2d 100644 --- a/web/client/src/sections/shouye/containers/shouye.js +++ b/web/client/src/sections/shouye/containers/shouye.js @@ -5,89 +5,135 @@ import moment from "moment"; import '../style.less'; import { push } from 'react-router-redux'; import { Model } from 'echarts'; -import {getPatrolPlan} from '../../patrolManage/actions/plan' +import { getPatrolPlan } from '../../patrolManage/actions/plan' +import XColumn from '../components/charts/xColumn' +import StackColumn from '../components/charts/stackColumn' +import AlarmStatistics from '../components/alarm/alarmStatistics' +import Column from '../components/charts/column' const Information = (props) => { - const { dispatch, actions, user, loading } = props + const { dispatch, actions, user, loading, clientHeight } = props const { patrolManage, issueHandle } = actions - const [planedata,setplandata] = useState([]) - const [xunjiandata,setxunjiandata] = useState([]) - const [shijiandata,setshijiandata] = useState([]) - const topdata =[] + const [planedata, setplandata] = useState([]) + const [xunjiandata, setxunjiandata] = useState([]) + const [shijiandata, setshijiandata] = useState([]) + + const [chartData1, setChartData1] = useState([]) + const [chartData2, setChartData2] = useState([]) + const [chartData3, setChartData3] = useState([]) + const [chartData4, setChartData4] = useState([]) + + const topdata = [] const format = 'YYYY-MM-DD HH:mm:ss' const times = [moment().subtract(70, 'years').format(format), moment().format(format)] - useEffect(()=>{ - dispatch(getPatrolPlan()).then(async (res)=>{ - const res2 = await dispatch(patrolManage.records(`patrolRecord/all/${times[0]}/${times[1]}/null/null`)) - console.log(res2,'res2') - setshijiandata(res2?.payload?.data) - setxunjiandata(res2?.payload?.data.filter(i=>parseInt(moment().format('YYYYMMDD'))=== parseInt(moment(i.inspectionTime ).format('YYYYMMDD')))) - const count = res?.payload?.data?.rows?.filter(i=>{ - // console.log(i?.frequency?.match(/^[0-9]*$/),'jjj') - if(i?.frequency.split('/')[i?.frequency.split('/').length-1]==='天'){ - // console.log(i?.frequency?.match(/[\d.]/g).join(''),'jjj') - return parseInt(moment().format('YYYYMMDD'))<=parseInt(moment(i.endTime).format('YYYYMMDD')) - // console.log('是的',i?.frequency.split('/')[i?.frequency.split('/').length-1]) - }else if(i?.frequency.split('/')[i?.frequency.split('/').length-1]==='周'){ - // console.log(i?.frequency?.match(/^[0-9]*$/),'jjj') - return parseInt(moment().format('YYYYMMDD'))<=parseInt(moment(i.endTime).format('YYYYMMDD'))&&res2?.payload?.data?.filter(j=>j.patrolPlanId===i.id - &&moment(j.inspectionTim).week()===moment().week()).length { + dispatch(getPatrolPlan()).then(async (res) => { + const res2 = await dispatch(patrolManage.records(`patrolRecord/all/${times[0]}/${times[1]}/null/null`)) + setshijiandata(res2?.payload?.data) + setxunjiandata(res2?.payload?.data.filter(i => parseInt(moment().format('YYYYMMDD')) === parseInt(moment(i.inspectionTime).format('YYYYMMDD')))) + const count = res?.payload?.data?.rows?.filter(i => { + if (i?.frequency.split('/')[i?.frequency.split('/').length - 1] === '天') { + return parseInt(moment().format('YYYYMMDD')) <= parseInt(moment(i.endTime).format('YYYYMMDD')) + } else if (i?.frequency.split('/')[i?.frequency.split('/').length - 1] === '周') { + return parseInt(moment().format('YYYYMMDD')) <= parseInt(moment(i.endTime).format('YYYYMMDD')) && res2?.payload?.data?.filter(j => j.patrolPlanId === i.id + && moment(j.inspectionTim).week() === moment().week()).length < parseInt(i?.frequency?.match(/[\d.]/g).join('')) } - else if(i?.frequency.split('/')[i?.frequency.split('/').length-1]==='月'){ - // console.log(i?.frequency?.match(/^[0-9]*$/),'jjj') - return parseInt(moment().format('YYYYMMDD'))<=parseInt(moment(i.endTime).format('YYYYMMDD'))&&res2?.payload?.data?.filter(j=>j.patrolPlanId===i.id - &&moment(j.inspectionTim).month()===moment().month()).length j.patrolPlanId === i.id + && moment(j.inspectionTim).month() === moment().month()).length < parseInt(i?.frequency?.match(/[\d.]/g).join('')) } }) - console.log(count,'count') setplandata(count) - console.log(res,'res') + + + calcChartData(res2?.payload?.data) + }) + }, []) + + + const calcChartData = (data) => { + let arr = [] + data.filter(d => d.alarm).forEach(l => { + let ext = arr.find(a => a.name === l.point.name); + if (ext) { + ext.value++; + } else { + arr.push({ name: l.point.name, value: 1 }) + } }) - },[]) - console.log(xunjiandata,'xunjiandata') + arr.sort((a, b) => b.value - a.value) + setChartData1(arr.slice(0, 10));//展示前10名 + } return ( <> -
-
-
-
今日巡检
-
{planedata.length}
+
+
+
+
今日巡检
+
{planedata.length}
+
+
+
完成巡检:{xunjiandata.length}个
+
巡检上报:{xunjiandata.filter(i => i?.alarm === true).length}个
+
-
-
完成巡检:{xunjiandata.length}个
-
巡检上报:{xunjiandata.filter(i=>i?.alarm===true).length}个
+
+
+
今日事件
+
{xunjiandata.filter(i => i?.alarm === true).length}
+
+
+
已处理:个
+
未处理:2个
+
-
-
-
-
今日事件
-
{xunjiandata.filter(i=>i?.alarm===true).length}
-
-
-
已处理:个
-
未处理:2个
+
+
+
今日预警
+
0
+
+
+
已下发:2个
+
-
-
-
今日预警
-
0
+ +
+
+ cd.value).reverse()} + yAxis={chartData1.map(cd => cd.name).reverse()} /> +
+
+ +
-
-
已下发:2个
+
+
+ +
+
+ +
-
-
+ ) } -function mapStateToProps (state) { +function mapStateToProps(state) { const { auth, global } = state; return { user: auth.user, actions: global.actions, + clientHeight: global.clientHeight }; } diff --git a/web/client/src/sections/shouye/style.less b/web/client/src/sections/shouye/style.less index bea32e1..f70cc49 100644 --- a/web/client/src/sections/shouye/style.less +++ b/web/client/src/sections/shouye/style.less @@ -25,4 +25,20 @@ font-size: 1.5625rem; } } +} +.shouye-chart-card { + margin: 0 1.875rem; + margin-top: 20px; +} +.alarm-row { + background-repeat: no-repeat; + background-size: 100% 100%; + padding: 0px 14px 0px 8px; + color: #fff; +} +.rank1 { + background-image: url('/assets/images/homePage/rank1.png'); +} +.rank2 { + background-image: url('/assets/images/homePage/rank2.png'); } \ No newline at end of file