You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
836 lines
40 KiB
836 lines
40 KiB
import React, { useEffect, useState, useRef } from 'react';
|
|
import { connect } from 'react-redux';
|
|
import { Timeline, Card, Button, Modal, Form, Tooltip, Select, Radio, RadioGroup, Spin } from '@douyinfe/semi-ui';
|
|
import { push } from 'react-router-redux';
|
|
import { Setup, OutHidden } from "$components";
|
|
import ReactECharts from 'echarts-for-react';
|
|
import moment from "moment";
|
|
|
|
|
|
|
|
const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, socket, pepProjectId, statisticOnline, strucSeries }) => {
|
|
|
|
const { control, install, problem } = actions
|
|
const [setup, setSetup] = useState(false); //设置是否显现
|
|
const [tableType, setTableType] = useState(''); //localStorage存储名
|
|
const [tableSetup, setTableSetup] = useState([]); //单一表格设置信息
|
|
const [long, setLong] = useState(''); //最新动态设置
|
|
const [pomsList, setPomsList] = useState([]); //项目
|
|
const [faultId, setFaultId] = useState(''); //项目id 故障数统计
|
|
const [onlineId, setOnlineId] = useState(''); //项目id 数据在线率
|
|
const [setData, setSetData] = useState(); //设置总数
|
|
const [radioStatistics, setRadioStatistics] = useState('day'); //故障数统计(日,周,月)
|
|
const [radioRank, setRadioRank] = useState('day'); //故障数排名(日,周,月)
|
|
const [dataAlarm, setDataAlarm] = useState({}); //故障数统计--数据类
|
|
const [videoAlarm, setVideoAlarm] = useState({}); //故障故障数统计--视频
|
|
const [useAlarm, setUseAlarm] = useState({}); //故障故障数统计--应用
|
|
const [behind, setBehind] = useState(true); //故障数统计下钻
|
|
const [behindShow, setBehindShow] = useState([]); //故障数统计展示
|
|
const [videoData, setVideoData] = useState([]); //视频故障统计
|
|
const [datumData, setDatumData] = useState([]); //数据故障统计
|
|
const [useData, setUseData] = useState([]); //应用故障统计
|
|
const [rankData, setRankData] = useState([]); //故障排名
|
|
|
|
const [onlineStruc, setOnlineStruc] = useState([])
|
|
const [online, setOnline] = useState([])
|
|
const [value, setValue] = useState([])
|
|
|
|
const [successionId, setSuccessionId] = useState(''); //项目id 数据连续率
|
|
const [seriesStruc, setSeriesStruc] = useState([]) //连续率 结构物数据
|
|
const [series, setSeries] = useState([]) //连续率 数据
|
|
const [seriesValue, setSeriesValue] = useState([]) //连续率 结构物Id
|
|
const [sensorValue, setSensorValue] = useState([]) //连续率 测点Id
|
|
const [sensorList, setSensorList] = useState([]) //连续率 测点数数据
|
|
|
|
const [statisticsSpin, setStatisticsSpin] = useState(false) //故障数统计 加载中
|
|
const [rankSpin, setRankSpin] = useState(false) //故障数排名 加载中
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
if (projectPoms?.length > 0) {
|
|
let data = projectPoms?.filter(v => v.pepProjectIsDelete != 1)?.map(v => ({ value: v.id, label: v.pepProjectName || v.name }))
|
|
setPomsList(data)
|
|
}
|
|
}, [projectPoms])
|
|
|
|
useEffect(async () => {
|
|
if (projectPoms?.length > 0) {
|
|
let data = await getData('day', pepProjectId, true, true)
|
|
await getRank(data)
|
|
setRadioStatistics('day')
|
|
setRadioRank('day')
|
|
setFaultId('')
|
|
let ProjectId = pepProjectId ? (pepProjectId?.length > 0 ? pepProjectId.split(",")[0] : pepProjectId) : projectPoms[0]?.id
|
|
await getStatisticOnline(ProjectId) //始终获取一个项目的数据
|
|
await getStrucSeries(ProjectId) //始终获取一个项目的数据
|
|
|
|
if (pepProjectId) {
|
|
setPomsList(projectPoms?.filter(v => v.pepProjectIsDelete != 1 && ((pepProjectId?.length > 0 ? pepProjectId.split(",")?.map(p => Number(p)) : [pepProjectId]).includes(v.id)))?.map(v => ({ value: v.id, label: v.pepProjectName || v.name })))
|
|
if (!pepProjectId?.length > 0 || pepProjectId.split(",")?.length == 1) {
|
|
setFaultId(Number(pepProjectId))
|
|
}
|
|
} else {
|
|
setPomsList(projectPoms?.filter(v => v.pepProjectIsDelete != 1)?.map(v => ({ value: v.id, label: v.pepProjectName || v.name })))
|
|
}
|
|
|
|
}
|
|
}, [pepProjectId, projectPoms])
|
|
|
|
|
|
//数据在线率
|
|
const getStatisticOnline = async (id) => {
|
|
await dispatch(control.getStatisticOnline({ pepProjectId: id })).then(res => {
|
|
if (res.success) {
|
|
setOnlineId(Number(id))
|
|
let data = res.payload.data
|
|
setOnlineStruc(data?.map(v => ({ value: v.strucId, label: v.strucName })) || [])
|
|
setOnline(data?.slice(0, 10) || [])
|
|
setValue(data?.map(v => v.strucId)?.slice(0, 10) || [])
|
|
}
|
|
})
|
|
}
|
|
|
|
//数据连续率
|
|
const getStrucSeries = async (id) => {
|
|
await dispatch(control.getStrucSeries({ pepProjectId: id })).then(res => {
|
|
if (res.success) {
|
|
let data = res.payload.data
|
|
setSuccessionId(Number(id))
|
|
let struc = []
|
|
data?.forEach(f => {
|
|
if (!struc?.find(h => h.value == f.structure)) {
|
|
struc.push({ value: f.structure, label: f?.struc?.strucName })
|
|
}
|
|
})
|
|
setSeriesStruc(struc)
|
|
setSeriesValue(struc[0]?.value)
|
|
let findStruc = data?.filter(d => d.structure == struc[0]?.value)
|
|
setSeries(findStruc?.slice(0, 10) || [])
|
|
setSensorList(findStruc?.map(v => ({ value: v.id, label: v.name })) || [])
|
|
setSensorValue(findStruc?.map(v => v.id)?.slice(0, 10) || [])
|
|
}
|
|
})
|
|
}
|
|
|
|
|
|
|
|
const getRank = async (data) => {
|
|
let dataList = []
|
|
if (pepProjectId && (!pepProjectId?.length || pepProjectId.split(",")?.length == 1) || projectPoms?.legend == 1) {
|
|
|
|
data?.AlarmData?.filter(p => p.State < 3)?.forEach(s => {
|
|
let find = dataList?.find(a => a.StructureId == s.StructureId)
|
|
if (find) {
|
|
find.sum += 1
|
|
} else {
|
|
dataList.push({
|
|
StructureId: s.StructureId,
|
|
name: s.StructureName,
|
|
sum: 1
|
|
})
|
|
}
|
|
})
|
|
|
|
data?.AlarmVideo?.filter(p => !p.confirmTime)?.forEach(s => {
|
|
s?.struc?.forEach(f => {
|
|
let find = dataList?.find(a => a.id == s.StructureId)
|
|
if (find) {
|
|
find.sum += 1
|
|
} else {
|
|
dataList.push({
|
|
StructureId: f.id,
|
|
name: f.name,
|
|
sum: 1
|
|
})
|
|
}
|
|
})
|
|
})
|
|
|
|
} else {
|
|
projectPoms?.filter(v => v.pepProjectIsDelete != 1)?.forEach(d => {
|
|
let data1 = data?.AlarmData?.filter(v => v.pomsProject?.map(p => p.id)?.includes(d.id) && v.State < 3)?.length || 0
|
|
let data2 = data?.AlarmVideo?.filter(v => v.pomsProject?.map(p => p.id)?.includes(d.id) && !v.confirmTime)?.length || 0
|
|
dataList.push({
|
|
name: d.name || d.pepProjectName,
|
|
sum: data1 + data2
|
|
})
|
|
})
|
|
|
|
}
|
|
setRankData(dataList.sort((a, b) => b.sum - a.sum)?.slice(0, 5) || [])
|
|
}
|
|
|
|
const getData = async (radio, pepProjectId, diff1, diff2) => {
|
|
if (diff2) setStatisticsSpin(true)
|
|
if (diff1) setRankSpin(true)
|
|
let data = {}
|
|
await dispatch(control.getAlarmData({
|
|
pepProjectId: pepProjectId,
|
|
startTime: moment().startOf(radio).format('YYYY-MM-DD HH:mm:ss')
|
|
})).then((res) => {
|
|
if (res.success) {
|
|
if (diff1) {
|
|
data.AlarmData = res.payload.data || []
|
|
}
|
|
if (diff2) {
|
|
setDatumData(res.payload.data || [])
|
|
let group = {
|
|
group1: { sum: 0, untreated: 0 }, group2: { sum: 0, untreated: 0 }, group3: { sum: 0, untreated: 0 },
|
|
group4: { sum: 0, untreated: 0 }, group5: { sum: 0, untreated: 0 }
|
|
}
|
|
res.payload.data?.forEach(v => {
|
|
group['group' + v.AlarmGroup].sum += 1
|
|
if (v.State < 3) {
|
|
group['group' + v.AlarmGroup].untreated += 1
|
|
}
|
|
})
|
|
setDataAlarm(group)
|
|
}
|
|
}
|
|
})
|
|
|
|
|
|
|
|
await dispatch(problem.getAlarmVideoList({
|
|
pepProjectId: pepProjectId,
|
|
startTime: moment().startOf(radio).format('YYYY-MM-DD HH:mm:ss')
|
|
})).then((res) => {
|
|
if (res.success) {
|
|
if (diff1) {
|
|
data.AlarmVideo = res.payload.data || []
|
|
}
|
|
if (diff2) {
|
|
setVideoData(res.payload.data || [])
|
|
let alarmData = { sum: 0, untreated: 0 }
|
|
res.payload.data?.forEach(v => {
|
|
alarmData.sum += 1
|
|
if (!v.confirmTime) {
|
|
alarmData.untreated += 1
|
|
}
|
|
})
|
|
setVideoAlarm(alarmData)
|
|
}
|
|
|
|
}
|
|
})
|
|
|
|
if (diff2) {
|
|
await dispatch(control.getAlarmUse({
|
|
pepProjectId: pepProjectId,
|
|
startTime: moment().startOf(radio).format('YYYY-MM-DD HH:mm:ss')
|
|
})).then((res) => {
|
|
if (res.success) {
|
|
setUseData(res.payload.data || [])
|
|
let alarmData = { sum: 0, untreated: 0 }
|
|
res.payload.data?.forEach(v => {
|
|
alarmData.sum += 1
|
|
if (!v.confirmTime) {
|
|
alarmData.untreated += 1
|
|
}
|
|
})
|
|
setUseAlarm(alarmData)
|
|
}
|
|
})
|
|
}
|
|
setStatisticsSpin(false)
|
|
setRankSpin(false)
|
|
return data
|
|
}
|
|
|
|
|
|
const behindHandle = (key) => {
|
|
let show = []
|
|
switch (key) {
|
|
case '数据中断':
|
|
dispatch(problem.getAlarmDataGroup()).then((res) => {
|
|
if (res.success) {
|
|
let data = res.payload.data?.find(v => v.desc == '数据中断')?.unit || []
|
|
let sumData = datumData?.filter(s => s.AlarmGroup == 1) || []
|
|
data?.forEach(v => {
|
|
let dataList = sumData?.filter(s => s.AlarmGroupUnit == v.id) || []
|
|
let untreated = dataList?.filter(s => s.State < 3)?.length || 0
|
|
show.push({
|
|
name: v.name,
|
|
untreated: untreated,
|
|
processed: dataList?.length - untreated,
|
|
num: dataList?.length
|
|
})
|
|
})
|
|
setBehindShow(show.sort((a, b) => b.num - a.num)?.slice(0, 5) || [])
|
|
}
|
|
})
|
|
break;
|
|
case '数据异常':
|
|
dispatch(problem.getAlarmDataGroup()).then((res) => {
|
|
if (res.success) {
|
|
let data = res.payload.data?.find(v => v.desc == '数据异常')?.unit || []
|
|
let sumData = datumData?.filter(s => s.AlarmGroup == 2) || []
|
|
data?.forEach(v => {
|
|
let dataList = sumData?.filter(s => s.AlarmGroupUnit == v.id) || []
|
|
let untreated = dataList?.filter(s => s.State < 3)?.length || 0
|
|
show.push({
|
|
name: v.name,
|
|
untreated: untreated,
|
|
processed: dataList?.length - untreated,
|
|
num: dataList?.length
|
|
})
|
|
})
|
|
setBehindShow(show.sort((a, b) => b.num - a.num)?.slice(0, 5) || [])
|
|
}
|
|
})
|
|
break;
|
|
case '策略命中':
|
|
dispatch(problem.getAlarmDataGroup()).then((res) => {
|
|
if (res.success) {
|
|
let data = res.payload.data?.find(v => v.desc == '策略命中')?.unit || []
|
|
let sumData = datumData?.filter(s => s.AlarmGroup == 3) || []
|
|
data?.forEach(v => {
|
|
let dataList = sumData?.filter(s => s.AlarmGroupUnit == v.id) || []
|
|
let untreated = dataList?.filter(s => s.State < 3)?.length || 0
|
|
show.push({
|
|
name: v.name,
|
|
untreated: untreated,
|
|
processed: dataList?.length - untreated,
|
|
num: dataList?.length
|
|
})
|
|
})
|
|
setBehindShow(show.sort((a, b) => b.num - a.num)?.slice(0, 5) || [])
|
|
}
|
|
})
|
|
break;
|
|
case '视频异常':
|
|
dispatch(problem.getAlarmVideoExceptionType()).then((res) => {
|
|
if (res.success) {
|
|
res.payload.data?.forEach(v => {
|
|
let dataList = videoData?.filter(s => s.statusId == v.statusId) || []
|
|
let untreated = dataList?.filter(s => !s.confirmTime)?.length || 0
|
|
show.push({
|
|
name: v.describe,
|
|
untreated: untreated,
|
|
processed: dataList?.length - untreated,
|
|
num: dataList?.length
|
|
})
|
|
})
|
|
setBehindShow(show.sort((a, b) => b.num - a.num)?.slice(0, 5) || [])
|
|
}
|
|
})
|
|
|
|
setBehind(false)
|
|
|
|
break;
|
|
case '应用异常':
|
|
[{ name: '接口报错', value: 'apiError ' },
|
|
{ name: '加载超时', value: 'timeout' },
|
|
{ name: '元素异常', value: 'element' }].forEach(v => {
|
|
let dataList = useData?.filter(s => s.type == v.value) || []
|
|
let untreated = dataList?.filter(s => !s.confirmTime)?.length || 0
|
|
show.push({
|
|
name: v.name,
|
|
untreated: untreated,
|
|
processed: dataList?.length - untreated,
|
|
num: dataList?.length
|
|
})
|
|
})
|
|
setBehindShow(show.sort((a, b) => b.num - a.num)?.slice(0, 5) || [])
|
|
break;
|
|
case '设备异常':
|
|
dispatch(problem.getAlarmDataGroup()).then((res) => {
|
|
if (res.success) {
|
|
let data = res.payload.data?.find(v => v.desc == '掉线' || v.desc == '不活跃')?.unit || []
|
|
let sumData = datumData?.filter(s => s.AlarmGroup == 4 || s.AlarmGroup == 5) || []
|
|
data?.forEach(v => {
|
|
let dataList = sumData?.filter(s => s.AlarmGroupUnit == v.id) || []
|
|
let untreated = dataList?.filter(s => s.State < 3)?.length || 0
|
|
show.push({
|
|
name: v.name,
|
|
untreated: untreated,
|
|
processed: dataList?.length - untreated,
|
|
num: dataList?.length
|
|
})
|
|
})
|
|
setBehindShow(show.sort((a, b) => b.num - a.num)?.slice(0, 5) || [])
|
|
}
|
|
})
|
|
break;
|
|
}
|
|
setBehind(false)
|
|
}
|
|
|
|
|
|
return (<>
|
|
{/* 数据分析 */}
|
|
{
|
|
<div style={{ background: '#FFFFFF', boxShadow: '0px 0px 12px 2px rgba(220,222,224,0.2)', borderRadius: 2, paddingTop: 20, paddingLeft: 24, marginTop: 22 }}>
|
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
|
<div style={{ display: 'flex', alignItems: 'center' }}>
|
|
<div style={{ width: 0, height: 20, borderLeft: '3px solid #005ABD', borderTop: '3px solid transparent', borderBottom: '3px solid transparent' }}></div>
|
|
<div style={{ fontFamily: "YouSheBiaoTiHei", fontSize: 24, color: '#101531', marginLeft: 8 }}>数据分析</div>
|
|
<div style={{ marginLeft: 6, fontSize: 12, color: '#969799', fontFamily: "DINExp", }}>DATA ANALYSIS</div>
|
|
</div>
|
|
{/* <div style={{ marginRight: 25 }}>
|
|
<img title='设置' src="/assets/images/problem/setup.png" style={{ width: 18, height: 18, cursor: "pointer" }} onClick={() => {
|
|
setSetup(true)
|
|
setTableType('analyse')
|
|
attribute('analyse')
|
|
setSetData(10)
|
|
}} />
|
|
</div> */}
|
|
</div>
|
|
<div style={{ width: '100%', height: '100%', marginTop: 20 }}>
|
|
|
|
<div style={{ display: "flex" }}>
|
|
{/* 故障数统计 */}
|
|
<div style={{ padding: 16, width: '50%', height: 300 }}>
|
|
<Spin spinning={statisticsSpin} tip="数据加载中...">
|
|
{behind ?
|
|
<>
|
|
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
|
<div style={{ fontSize: 18, fontWeight: 'bold', color: "#0b0b0bbd" }}>故障数统计</div>
|
|
<div>
|
|
<Select showClear filter placeholder='项目' value={faultId} style={{ width: 160, marginRight: 10 }}
|
|
onChange={(v) => {
|
|
setFaultId(v)
|
|
getData(radioStatistics, v, false, true)
|
|
}}
|
|
optionList={pomsList}
|
|
/>
|
|
<RadioGroup type='button' buttonSize='middle' value={radioStatistics} style={{ marginRight: 10 }}
|
|
onChange={e => {
|
|
setRadioStatistics(e.target.value)
|
|
getData(e.target.value, pepProjectId, false, true)
|
|
}}
|
|
>
|
|
<Radio value="day">今日</Radio>
|
|
<Radio value="week">本周</Radio>
|
|
<Radio value="month">本月</Radio>
|
|
</RadioGroup>
|
|
</div>
|
|
</div>
|
|
<div style={{ display: 'flex', padding: 16, height: "100%" }}>
|
|
<div style={{ display: "flex", flexDirection: "column", justifyContent: "space-evenly", width: 180 }}>
|
|
<div style={{ display: 'flex', justifyContent: "space-between", cursor: 'pointer' }} onClick={() => behindHandle('数据中段')}>
|
|
<div>数据中断:</div>
|
|
<div style={{ fontWeight: 500 }}>
|
|
<sapn style={{ color: "red" }}>{dataAlarm?.group1?.untreated || 0}</sapn> /
|
|
<span style={{ color: "rgb(48 47 138)" }}>{dataAlarm?.group1?.sum || 0}</span>
|
|
</div>
|
|
</div>
|
|
<div style={{ display: 'flex', justifyContent: "space-between", cursor: 'pointer' }} onClick={() => behindHandle('数据异常')}>
|
|
<div>数据异常:</div>
|
|
<div style={{ fontWeight: 500 }}>
|
|
<sapn style={{ color: "red" }}>{dataAlarm?.group2?.untreated || 0}</sapn> /
|
|
<span style={{ color: "rgb(48 47 138)" }}>{dataAlarm?.group2?.sum || 0}</span>
|
|
</div>
|
|
</div>
|
|
<div style={{ display: 'flex', justifyContent: "space-between", cursor: 'pointer' }} onClick={() => behindHandle('策略命中')}>
|
|
<div>策略命中:</div>
|
|
<div style={{ fontWeight: 500 }}>
|
|
<sapn style={{ color: "red" }}>{dataAlarm?.group3?.untreated || 0}</sapn> /
|
|
<span style={{ color: "rgb(48 47 138)" }}>{dataAlarm?.group3?.sum || 0}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div style={{ display: 'flex', justifyContent: "space-between", cursor: 'pointer' }} onClick={() => behindHandle('视频异常')}>
|
|
<div>视频异常:</div>
|
|
<div style={{ fontWeight: 500 }}>
|
|
<sapn style={{ color: "red" }}>{videoAlarm?.untreated || 0}</sapn> /
|
|
<span style={{ color: "rgb(48 47 138)" }}>{videoAlarm?.sum || 0}</span>
|
|
</div>
|
|
</div>
|
|
<div style={{ display: 'flex', justifyContent: "space-between", cursor: 'pointer' }} onClick={() => behindHandle('应用异常')}>
|
|
<div>应用异常:</div>
|
|
<div style={{ fontWeight: 500 }}>
|
|
<sapn style={{ color: "red" }}>{useAlarm?.untreated || 0}</sapn> /
|
|
<span style={{ color: "rgb(48 47 138)" }}>{useAlarm?.sum || 0}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div style={{ display: 'flex', justifyContent: "space-between", cursor: 'pointer' }} onClick={() => behindHandle('设备异常')}>
|
|
<div>设备异常:</div>
|
|
<div style={{ fontWeight: 500 }}>
|
|
<sapn style={{ color: "red" }}>{(dataAlarm?.group4?.untreated || 0) + (dataAlarm?.group5?.untreated || 0)}</sapn> /
|
|
<span style={{ color: "rgb(48 47 138)" }}>{(dataAlarm?.group4?.sum || 0) + (dataAlarm?.group5?.sum || 0)}</span>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
<div style={{ width: 'calc(100% - 180px)', display: 'flex', justifyContent: 'center', alignItems: 'center', fontSize: 46, fontWeight: 600 }}>
|
|
<div style={{ fontWeight: 500 }}>
|
|
|
|
{(dataAlarm?.group1?.untreated || 0)
|
|
+ (dataAlarm?.group2?.untreated || 0)
|
|
+ (dataAlarm?.group3?.untreated || 0)
|
|
+ (dataAlarm?.group4?.untreated || 0)
|
|
+ (dataAlarm?.group5?.untreated || 0)
|
|
+ (videoAlarm?.untreated || 0)
|
|
+ (useAlarm?.untreated || 0)
|
|
}
|
|
/
|
|
{(dataAlarm?.group1?.sum || 0)
|
|
+ (dataAlarm?.group2?.sum || 0)
|
|
+ (dataAlarm?.group3?.sum || 0)
|
|
+ (dataAlarm?.group4?.sum || 0)
|
|
+ (dataAlarm?.group5?.sum || 0)
|
|
+ (videoAlarm?.sum || 0)
|
|
+ (useAlarm?.sum || 0)
|
|
}
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</>
|
|
: <div onClick={() => {
|
|
setBehindShow([])
|
|
setBehind(true)
|
|
}}>
|
|
<ReactECharts
|
|
option={{
|
|
title: {
|
|
text: '故障数统计',
|
|
},
|
|
grid: {
|
|
left: '10%',
|
|
// right: '4%',
|
|
// bottom: '3%',
|
|
// containLabel: true
|
|
},
|
|
// dataZoom: [
|
|
// {
|
|
// type: 'slider',
|
|
// // startValue: behindShow?.map(v => v.name) || []
|
|
// },
|
|
// {
|
|
// type: 'inside',
|
|
// },
|
|
// ],
|
|
tooltip: {
|
|
trigger: 'axis'
|
|
},
|
|
legend: {
|
|
data: ['未处理', '已处理'],
|
|
right: '10%',
|
|
},
|
|
xAxis: {
|
|
type: 'category',
|
|
// boundaryGap: false,
|
|
data: behindShow?.map(v => v.name) || []
|
|
},
|
|
yAxis: {
|
|
type: 'value',
|
|
name: "单位:条",
|
|
},
|
|
series: [
|
|
{
|
|
type: 'bar',
|
|
name: '未处理',
|
|
smooth: true,
|
|
itemStyle: { color: '#df4141', },
|
|
barWidth: 20,
|
|
data: behindShow?.map(v => v.untreated) || []
|
|
},
|
|
{
|
|
type: 'bar',
|
|
name: '已处理',
|
|
smooth: true,
|
|
itemStyle: { color: '#0ddf42', },
|
|
barWidth: 20,
|
|
data: behindShow?.map(v => v.processed) || []
|
|
},
|
|
|
|
]
|
|
}}
|
|
notMerge={true}
|
|
lazyUpdate={true}
|
|
// onChartReady={this.onChartReadyCallback}
|
|
// onEvents={EventsDict}
|
|
// opts={}
|
|
/>
|
|
</div>
|
|
}
|
|
</Spin>
|
|
|
|
</div>
|
|
{/* 故障数排名*/}
|
|
<div style={{ padding: 10, width: '50%', height: 300, position: "relative" }}>
|
|
<Spin spinning={rankSpin} tip="数据加载中...">
|
|
<RadioGroup type='button' buttonSize='middle' value={radioRank} style={{ marginRight: 10, zIndex: 10, position: "absolute", top: 8, left: 112 }}
|
|
onChange={async e => {
|
|
setRadioRank(e.target.value)
|
|
let data = await getData(e.target.value, pepProjectId, true, false)
|
|
await getRank(data)
|
|
}}
|
|
>
|
|
<Radio value="day">今日</Radio>
|
|
<Radio value="week">本周</Radio>
|
|
<Radio value="month">本月</Radio>
|
|
</RadioGroup>
|
|
<ReactECharts
|
|
option={{
|
|
title: {
|
|
text: '故障数排名',
|
|
},
|
|
grid: {
|
|
left: 70,
|
|
// right: '4%',
|
|
// bottom: '3%',
|
|
// containLabel: true
|
|
},
|
|
tooltip: {
|
|
trigger: 'axis',
|
|
formatter: function (params) {
|
|
// 自定义提示框内容
|
|
// console.log(params);
|
|
let title = rankData[params[0].dataIndex]?.name + '<br/>' + '<br/>' + params[0]?.seriesName + ":" + " " + " " + params[0]?.value
|
|
return title
|
|
}
|
|
},
|
|
legend: {
|
|
data: ['未处理故障数'],
|
|
right: '10%',
|
|
},
|
|
yAxis: {
|
|
type: 'category',
|
|
data: rankData?.map(v => {
|
|
if (v.name?.length > 4) {
|
|
return v.name?.slice(0, 4) + '...'
|
|
} else {
|
|
return v.name
|
|
}
|
|
}) || []
|
|
},
|
|
xAxis: {
|
|
type: 'value',
|
|
},
|
|
series: [
|
|
{
|
|
type: 'bar',
|
|
name: '未处理故障数',
|
|
smooth: true,
|
|
itemStyle: { color: '#0ddf42', },
|
|
barWidth: 20,
|
|
data: rankData?.map(v => v.sum) || []
|
|
},
|
|
|
|
]
|
|
}}
|
|
notMerge={true}
|
|
lazyUpdate={true}
|
|
// onChartReady={this.onChartReadyCallback}
|
|
// onEvents={EventsDict}
|
|
// opts={}
|
|
/>
|
|
</Spin>
|
|
|
|
</div>
|
|
</div>
|
|
<div style={{ display: "flex" }}>
|
|
{/* 数据在线率 */}
|
|
<div style={{ marginTop: 30, padding: 10, width: '50%', height: 350, position: "relative" }}>
|
|
<div style={{ zIndex: 10, position: "absolute", top: 8, left: 112, display: 'flex' }}>
|
|
<Select filter placeholder='项目' value={onlineId} style={{ width: 160, marginRight: 10 }}
|
|
onChange={(v) => {
|
|
getStatisticOnline(v)
|
|
}}
|
|
optionList={pomsList}
|
|
/>
|
|
<Select showClear
|
|
filter
|
|
placeholder='结构物'
|
|
value={value}
|
|
multiple={true}
|
|
maxTagCount={1}
|
|
style={{ width: 160, marginRight: 10 }}
|
|
optionList={onlineStruc}
|
|
onChange={v => {
|
|
setValue(v)
|
|
setOnline(statisticOnline?.filter(s => s.structure == v))
|
|
}}
|
|
/>
|
|
|
|
</div>
|
|
<ReactECharts
|
|
option={{
|
|
title: {
|
|
text: '数据在线率',
|
|
},
|
|
grid: {
|
|
left: 27,
|
|
right: 10,
|
|
bottom: 20,
|
|
},
|
|
tooltip: {
|
|
trigger: 'axis',
|
|
formatter: function (params) {
|
|
// 自定义提示框内容
|
|
// console.log(params);
|
|
let title = params[0].data[0] + '<br/>' + '<br/>'
|
|
params.forEach(v => {
|
|
let find = online?.find(s => s.strucName == v.seriesName)?.online?.find(d => moment(d.collect_time).format('YYYY-MM-DD HH') == v.data[0]) || {}
|
|
title = title + v.seriesName + ":" + " " + " " + v.data[1] + "%" + "(" + find?.online + "/" + find?.total + ")" + '<br/>'
|
|
})
|
|
return title
|
|
}
|
|
},
|
|
xAxis: {
|
|
type: 'time',
|
|
// name: "时间",
|
|
boundaryGap: false,
|
|
minInterval: 1000 * 60 * 60,
|
|
},
|
|
yAxis: {
|
|
type: 'value',
|
|
name: "单位%",
|
|
areaStyle: {
|
|
color: '#FFF',
|
|
},
|
|
},
|
|
series: online?.map(v => ({
|
|
type: 'line',
|
|
name: v.strucName,
|
|
smooth: true,
|
|
areaStyle: {
|
|
color: '#0e9cff26',
|
|
},
|
|
data: v.online?.map(f => [moment(f.collect_time).format('YYYY-MM-DD HH'), f.rate.toFixed(1)]) || []
|
|
})) || []
|
|
}}
|
|
notMerge={true}
|
|
lazyUpdate={true}
|
|
style={{ width: "100%", height: "100%" }}
|
|
/>
|
|
|
|
</div>
|
|
{/* 数据连续率 */}
|
|
<div style={{ marginTop: 30, padding: 10, width: '50%', height: 350, position: "relative" }}>
|
|
<div style={{ zIndex: 10, position: "absolute", top: 8, left: 112, display: 'flex' }}>
|
|
<Select filter placeholder='项目' value={successionId} style={{ width: 160, marginRight: 10 }}
|
|
onChange={(v) => {
|
|
getStrucSeries(v)
|
|
}}
|
|
optionList={pomsList}
|
|
/>
|
|
<Select
|
|
filter
|
|
placeholder='结构物'
|
|
value={seriesValue}
|
|
maxTagCount={1}
|
|
style={{ width: 160, marginRight: 10 }}
|
|
optionList={seriesStruc}
|
|
onChange={v => {
|
|
setSeriesValue(v)
|
|
let data = strucSeries?.filter(s => v == s.structure)
|
|
setSeries(data?.slice(0, 10) || [])
|
|
setSensorList(data?.map(v => ({ value: v.id, label: v.name })) || [])
|
|
setSensorValue(data?.slice(0, 10)?.map(d => d.id) || [])
|
|
}}
|
|
/>
|
|
<Select showClear
|
|
filter
|
|
placeholder='测点'
|
|
value={sensorValue}
|
|
multiple={true}
|
|
maxTagCount={1}
|
|
style={{ width: 160, marginRight: 10 }}
|
|
optionList={sensorList}
|
|
onChange={v => {
|
|
setSensorValue(v)
|
|
let data = strucSeries?.filter(s => (!v.length > 0 || v.includes(s.id)) && seriesValue == s.structure)
|
|
setSeries(data || [])
|
|
}}
|
|
/>
|
|
|
|
</div>
|
|
<ReactECharts
|
|
option={{
|
|
title: {
|
|
text: '数据连续率',
|
|
},
|
|
grid: {
|
|
left: 27,
|
|
right: 10,
|
|
bottom: 20,
|
|
},
|
|
tooltip: {
|
|
trigger: 'axis',
|
|
formatter: function (params) {
|
|
// 自定义提示框内容
|
|
let title = params[0]?.data[0] + '<br/>' + '<br/>'
|
|
params.forEach(v => {
|
|
let find = series?.find(s => s.name == v.seriesName) || {}
|
|
let findOne = find?.series?.find(d => moment(d.collect_time).format('YYYY-MM-DD HH') == v.data[0]) || {}
|
|
title = title + find?.name + ":" + " " + " " + v.data[1] * 100 + "%" + "(" + (findOne?.num || 0) + "/" + (findOne?.max || findOne?.num || 0) + ")" + '<br/>'
|
|
})
|
|
return title
|
|
}
|
|
},
|
|
xAxis: {
|
|
type: 'time',
|
|
// name: "时间",
|
|
boundaryGap: false,
|
|
minInterval: 1000 * 60 * 60,
|
|
},
|
|
yAxis: {
|
|
type: 'value',
|
|
name: "单位%",
|
|
areaStyle: {
|
|
color: '#FFF',
|
|
},
|
|
},
|
|
series: series?.map(v => ({
|
|
type: 'line',
|
|
name: v.name,
|
|
smooth: true,
|
|
areaStyle: {
|
|
color: '#0e9cff26',
|
|
},
|
|
data: v.series?.map(f => [moment(f.collect_time).format('YYYY-MM-DD HH'), Number(f.cont)]) || []
|
|
})) || []
|
|
}}
|
|
notMerge={true}
|
|
lazyUpdate={true}
|
|
style={{ width: "100%", height: "100%" }}
|
|
/>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
</div >}
|
|
|
|
{/* 设置弹窗 */}
|
|
{
|
|
setup && <Setup
|
|
tableType={tableType}
|
|
tableList={tableSetup}
|
|
layout={long}
|
|
data={setData}
|
|
close={() => {
|
|
setSetup(false);
|
|
attribute(tableType);
|
|
setTableType('')
|
|
setLong('')
|
|
}}
|
|
/>
|
|
}
|
|
</>
|
|
)
|
|
}
|
|
|
|
function mapStateToProps (state) {
|
|
const { auth, global, members, webSocket, ProjectPoms, statisticOnline, strucSeries } = state;
|
|
|
|
return {
|
|
user: auth.user,
|
|
actions: global.actions,
|
|
pepProjectId: global.pepProjectId,
|
|
socket: webSocket.socket,
|
|
projectPoms: ProjectPoms?.data?.rows,
|
|
statisticOnline: statisticOnline?.data || [],
|
|
strucSeries: strucSeries?.data || []
|
|
};
|
|
}
|
|
|
|
export default connect(mapStateToProps)(AlarmChart);
|
|
|