Browse Source

控制台bug优化

dev
wenlele 1 year ago
parent
commit
bbf5a3546a
  1. 2
      api/app/lib/controllers/alarm/video.js
  2. 63
      api/app/lib/controllers/control/analysis.js
  3. 147
      web/client/src/sections/control/components/alarm-chart.js
  4. 2
      web/client/src/sections/control/containers/control.jsx

2
api/app/lib/controllers/alarm/video.js

@ -138,6 +138,7 @@ async function alarmList (ctx) {
cameraAlarm.cameraId AS cameraId, cameraAlarm.cameraId AS cameraId,
cameraAlarm.cameraName AS cameraName, cameraAlarm.cameraName AS cameraName,
cameraAlarm.cameraKindId AS cameraKindId, cameraAlarm.cameraKindId AS cameraKindId,
cameraAlarm.statusId AS statusId,
cameraAlarm.venderId AS venderId, cameraAlarm.venderId AS venderId,
cameraAlarm.venderName AS venderName, cameraAlarm.venderName AS venderName,
cameraAlarm.cameraSerialNo AS cameraSerialNo, cameraAlarm.cameraSerialNo AS cameraSerialNo,
@ -257,6 +258,7 @@ async function alarmList (ctx) {
let d = { let d = {
cameraId: a.cameraId, cameraId: a.cameraId,
cameraName: a.cameraName, cameraName: a.cameraName,
statusId: a.statusId,
camerOnline: a.cameraOnline, camerOnline: a.cameraOnline,
cameraSerialNo: a.cameraSerialNo, cameraSerialNo: a.cameraSerialNo,
cameraChannelNo: a.cameraChannelNo, cameraChannelNo: a.cameraChannelNo,

63
api/app/lib/controllers/control/analysis.js

@ -757,26 +757,26 @@ async function getStrucSeries (ctx) {
index: strucSeriesClient.config.index, index: strucSeriesClient.config.index,
type: strucSeriesClient.config.type, type: strucSeriesClient.config.type,
body: { body: {
// "query": { "query": {
// "bool": { "bool": {
// "filter": [ "filter": [
// { {
// "range": { "range": {
// "collect_time": { "collect_time": {
// "gte": `${moment().subtract(32, 'hours').format('YYYY-MM-DDTHH:mm:ss.SSS')}Z`, "gte": `${moment().subtract(32, 'hours').format('YYYY-MM-DDTHH:mm:ss.SSS')}Z`,
// // "gte": "2023-08-24T08:00:00.000Z", // "gte": "2023-08-24T08:00:00.000Z",
// } }
// } }
// }, },
// { {
// "terms": { "terms": {
// "structure": anxinStrucIds, "structure": anxinStrucIds,
// // "structure": [1, 2, 3] // "structure": [1, 2, 3]
// } }
// } }
// ] ]
// } }
// }, },
"sort": [ "sort": [
{ {
"collect_time": { "collect_time": {
@ -793,23 +793,32 @@ async function getStrucSeries (ctx) {
} }
} }
for (let struc of anxinStruc) { const sensor = anxinStrucIds.length ? await clickHouse.anxinyun.query(
`SELECT
id,structure,name
FROM t_sensor
INNER JOIN t_structure
ON t_structure.id = t_sensor.structure
WHERE
t_sensor.structure IN (${anxinStrucIds.join(',')})`
).toPromise() : []
for (let data of sensor) {
let curSeries = let curSeries =
seriesRes.hits.hits seriesRes.hits.hits
.filter((h) => h._source.structure == struc.strucId) .filter((h) => h._source.sensor == data.id)
// .sort((a, b) => {
// return a._source.collect_time - b._source.collect_time
// })
.map(s => { .map(s => {
return { return {
...s._source, ...s._source,
} }
}) })
struc.series = curSeries let struc = anxinStruc.find((h) => h.strucId == data.structure)
data.series = curSeries
data.struc = struc
} }
ctx.status = 200; ctx.status = 200;
ctx.body = anxinStruc; ctx.body = sensor;
} else { } else {
ctx.status = 200; ctx.status = 200;
ctx.body = []; ctx.body = [];

147
web/client/src/sections/control/components/alarm-chart.js

@ -1,6 +1,6 @@
import React, { useEffect, useState, useRef } from 'react'; import React, { useEffect, useState, useRef } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Timeline, Card, Button, Modal, Form, Tooltip, Select, Radio, RadioGroup } from '@douyinfe/semi-ui'; import { Timeline, Card, Button, Modal, Form, Tooltip, Select, Radio, RadioGroup, Spin } from '@douyinfe/semi-ui';
import { push } from 'react-router-redux'; import { push } from 'react-router-redux';
import { Setup, OutHidden } from "$components"; import { Setup, OutHidden } from "$components";
import ReactECharts from 'echarts-for-react'; import ReactECharts from 'echarts-for-react';
@ -19,7 +19,6 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
const [pomsList, setPomsList] = useState([]); //项目 const [pomsList, setPomsList] = useState([]); //项目
const [faultId, setFaultId] = useState(''); //项目id 故障数统计 const [faultId, setFaultId] = useState(''); //项目id 故障数统计
const [onlineId, setOnlineId] = useState(''); //项目id 数据在线率 const [onlineId, setOnlineId] = useState(''); //项目id 数据在线率
const [successionId, setSuccessionId] = useState(''); //项目id 数据连续率
const [setData, setSetData] = useState(); //设置总数 const [setData, setSetData] = useState(); //设置总数
const [radioStatistics, setRadioStatistics] = useState('day'); //故障数统计(日,周,月) const [radioStatistics, setRadioStatistics] = useState('day'); //故障数统计(日,周,月)
const [radioRank, setRadioRank] = useState('day'); //故障数排名(日,周,月) const [radioRank, setRadioRank] = useState('day'); //故障数排名(日,周,月)
@ -37,9 +36,16 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
const [online, setOnline] = useState([]) const [online, setOnline] = useState([])
const [value, setValue] = useState([]) const [value, setValue] = useState([])
const [seriesStruc, setSeriesStruc] = useState([]) const [successionId, setSuccessionId] = useState(''); //项目id 数据连续率
const [series, setSeries] = useState([]) const [seriesStruc, setSeriesStruc] = useState([]) //连续率 结构物数据
const [seriesValue, setSeriesValue] = 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) //故障数排名 加载中
@ -57,38 +63,44 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
setRadioStatistics('day') setRadioStatistics('day')
setRadioRank('day') setRadioRank('day')
setFaultId('') setFaultId('')
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 })))
} else {
setPomsList(projectPoms?.filter(v => v.pepProjectIsDelete != 1)?.map(v => ({ value: v.id, label: v.pepProjectName || v.name })))
}
}
}, [pepProjectId, projectPoms])
useEffect(() => { await dispatch(control.getStatisticOnline({ pepProjectId: pepProjectId })).then(res => {
setOnlineId('')
dispatch(control.getStatisticOnline({ pepProjectId: onlineId || pepProjectId })).then(res => {
if (res.success) { if (res.success) {
let data = res.payload.data?.filter(s => !onlineId || s.pomsProject?.map(p => p.id)?.includes(onlineId)) setOnlineId('')
let data = res.payload.data
setOnlineStruc(data?.map(v => ({ value: v.strucId, label: v.strucName })) || []) setOnlineStruc(data?.map(v => ({ value: v.strucId, label: v.strucName })) || [])
setOnline(data?.slice(0, 10) || []) setOnline(data?.slice(0, 10) || [])
setValue(data?.map(v => v.strucId)?.slice(0, 10) || []) setValue(data?.map(v => v.strucId)?.slice(0, 10) || [])
} }
}) })
}, [onlineId, pepProjectId])
useEffect(() => { await dispatch(control.getStrucSeries({ pepProjectId: pepProjectId })).then(res => {
setSuccessionId('')
dispatch(control.getStrucSeries({ pepProjectId: successionId || pepProjectId })).then(res => {
if (res.success) { if (res.success) {
let data = res.payload.data?.filter(s => !successionId || s.pomsProject?.map(p => p.id)?.includes(successionId)) setSuccessionId('')
setSeriesStruc(data?.map(v => ({ value: v.strucId, label: v.strucName })) || []) setSeriesValue('')
let data = res.payload.data?.filter(s => !successionId || s?.struc?.pomsProject?.map(p => p.id)?.includes(successionId))
setSeriesStruc(data?.map(v => ({ value: v.id, label: v.name })) || [])
setSeries(data?.slice(0, 10) || []) setSeries(data?.slice(0, 10) || [])
setSeriesValue(data?.map(v => v.strucId)?.slice(0, 10) || []) setSensorList(data?.map(v => ({ value: v.id, label: v.name })) || [])
setSensorValue(data?.map(v => v.id)?.slice(0, 10) || [])
} }
}) })
}, [successionId, pepProjectId])
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))
setOnlineId(Number(pepProjectId))
setSuccessionId(Number(pepProjectId))
}
} else {
setPomsList(projectPoms?.filter(v => v.pepProjectIsDelete != 1)?.map(v => ({ value: v.id, label: v.pepProjectName || v.name })))
}
}
}, [pepProjectId, projectPoms])
const getRank = async (data) => { const getRank = async (data) => {
let dataList = [] let dataList = []
@ -137,6 +149,8 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
} }
const getData = async (radio, pepProjectId, diff1, diff2) => { const getData = async (radio, pepProjectId, diff1, diff2) => {
if (diff2) setStatisticsSpin(true)
if (diff1) setRankSpin(true)
let data = {} let data = {}
await dispatch(control.getAlarmData({ await dispatch(control.getAlarmData({
pepProjectId: pepProjectId, pepProjectId: pepProjectId,
@ -206,7 +220,8 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
} }
}) })
} }
setStatisticsSpin(false)
setRankSpin(false)
return data return data
} }
@ -214,7 +229,7 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
const behindHandle = (key) => { const behindHandle = (key) => {
let show = [] let show = []
switch (key) { switch (key) {
case '数据中': case '数据中':
dispatch(problem.getAlarmDataGroup()).then((res) => { dispatch(problem.getAlarmDataGroup()).then((res) => {
if (res.success) { if (res.success) {
let data = res.payload.data?.find(v => v.desc == '数据中断')?.unit || [] let data = res.payload.data?.find(v => v.desc == '数据中断')?.unit || []
@ -354,6 +369,7 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
<div style={{ display: "flex" }}> <div style={{ display: "flex" }}>
{/* 故障数统计 */} {/* 故障数统计 */}
<div style={{ padding: 16, width: '50%', height: 300 }}> <div style={{ padding: 16, width: '50%', height: 300 }}>
<Spin spinning={statisticsSpin} tip="数据加载中...">
{behind ? {behind ?
<> <>
<div style={{ display: "flex", justifyContent: "space-between" }}> <div style={{ display: "flex", justifyContent: "space-between" }}>
@ -381,7 +397,7 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
<div style={{ display: 'flex', padding: 16, height: "100%" }}> <div style={{ display: 'flex', padding: 16, height: "100%" }}>
<div style={{ display: "flex", flexDirection: "column", justifyContent: "space-evenly", width: 180 }}> <div style={{ display: "flex", flexDirection: "column", justifyContent: "space-evenly", width: 180 }}>
<div style={{ display: 'flex', justifyContent: "space-between", cursor: 'pointer' }} onClick={() => behindHandle('数据中段')}> <div style={{ display: 'flex', justifyContent: "space-between", cursor: 'pointer' }} onClick={() => behindHandle('数据中段')}>
<div>数据中</div> <div>数据中</div>
<div style={{ fontWeight: 500 }}> <div style={{ fontWeight: 500 }}>
<sapn style={{ color: "red" }}>{dataAlarm?.group1?.untreated || 0}</sapn> / <sapn style={{ color: "red" }}>{dataAlarm?.group1?.untreated || 0}</sapn> /
<span style={{ color: "rgb(48 47 138)" }}>{dataAlarm?.group1?.sum || 0}</span> <span style={{ color: "rgb(48 47 138)" }}>{dataAlarm?.group1?.sum || 0}</span>
@ -519,9 +535,12 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
/> />
</div> </div>
} }
</Spin>
</div> </div>
{/* 故障数排名*/} {/* 故障数排名*/}
<div style={{ padding: 10, width: '50%', height: 300, position: "relative" }}> <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 }} <RadioGroup type='button' buttonSize='middle' value={radioRank} style={{ marginRight: 10, zIndex: 10, position: "absolute", top: 8, left: 112 }}
onChange={async e => { onChange={async e => {
setRadioRank(e.target.value) setRadioRank(e.target.value)
@ -539,21 +558,33 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
text: '故障数排名', text: '故障数排名',
}, },
grid: { grid: {
left: '10%', left: 70,
// right: '4%', // right: '4%',
// bottom: '3%', // bottom: '3%',
// containLabel: true // containLabel: true
}, },
tooltip: { tooltip: {
trigger: 'axis' trigger: 'axis',
formatter: function (params) {
// 自定义提示框内容
// console.log(params);
let title = rankData[params[0].dataIndex]?.name + '<br/>' + '<br/>' + params[0]?.seriesName + ":" + "&nbsp" + "&nbsp" + params[0]?.value
return title
}
}, },
legend: { legend: {
data: ['故障数'], data: ['未处理故障数'],
right: '10%', right: '10%',
}, },
yAxis: { yAxis: {
type: 'category', type: 'category',
data: rankData?.map(v => v.name) || [] data: rankData?.map(v => {
if (v.name?.length > 4) {
return v.name?.slice(0, 4) + '...'
} else {
return v.name
}
}) || []
}, },
xAxis: { xAxis: {
type: 'value', type: 'value',
@ -561,7 +592,7 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
series: [ series: [
{ {
type: 'bar', type: 'bar',
name: '故障数', name: '未处理故障数',
smooth: true, smooth: true,
itemStyle: { color: '#0ddf42', }, itemStyle: { color: '#0ddf42', },
barWidth: 20, barWidth: 20,
@ -576,6 +607,8 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
// onEvents={EventsDict} // onEvents={EventsDict}
// opts={} // opts={}
/> />
</Spin>
</div> </div>
</div> </div>
<div style={{ display: "flex" }}> <div style={{ display: "flex" }}>
@ -585,6 +618,10 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
<Select filter showClear placeholder='项目' value={onlineId} style={{ width: 160, marginRight: 10 }} <Select filter showClear placeholder='项目' value={onlineId} style={{ width: 160, marginRight: 10 }}
onChange={(v) => { onChange={(v) => {
setOnlineId(v) setOnlineId(v)
let data = statisticOnline?.filter(s => !v || s.pomsProject?.map(p => p.id)?.includes(v))
setOnlineStruc(data?.map(v => ({ value: v.strucId, label: v.strucName })) || [])
setOnline(data?.slice(0, 10) || [])
setValue(data?.map(v => v.strucId)?.slice(0, 10) || [])
}} }}
optionList={pomsList} optionList={pomsList}
/> />
@ -661,6 +698,18 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
<Select filter showClear placeholder='项目' value={successionId} style={{ width: 160, marginRight: 10 }} <Select filter showClear placeholder='项目' value={successionId} style={{ width: 160, marginRight: 10 }}
onChange={(v) => { onChange={(v) => {
setSuccessionId(v) setSuccessionId(v)
setSeriesValue('')
let data = strucSeries?.filter(s => !v || s?.struc?.pomsProject?.map(p => p.id)?.includes(v))
let struc = []
data?.forEach(f => {
if (!struc?.find(h => h.value == f.structure)) {
struc.push({ value: f.structure, label: f?.struc?.strucName })
}
})
setSeriesStruc(struc)
setSeries(data?.slice(0, 10) || [])
setSensorList(data?.slice(0, 10)?.map(v => ({ value: v.id, label: v.name })) || [])
setSensorValue(data?.slice(0, 10)?.map(d => d.id) || [])
}} }}
optionList={pomsList} optionList={pomsList}
/> />
@ -674,8 +723,24 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
optionList={seriesStruc} optionList={seriesStruc}
onChange={v => { onChange={v => {
setSeriesValue(v) setSeriesValue(v)
let data = strucSeries?.filter(s => !onlineId || s.pomsProject?.map(p => p.id)?.includes(onlineId)) let data = strucSeries?.filter(s => (!v.length > 0 || v.includes(s.structure)) && (!successionId || s.pomsProject?.map(p => p.id)?.includes(successionId)))
setSeries(data?.filter(s => v.includes(s.strucId))) setSeries(data?.slice(0, 10) || [])
setSensorList(data?.slice(0, 10)?.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?.length > 0 || seriesValue?.includes(s.structure)) && (!successionId || s.pomsProject?.map(p => p.id)?.includes(successionId)))
setSeries(data || [])
}} }}
/> />
@ -683,7 +748,7 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
<ReactECharts <ReactECharts
option={{ option={{
title: { title: {
text: '数据在线率', text: '数据连续率',
}, },
grid: { grid: {
left: 27, left: 27,
@ -694,11 +759,11 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
trigger: 'axis', trigger: 'axis',
formatter: function (params) { formatter: function (params) {
// 自定义提示框内容 // 自定义提示框内容
// console.log(params); let title = params[0]?.data[0] + '<br/>' + '<br/>'
let title = params[0].data[0] + '<br/>' + '<br/>'
params.forEach(v => { params.forEach(v => {
let find = series?.find(s => s.strucName == v.seriesName)?.series?.find(d => moment(d.collect_time).format('YYYY-MM-DD HH') == v.data[0]) || {} let find = series?.find(s => s.name == v.seriesName) || {}
title = title + v.seriesName + ":" + "&nbsp" + "&nbsp" + v.data[1] + "%" + "(" + find?.num + "/" + find?.tTotal + ")" + '<br/>' let findOne = find?.series?.find(d => moment(d.collect_time).format('YYYY-MM-DD HH') == v.data[0]) || {}
title = title + find?.name + ":" + "&nbsp" + "&nbsp" + v.data[1] * 100 + "%" + "(" + findOne?.tTotal + "/" + (findOne?.num || findOne?.tTotal) + ")" + '<br/>'
}) })
return title return title
} }
@ -718,7 +783,7 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
}, },
series: series?.map(v => ({ series: series?.map(v => ({
type: 'line', type: 'line',
name: v.strucName, name: v.name,
smooth: true, smooth: true,
areaStyle: { areaStyle: {
color: '#0e9cff26', color: '#0e9cff26',

2
web/client/src/sections/control/containers/control.jsx

@ -620,7 +620,7 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
dynamic: ['discovery', 'notice', 'handle', 'confirm'], dynamic: ['discovery', 'notice', 'handle', 'confirm'],
} }
let show = { let show = {
overall: ['workbench', 'statistical', 'dataAnalyse'], overall: ['workbench', 'dataAnalyse'],
workbench: ['project', 'data', 'app', 'device'], workbench: ['project', 'data', 'app', 'device'],
statistical: ['milestone', 'personnel', 'web', 'problem'], statistical: ['milestone', 'personnel', 'web', 'problem'],
analyse: ['dataInterrupt', 'dataAbnormal', 'policyHit', 'videoException', 'appAbnormal', 'deviceAbnormal', 'problemAnalysis'], analyse: ['dataInterrupt', 'dataAbnormal', 'policyHit', 'videoException', 'appAbnormal', 'deviceAbnormal', 'problemAnalysis'],

Loading…
Cancel
Save