diff --git a/api/app/lib/controllers/alarm/video.js b/api/app/lib/controllers/alarm/video.js index 7fd42d8..6501066 100644 --- a/api/app/lib/controllers/alarm/video.js +++ b/api/app/lib/controllers/alarm/video.js @@ -138,6 +138,7 @@ async function alarmList (ctx) { cameraAlarm.cameraId AS cameraId, cameraAlarm.cameraName AS cameraName, cameraAlarm.cameraKindId AS cameraKindId, + cameraAlarm.statusId AS statusId, cameraAlarm.venderId AS venderId, cameraAlarm.venderName AS venderName, cameraAlarm.cameraSerialNo AS cameraSerialNo, @@ -257,6 +258,7 @@ async function alarmList (ctx) { let d = { cameraId: a.cameraId, cameraName: a.cameraName, + statusId: a.statusId, camerOnline: a.cameraOnline, cameraSerialNo: a.cameraSerialNo, cameraChannelNo: a.cameraChannelNo, diff --git a/api/app/lib/controllers/control/analysis.js b/api/app/lib/controllers/control/analysis.js index d2aa9f2..a6a2eaf 100644 --- a/api/app/lib/controllers/control/analysis.js +++ b/api/app/lib/controllers/control/analysis.js @@ -757,26 +757,26 @@ async function getStrucSeries (ctx) { index: strucSeriesClient.config.index, type: strucSeriesClient.config.type, body: { - // "query": { - // "bool": { - // "filter": [ - // { - // "range": { - // "collect_time": { - // "gte": `${moment().subtract(32, 'hours').format('YYYY-MM-DDTHH:mm:ss.SSS')}Z`, - // // "gte": "2023-08-24T08:00:00.000Z", - // } - // } - // }, - // { - // "terms": { - // "structure": anxinStrucIds, - // // "structure": [1, 2, 3] - // } - // } - // ] - // } - // }, + "query": { + "bool": { + "filter": [ + { + "range": { + "collect_time": { + "gte": `${moment().subtract(32, 'hours').format('YYYY-MM-DDTHH:mm:ss.SSS')}Z`, + // "gte": "2023-08-24T08:00:00.000Z", + } + } + }, + { + "terms": { + "structure": anxinStrucIds, + // "structure": [1, 2, 3] + } + } + ] + } + }, "sort": [ { "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 = seriesRes.hits.hits - .filter((h) => h._source.structure == struc.strucId) - // .sort((a, b) => { - // return a._source.collect_time - b._source.collect_time - // }) + .filter((h) => h._source.sensor == data.id) .map(s => { return { ...s._source, } }) - struc.series = curSeries + let struc = anxinStruc.find((h) => h.strucId == data.structure) + data.series = curSeries + data.struc = struc } ctx.status = 200; - ctx.body = anxinStruc; + ctx.body = sensor; } else { ctx.status = 200; ctx.body = []; diff --git a/web/client/src/sections/control/components/alarm-chart.js b/web/client/src/sections/control/components/alarm-chart.js index 6153b42..d1dfd9d 100644 --- a/web/client/src/sections/control/components/alarm-chart.js +++ b/web/client/src/sections/control/components/alarm-chart.js @@ -1,6 +1,6 @@ import React, { useEffect, useState, useRef } from 'react'; 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 { Setup, OutHidden } from "$components"; import ReactECharts from 'echarts-for-react'; @@ -19,7 +19,6 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so const [pomsList, setPomsList] = useState([]); //项目 const [faultId, setFaultId] = useState(''); //项目id 故障数统计 const [onlineId, setOnlineId] = useState(''); //项目id 数据在线率 - const [successionId, setSuccessionId] = useState(''); //项目id 数据连续率 const [setData, setSetData] = useState(); //设置总数 const [radioStatistics, setRadioStatistics] = 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 [value, setValue] = useState([]) - const [seriesStruc, setSeriesStruc] = useState([]) - const [series, setSeries] = useState([]) - const [seriesValue, setSeriesValue] = 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) //故障数排名 加载中 + @@ -52,43 +58,49 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so useEffect(async () => { if (projectPoms?.length > 0) { - let data = await getData('day', pepProjectId, true, true) - await getRank(data) - setRadioStatistics('day') - setRadioRank('day') - 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 }))) + let data = await getData('day', pepProjectId, true, true) + await getRank(data) + setRadioStatistics('day') + setRadioRank('day') + setFaultId('') + + await dispatch(control.getStatisticOnline({ pepProjectId: pepProjectId })).then(res => { + if (res.success) { + setOnlineId('') + 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) || []) } - } - }, [pepProjectId, projectPoms]) + }) + await dispatch(control.getStrucSeries({ pepProjectId: pepProjectId })).then(res => { + if (res.success) { + setSuccessionId('') + 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) || []) + setSensorList(data?.map(v => ({ value: v.id, label: v.name })) || []) + setSensorValue(data?.map(v => v.id)?.slice(0, 10) || []) + } + }) - useEffect(() => { - setOnlineId('') - dispatch(control.getStatisticOnline({ pepProjectId: onlineId || pepProjectId })).then(res => { - if (res.success) { - let data = res.payload.data?.filter(s => !onlineId || s.pomsProject?.map(p => p.id)?.includes(onlineId)) - setOnlineStruc(data?.map(v => ({ value: v.strucId, label: v.strucName })) || []) - setOnline(data?.slice(0, 10) || []) - setValue(data?.map(v => v.strucId)?.slice(0, 10) || []) + 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 }))) } - }) - }, [onlineId, pepProjectId]) - useEffect(() => { - setSuccessionId('') - dispatch(control.getStrucSeries({ pepProjectId: successionId || pepProjectId })).then(res => { - if (res.success) { - let data = res.payload.data?.filter(s => !successionId || s.pomsProject?.map(p => p.id)?.includes(successionId)) - setSeriesStruc(data?.map(v => ({ value: v.strucId, label: v.strucName })) || []) - setSeries(data?.slice(0, 10) || []) - setSeriesValue(data?.map(v => v.strucId)?.slice(0, 10) || []) - } - }) - }, [successionId, pepProjectId]) + } + }, [pepProjectId, projectPoms]) + + const getRank = async (data) => { let dataList = [] @@ -137,6 +149,8 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so } const getData = async (radio, pepProjectId, diff1, diff2) => { + if (diff2) setStatisticsSpin(true) + if (diff1) setRankSpin(true) let data = {} await dispatch(control.getAlarmData({ pepProjectId: pepProjectId, @@ -206,7 +220,8 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so } }) } - + setStatisticsSpin(false) + setRankSpin(false) return data } @@ -214,7 +229,7 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so const behindHandle = (key) => { let show = [] switch (key) { - case '数据中段': + case '数据中断': dispatch(problem.getAlarmDataGroup()).then((res) => { if (res.success) { let data = res.payload.data?.find(v => v.desc == '数据中断')?.unit || [] @@ -354,228 +369,246 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so
{/* 故障数统计 */}
- {behind ? - <> -
-
故障数统计
-
- { + setFaultId(v) + getData(radioStatistics, v, false, true) + }} + optionList={pomsList} + /> + { + setRadioStatistics(e.target.value) + getData(e.target.value, pepProjectId, false, true) + }} + > + 今日 + 本周 + 本月 + +
-
-
-
-
behindHandle('数据中段')}> -
数据中段:
-
- {dataAlarm?.group1?.untreated || 0} / - {dataAlarm?.group1?.sum || 0} +
+
+
behindHandle('数据中段')}> +
数据中断:
+
+ {dataAlarm?.group1?.untreated || 0} / + {dataAlarm?.group1?.sum || 0} +
-
-
behindHandle('数据异常')}> -
数据异常:
-
- {dataAlarm?.group2?.untreated || 0} / - {dataAlarm?.group2?.sum || 0} +
behindHandle('数据异常')}> +
数据异常:
+
+ {dataAlarm?.group2?.untreated || 0} / + {dataAlarm?.group2?.sum || 0} +
-
-
behindHandle('策略命中')}> -
策略命中:
-
- {dataAlarm?.group3?.untreated || 0} / - {dataAlarm?.group3?.sum || 0} +
behindHandle('策略命中')}> +
策略命中:
+
+ {dataAlarm?.group3?.untreated || 0} / + {dataAlarm?.group3?.sum || 0} +
-
-
behindHandle('视频异常')}> -
视频异常:
-
- {videoAlarm?.untreated || 0} / - {videoAlarm?.sum || 0} +
behindHandle('视频异常')}> +
视频异常:
+
+ {videoAlarm?.untreated || 0} / + {videoAlarm?.sum || 0} +
-
-
behindHandle('应用异常')}> -
应用异常:
-
- {useAlarm?.untreated || 0} / - {useAlarm?.sum || 0} +
behindHandle('应用异常')}> +
应用异常:
+
+ {useAlarm?.untreated || 0} / + {useAlarm?.sum || 0} +
-
-
behindHandle('设备异常')}> -
设备异常:
-
- {(dataAlarm?.group4?.untreated || 0) + (dataAlarm?.group5?.untreated || 0)} / - {(dataAlarm?.group4?.sum || 0) + (dataAlarm?.group5?.sum || 0)} +
behindHandle('设备异常')}> +
设备异常:
+
+ {(dataAlarm?.group4?.untreated || 0) + (dataAlarm?.group5?.untreated || 0)} / + {(dataAlarm?.group4?.sum || 0) + (dataAlarm?.group5?.sum || 0)} +
+
+
+
-
-
-
- - {(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) - } + {(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) + } +
-
- - :
{ - setBehindShow([]) - setBehind(true) - }}> - 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) || [] + + :
{ + setBehindShow([]) + setBehind(true) + }}> + v.name) || [] + // }, + // { + // type: 'inside', + // }, + // ], + tooltip: { + trigger: 'axis' }, - { - type: 'bar', - name: '已处理', - smooth: true, - itemStyle: { color: '#0ddf42', }, - barWidth: 20, - data: behindShow?.map(v => v.processed) || [] + 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={} + /> +
+ } + - ] - }} - notMerge={true} - lazyUpdate={true} - // onChartReady={this.onChartReadyCallback} - // onEvents={EventsDict} - // opts={} - /> -
- }
{/* 故障数排名*/}
- { - setRadioRank(e.target.value) - let data = await getData(e.target.value, pepProjectId, true, false) - await getRank(data) - }} - > - 今日 - 本周 - 本月 - - v.name) || [] - }, - xAxis: { - type: 'value', - }, - series: [ - { - type: 'bar', - name: '故障数', - smooth: true, - itemStyle: { color: '#0ddf42', }, - barWidth: 20, - data: rankData?.map(v => v.sum) || [] + + { + setRadioRank(e.target.value) + let data = await getData(e.target.value, pepProjectId, true, false) + await getRank(data) + }} + > + 今日 + 本周 + 本月 + + ' + '
' + 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={} + /> +
- ] - }} - notMerge={true} - lazyUpdate={true} - // onChartReady={this.onChartReadyCallback} - // onEvents={EventsDict} - // opts={} - />
@@ -585,6 +618,10 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so { 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} /> @@ -674,8 +723,24 @@ const AlarmChart = ({ dispatch, actions, user, history, projectPoms, loading, so optionList={seriesStruc} onChange={v => { setSeriesValue(v) - let data = strucSeries?.filter(s => !onlineId || s.pomsProject?.map(p => p.id)?.includes(onlineId)) - setSeries(data?.filter(s => v.includes(s.strucId))) + let data = strucSeries?.filter(s => (!v.length > 0 || v.includes(s.structure)) && (!successionId || s.pomsProject?.map(p => p.id)?.includes(successionId))) + 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) || []) + }} + /> +