Browse Source

控制台优化

dev
wenlele 1 year ago
parent
commit
01d2876085
  1. 6
      api/app/lib/controllers/alarm/video.js
  2. 426
      api/app/lib/controllers/control/analysis.js
  3. 2
      api/app/lib/controllers/control/data.js
  4. 14
      api/app/lib/routes/control/index.js
  5. 10
      api/config.js
  6. 4
      web/client/src/components/setup.jsx
  7. 40
      web/client/src/index.less
  8. 48
      web/client/src/sections/control/actions/control.js
  9. 774
      web/client/src/sections/control/components/alarm-chart.js
  10. 87
      web/client/src/sections/control/containers/control.jsx
  11. 25
      web/client/src/utils/webapi.js

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

@ -81,7 +81,7 @@ async function alarmList (ctx) {
const { clickHouse } = ctx.app.fs
const { utils: { judgeSuper, anxinStrucIdRange } } = ctx.app.fs
const { database: anxinyun } = clickHouse.anxinyun.opts.config
const { pepProjectId, keywordTarget, keyword, state, kindId, sustainTimeStart, sustainTimeEnd, limit, page, statusId, toExport } = ctx.query
const { pepProjectId, keywordTarget, keyword, state, kindId, sustainTimeStart, sustainTimeEnd, limit, page, statusId, toExport, startTime } = ctx.query
let anxinStruc = await anxinStrucIdRange({
ctx, pepProjectId, keywordTarget, keyword
@ -107,6 +107,7 @@ async function alarmList (ctx) {
cameraWhereOption.push(sql)
}
let statusAlarmWhereOption = []
if (sustainTimeStart && sustainTimeEnd) {
let momentStart = moment(sustainTimeStart).format('YYYY-MM-DD HH:mm:ss')
@ -128,6 +129,9 @@ async function alarmList (ctx) {
if (statusId) {
statusAlarmWhereOption.push(`camera_status_alarm.status_id = ${statusId}`)
}
if (startTime) {
statusAlarmWhereOption.push(`camera_status_alarm.create_time >= '${moment(startTime).format('YYYY-MM-DD HH:mm:ss')}'`)
}
const queryStr = `
SELECT

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

@ -405,8 +405,432 @@ async function problem (ctx) {
}
}
async function getAlarmData (ctx) {
try {
const { models } = ctx.fs.dc;
const { clickHouse } = ctx.app.fs
const { utils: { judgeSuper, anxinStrucIdRange } } = ctx.app.fs
const { database: anxinyun } = clickHouse.anxinyun.opts.config
const { pepProjectId, startTime } = ctx.query
let anxinStruc = await anxinStrucIdRange({ ctx, pepProjectId })
let whereOption = []
if (anxinStruc.length) {
const anxinStrucIds = anxinStruc.map(a => a.strucId)
whereOption.push(`alarms.StructureId IN (${anxinStrucIds.join(",")})`)
if (startTime) {
whereOption.push(`alarms.StartTime >= '${moment(startTime).format('YYYY-MM-DD HH:mm:ss')}'`)
}
const alarmRes = await clickHouse.dataAlarm.query(`
SELECT
alarm.alarms.State AS State,
SourceName, StartTime, EndTime,AlarmGroup,AlarmGroupUnit,
alarms.StructureId AS StructureId,
${anxinyun}.t_structure.name AS StructureName
FROM
alarms
LEFT JOIN ${anxinyun}.t_structure
ON ${anxinyun}.t_structure.id = alarms.StructureId
${whereOption.length ? 'WHERE ' + whereOption.join(' AND ') : ''}
`).toPromise();
alarmRes.forEach(ar => {
ar.pomsProject = (
anxinStruc.find(as => as.strucId == ar.StructureId) ||
{
pomsProject: [
// TODO: 开发临时添加
]
}
).pomsProject
})
ctx.status = 200;
ctx.body = alarmRes
} else {
ctx.body = []
}
ctx.status = 200;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function getAlarmVideo (ctx) {
try {
const { models } = ctx.fs.dc;
const { clickHouse } = ctx.app.fs
const { utils: { judgeSuper, anxinStrucIdRange } } = ctx.app.fs
const { database: anxinyun } = clickHouse.anxinyun.opts.config
const { pepProjectId, startTime } = ctx.query
let anxinStruc = await anxinStrucIdRange({ ctx, pepProjectId })
const anxinStrucIds = anxinStruc.map(a => a.strucId)
let statusAlarmWhereOption = []
if (startTime) {
statusAlarmWhereOption.push(`camera_status_alarm.create_time >= '${moment(startTime).format('YYYY-MM-DD HH:mm:ss')}'`)
}
const queryStr = `
SELECT
cameraAlarm.cameraId AS cameraId,
cameraAlarm.venderId AS venderId,
cameraAlarm.cameraSerialNo AS cameraSerialNo,
cameraAlarm.cameraChannelNo AS cameraChannelNo,
cameraAlarm.alarmId AS alarmId,
cameraAlarm.statusId AS statusId,
cameraAlarm.createTime AS createTime,
cameraAlarm.updateTime AS updateTime,
cameraAlarm.platform AS platform,
cameraAlarm.confirmContent AS confirmContent,
cameraAlarm.confirmTime AS confirmTime,
${'cameraAlarm.autoRestore AS autoRestore,'}
camera_status_resolve.id AS resolveId,
camera_status.describe AS statusDescribe,
camera_status_resolve.resolve AS resolve,
"gbCamera".online AS cameraOnline,
secret_yingshi.token AS yingshiToken,
anxinIpc.t_video_ipc.name AS anxinIpcPosition,
anxinStation.id AS anxinStationId,
anxinStation.name AS anxinStationName,
anxinStruc.name AS strucName,
anxinStruc.id AS strucId
FROM
(
SELECT
camera.id AS cameraId,
camera.gb_id AS gbId,
camera.vender_id AS venderId,
camera.yingshi_secret_id AS yingshiSecretId,
camera_status_alarm.id AS alarmId,
camera_status_alarm.create_time AS createTime,
camera_status_alarm.update_time AS updateTime,
camera_status_alarm.platform AS platform,
camera_status_alarm.status_id AS statusId,
camera_status_alarm.serial_no AS cameraSerialNo,
camera_status_alarm.channel_no AS cameraChannelNo,
camera_status_alarm.confirm AS confirmContent,
${'camera_status_alarm.auto_restore AS autoRestore,'}
camera_status_alarm.confirm_time AS confirmTime
FROM camera_status_alarm
INNER JOIN camera
ON camera.serial_no = camera_status_alarm.serial_no
AND camera.channel_no = camera_status_alarm.channel_no
LEFT JOIN vender
ON vender.id = camera.vender_id
WHERE
camera.delete = '0'
AND camera.recycle_time is null
${statusAlarmWhereOption.length ? 'AND ' + statusAlarmWhereOption.join(' AND ') : ''}
AND alarmId IN (
SELECT camera_status_alarm.id AS alarmId
FROM camera_status_alarm
RIGHT JOIN ${anxinyun}.t_video_ipc
ON toString(${anxinyun}.t_video_ipc.channel_no) = camera_status_alarm.channel_no
AND ${anxinyun}.t_video_ipc.serial_no = camera_status_alarm.serial_no
${`WHERE ${anxinyun}.t_video_ipc.structure IN (${anxinStrucIds.join(',')})`}
)
) AS cameraAlarm
LEFT JOIN camera_status
ON cameraAlarm.platform = camera_status.platform
AND cameraAlarm.statusId = camera_status.id
LEFT JOIN camera_status_resolve
ON camera_status_resolve.status_id = camera_status.id
LEFT JOIN "gbCamera"
ON "gbCamera".id = cameraAlarm.gbId
LEFT JOIN "secret_yingshi"
ON "secret_yingshi".id = cameraAlarm.yingshiSecretId
LEFT JOIN ${anxinyun}.t_video_ipc AS anxinIpc
ON toString(anxinIpc.channel_no) = cameraAlarm.cameraChannelNo
AND anxinIpc.serial_no = cameraAlarm.cameraSerialNo
LEFT JOIN ${anxinyun}.t_structure AS anxinStruc
ON anxinStruc.id = anxinIpc.structure
AND anxinStruc.id IN (${anxinStrucIds.join(',')})
LEFT JOIN ${anxinyun}.t_video_ipc_station AS anxinIpcStation
ON anxinIpcStation.ipc = anxinIpc.id
LEFT JOIN ${anxinyun}.t_sensor AS anxinStation
ON anxinStation.id = anxinIpcStation.station
`
const alarmRes = anxinStrucIds.length ? await clickHouse.vcmp.query(
queryStr
).toPromise() : []
console.log(queryStr);
let returnD = []
let positionD = {}
// 每个设备一个告警
for (let a of alarmRes) {
if (positionD[a.cameraId]) {
} else {
let d = {
createTime: a.createTime,
confirmTime: a.confirmTime,
statusId: a.statusId,
}
returnD.push(d)
positionD[a.cameraId] = {
positionReturnD: returnD.length - 1
}
}
}
ctx.status = 200;
ctx.body = returnD
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function getAlarmUse (ctx) {
try {
const models = ctx.fs.dc.models;
const { clickHouse } = ctx.app.fs
const { utils: { anxinStrucIdRange, pomsProjectRange } } = ctx.app.fs
const { pepProjectId, startTime } = ctx.query
let pomsProject = await pomsProjectRange({
ctx, pepProjectId,
keywordTarget: 'pepProject',
})
const pomsProjectIds = pomsProject.map(p => p.id)
let findOption = {
distinct: true,
where: {},
include: [{
model: models.App,
where: {},
attributes: {
exclude: ['projectId']
},
include: [{
model: models.ProjectCorrelation,
where: {},
attributes: {
exclude: ['createTime', 'createUser', 'anxinProjectId',]
},
}]
}]
}
if (startTime) {
findOption.where.createTime = { $gt: moment(startTime).format('YYYY-MM-DD HH:mm:ss') }
}
findOption.include[0].include[0].where.id = { $in: pomsProjectIds }
const listRes = await models.AppAlarm.findAll(findOption)
for (let lr of listRes) {
if (lr.app && lr.app.projectCorrelations) {
for (let p of lr.app.projectCorrelations) {
let corProjectCorrelations = pomsProject.find(pr => pr.id == p.id)
if (corProjectCorrelations) {
p.dataValues = corProjectCorrelations
}
}
}
}
ctx.status = 200;
ctx.body = listRes
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function getStatisticOnline (ctx) {
try {
const { models } = ctx.fs.dc;
const { clickHouse } = ctx.app.fs
const { utils: { judgeSuper, anxinStrucIdRange } } = ctx.app.fs
const { database: anxinyun } = clickHouse.anxinyun.opts.config
const { pepProjectId } = ctx.query
let anxinStruc = await anxinStrucIdRange({ ctx, pepProjectId })
if (anxinStruc.length) {
const anxinStrucIds = anxinStruc.map(a => a.strucId)
// 查在线率
const strucOnlineClient = ctx.app.fs.esclient.strucOnline
const onlineRes = anxinStrucIds.length ?
await strucOnlineClient.search({
index: strucOnlineClient.config.index,
type: strucOnlineClient.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]
}
}
]
}
},
"sort": [
{
"collect_time": {
"order": "asc"
}
}
],
"size": 10000
}
})
: {
hits: {
hits: []
}
}
for (let struc of anxinStruc) {
let curOnline =
onlineRes.hits.hits
.filter((h) => h._source.structure == struc.strucId)
// .sort((a, b) => {
// return a._source.collect_time - b._source.collect_time
// })
.map(s => {
return {
...s._source,
rate: s._source.online / s._source.total * 100
}
})
struc.online = curOnline
}
ctx.status = 200;
ctx.body = anxinStruc;
} else {
ctx.status = 200;
ctx.body = [];
}
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function getStrucSeries (ctx) {
try {
const { models } = ctx.fs.dc;
const { clickHouse } = ctx.app.fs
const { utils: { judgeSuper, anxinStrucIdRange } } = ctx.app.fs
const { database: anxinyun } = clickHouse.anxinyun.opts.config
const { pepProjectId } = ctx.query
let anxinStruc = await anxinStrucIdRange({ ctx, pepProjectId })
if (anxinStruc.length) {
const anxinStrucIds = anxinStruc.map(a => a.strucId)
// 查在线率
const strucSeriesClient = ctx.app.fs.esclient.strucSeries
const seriesRes = anxinStrucIds.length ?
await strucSeriesClient.search({
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]
// }
// }
// ]
// }
// },
"sort": [
{
"collect_time": {
"order": "asc"
}
}
],
"size": 10000
}
})
: {
hits: {
hits: []
}
}
for (let struc of anxinStruc) {
let curSeries =
seriesRes.hits.hits
.filter((h) => h._source.structure == struc.strucId)
// .sort((a, b) => {
// return a._source.collect_time - b._source.collect_time
// })
.map(s => {
return {
...s._source,
}
})
struc.series = curSeries
}
ctx.status = 200;
ctx.body = anxinStruc;
} else {
ctx.status = 200;
ctx.body = [];
}
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
module.exports = {
personnelApp,
problem
problem,
getAlarmData,
getAlarmVideo,
getAlarmUse,
getStatisticOnline,
getStrucSeries,
}

2
api/app/lib/controllers/control/data.js

@ -418,6 +418,6 @@ module.exports = {
getAppAlarmsAggDay,
getVideoAlarmsAggDay,
getAlarmsHandleStatistics,
getLatestDynamic
};

14
api/app/lib/routes/control/index.js

@ -40,4 +40,18 @@ module.exports = function (app, router, opts) {
//最新动态
app.fs.api.logAttr['GET/latest/dynamic'] = { content: '查询最新动态', visible: false };
router.get('/latest/dynamic', csData.getLatestDynamic);
app.fs.api.logAttr['GET/alarm/data'] = { content: '查询数据告警', visible: false };
router.get('/alarm/data', analysis.getAlarmData);
app.fs.api.logAttr['GET/alarm/use'] = { content: '查询应用告警', visible: false };
router.get('/alarm/use', analysis.getAlarmUse);
app.fs.api.logAttr['GET/statisticOnline'] = { content: '查询数据在线率', visible: false };
router.get('/StatisticOnline', analysis.getStatisticOnline);
app.fs.api.logAttr['GET/strucSeries'] = { content: '查询数据在线率', visible: false };
router.get('/strucSeries', analysis.getStrucSeries);
};

10
api/config.js

@ -141,6 +141,10 @@ const CAIYUN_KEY = process.env.CAIYUN_KEY || flags.caiyunKey || '1l0eNveMANMXEIJ
const ES_PLATFORM_NAME = process.env.ES_PLATFORM_NAME || flags.esPlatformName
|| 'anxincloud'
|| 'anxinyun';
const ES_CONTINUITY_NAME = process.env.ES_CONTINUITY_NAME || flags.esContinuityName
|| 'anxincloud'
|| 'anxinyun';
const ANXINCLOUD_ES_NODES_REST = process.env.ANXINCLOUD_ES_NODES_REST || flags.es;
// //business_key
// const BUSINESS_KEY=process.env.BUSINESS_KEY||['160','161']
@ -340,6 +344,12 @@ const product = {
index: `${ES_PLATFORM_NAME}_online`,
type: flags.esType ? flags.esType : '_doc'
},
strucSeries: {
//告警记录
rootURL: ANXINCLOUD_ES_NODES_REST.split(','),
index: `${ES_CONTINUITY_NAME}_continue`,
type: flags.esType ? flags.esType : '_doc'
},
}
}
}

4
web/client/src/components/setup.jsx

@ -11,7 +11,7 @@ function Setup (props) {
tableType,
tableList,
layout, //
data=8
data = 8
} = props;
const [check, setCheck] = useState([]);
@ -107,7 +107,7 @@ function Setup (props) {
key={itm.value}
value={itm.value}
style={layout == 'long' ? {} : checkboxcss}
disabled={ischeck(itm.value) || ['workbench', 'dynamic', 'handle', 'DeviceAccess','discovery'].includes(itm.value)}
disabled={ischeck(itm.value) || ['workbench', 'handle', 'DeviceAccess', 'discovery'].includes(itm.value)}
>
{itm.name}
</Checkbox>

40
web/client/src/index.less

@ -1,9 +1,8 @@
// webpack (vite 用 alias 兼容了)
// @import '~@douyinfe/semi-ui/dist/css/semi.min.css';
@import '~perfect-scrollbar/css/perfect-scrollbar.css';
@import '~nprogress/nprogress.css';
@import '~simplebar-react/dist/simplebar.min.css';
@import "~perfect-scrollbar/css/perfect-scrollbar.css";
@import "~nprogress/nprogress.css";
@import "~simplebar-react/dist/simplebar.min.css";
*,
*::before,
@ -11,6 +10,17 @@
box-sizing: border-box;
}
* {
:focus-visible {
outline: none;
}
}
.ps__rail-y,
.ps__rail-x {
background: transparent !important;
}
html,
body {
margin: 0;
@ -23,12 +33,10 @@ body {
}
.semi-timepicker-panel {
//时间选择器不显示滚动栏
::-webkit-scrollbar {
display: none;
/* Chrome Safari */
}
scrollbar-width: none;
@ -41,28 +49,28 @@ body {
a:link {
text-decoration: none;
color: unset
color: unset;
}
a:visited {
text-decoration: none;
color: unset
color: unset;
}
a:hover {
text-decoration: none;
color: unset
color: unset;
}
a:active {
text-decoration: none;
color: unset
color: unset;
}
}
// SEMI 全局样式
.semi-popover-content {
min-width: 300px
min-width: 300px;
}
.semi-portal-inner {
@ -70,10 +78,10 @@ body {
}
@font-face {
font-family: 'YouSheBiaoTiHei'; //这个可以任意取,但是应与后面相对应eg:yxingguang
src: url('/assets/fonts/YouSheBiaoTiHei-2.ttf');
font-family: "YouSheBiaoTiHei"; //这个可以任意取,但是应与后面相对应eg:yxingguang
src: url("/assets/fonts/YouSheBiaoTiHei-2.ttf");
}
@font-face {
font-family: 'DINExp'; //这个可以任意取,但是应与后面相对应eg:yxingguang
src: url('/assets/fonts/DINExp.ttf');
}
font-family: "DINExp"; //这个可以任意取,但是应与后面相对应eg:yxingguang
src: url("/assets/fonts/DINExp.ttf");
}

48
web/client/src/sections/control/actions/control.js

@ -130,3 +130,51 @@ export function getLatestDynamic (query) { //查询最新动态
reducer: { name: '' }
});
}
export function getAlarmData (query = {}) { //查询数据告警
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
query,
actionType: 'GET_ALARM_DATA',
url: `${ApiTable.getAlarmData}`,
msg: { error: '查询数据告警失败' },
reducer: { name: '' }
});
}
export function getAlarmUse (query = {}) { //查询视频告警
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
query,
actionType: 'GET_ALARM_USE',
url: `${ApiTable.getAlarmUse}`,
msg: { error: '查询应用告警失败' },
reducer: { name: '' }
});
}
export function getStatisticOnline (query = {}) { //查询数据在线率
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
query,
actionType: 'GET_STATISTICS_ONLINE',
url: `${ApiTable.getStatisticOnline}`,
msg: { error: '查询数据在线率失败' },
reducer: { name: 'statisticOnline' }
});
}
export function getStrucSeries (query = {}) { //查询数据连续率
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
query,
actionType: 'GET_STRUC_SERIES',
url: `${ApiTable.getStrucSeries}`,
msg: { error: '查询数据连续率失败' },
reducer: { name: 'strucSeries' }
});
}

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

@ -0,0 +1,774 @@
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 { push } from 'react-router-redux';
import { Setup, OutHidden } from "$components";
import ReactECharts from 'echarts-for-react';
import moment from "moment";
import SimpleBar from 'simplebar-react';
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 [successionId, setSuccessionId] = 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 [seriesStruc, setSeriesStruc] = useState([])
const [series, setSeries] = useState([])
const [seriesValue, setSeriesValue] = useState([])
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('')
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(() => {
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) || [])
}
})
}, [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])
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) => {
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)
}
})
}
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 }}>
{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>
}
</div>
{/* 故障数排名*/}
<div style={{ padding: 10, width: '50%', height: 300, position: "relative" }}>
<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: '10%',
// right: '4%',
// bottom: '3%',
// containLabel: true
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['故障数'],
right: '10%',
},
yAxis: {
type: 'category',
data: rankData?.map(v => 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={}
/>
</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 showClear placeholder='项目' value={onlineId} style={{ width: 160, marginRight: 10 }}
onChange={(v) => {
setOnlineId(v)
}}
optionList={pomsList}
/>
<Select showClear
filter
value={value}
multiple={true}
maxTagCount={1}
style={{ width: 160, marginRight: 10 }}
optionList={onlineStruc}
onChange={v => {
setValue(v)
let data = statisticOnline?.filter(s => !onlineId || s.pomsProject?.map(p => p.id)?.includes(onlineId))
setOnline(data?.filter(s => v.includes(s.strucId)))
}}
/>
</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 + ":" + "&nbsp" + "&nbsp" + 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 showClear placeholder='项目' value={successionId} style={{ width: 160, marginRight: 10 }}
onChange={(v) => {
setSuccessionId(v)
}}
optionList={pomsList}
/>
<Select showClear
filter
placeholder='结构物'
value={seriesValue}
multiple={true}
maxTagCount={1}
style={{ width: 160, marginRight: 10 }}
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)))
}}
/>
</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 = series?.find(s => s.strucName == v.seriesName)?.series?.find(d => moment(d.collect_time).format('YYYY-MM-DD HH') == v.data[0]) || {}
title = title + v.seriesName + ":" + "&nbsp" + "&nbsp" + v.data[1] + "%" + "(" + find?.num + "/" + find?.tTotal + ")" + '<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.strucName,
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);

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

@ -5,9 +5,12 @@ import { push } from 'react-router-redux';
import './control.less'
import PerfectScrollbar from "perfect-scrollbar";
import repairFQA from '../../means/containers/repairFQA';
import { Setup, OutHidden } from "$components";
import { Setup } from "$components";
import ReactECharts from 'echarts-for-react';
import moment from "moment";
import SimpleBar from 'simplebar-react';
import AlarmChart from '../components/alarm-chart';
let newScrollbar;
let overviewScrollbar;
@ -22,7 +25,7 @@ let member
let web
const Control = ({ dispatch, actions, user, history, loading, socket, pepProjectId }) => {
const Control = ({ dispatch, actions, user, history, loading, socket, pepProjectId, projectPoms }) => {
const { control, install } = actions
const [memberList, setMemberList] = useState([])//
@ -66,7 +69,6 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
if (msg?.msgDataMap) {
setSocketData(msg?.msgDataMap)
}
let a = msg;
});
return () => {
socket.off("alarmSendSocket")
@ -186,6 +188,17 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
}
}, [socketData])
useEffect(() => {
if (projectPoms) {
setProjectData(projectPoms?.filter(v => v.pepProjectIsDelete != 1))
let data = projectPoms?.filter(v => v.pepProjectIsDelete != 1)?.map(v => ({ pepProjectId: v.id, pepProjectName: v.pepProjectName || v.name }))
setPomsList(data)
setProjectId(projectPoms[0]?.pepProjectId)
}
}, [projectPoms])
useEffect(() => {
consoleToollink()
@ -197,17 +210,6 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
: ""
attribute(v)
})
async function concentration2 () {
await dispatch(install.getProjectPoms({ global: 1 })).then((res) => { //
if (res.success) {
setProjectData(res.payload.data?.rows?.filter(v => v.pepProjectIsDelete !== 1))
let data = res.payload.data?.rows?.filter(v => v.pepProjectIsDelete !== 1)?.map(v => ({ pepProjectId: v.id, pepProjectName: v.pepProjectName || v.name }))
setPomsList(data)
setProjectId(data[0]?.pepProjectId)
}
})
}
concentration2()
const domProject = document.getElementById("news");
if (domProject) {
@ -359,7 +361,7 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
}
})
}
concentration4()
// concentration4()
}, [projectId])
useEffect(() => {
@ -418,7 +420,7 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
})
}
}
concentration3()
// concentration3()
const domProject1 = document.getElementById("overviewCalc");
if (domProject1) {
@ -611,14 +613,14 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
let Select = {
overall: ['workbench', 'statistical', 'analyse', 'dynamic', 'tool'],
overall: ['workbench', 'statistical', 'dataAnalyse', 'analyse', 'dynamic', 'tool'],
workbench: ['project', 'data', 'app', 'device'],
statistical: ['milestone', 'personnel', 'DeviceAccess', 'web', 'problem'],
analyse: ['dataInterrupt', 'dataAbnormal', 'policyHit', 'videoException', 'appAbnormal', 'deviceAbnormal', 'problemAnalysis'],
dynamic: ['discovery', 'notice', 'handle', 'confirm'],
}
let show = {
overall: ['workbench', 'statistical', 'analyse', 'dynamic', 'tool'],
overall: ['workbench', 'statistical', 'dataAnalyse'],
workbench: ['project', 'data', 'app', 'device'],
statistical: ['milestone', 'personnel', 'web', 'problem'],
analyse: ['dataInterrupt', 'dataAbnormal', 'policyHit', 'videoException', 'appAbnormal', 'deviceAbnormal', 'problemAnalysis'],
@ -652,9 +654,10 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
{ name: '我的工作台', sort: 1, key: 'workbench', },
{ name: '统计概览', sort: 2, key: 'statistical', },
{ name: 'BI分析模块', sort: 3, key: 'analyse', },
{ name: '最新动态', sort: 4, key: 'dynamic', },
{ name: '我常用的工具', sort: 5, key: 'tool', },
{ name: '数据分析', sort: 3, key: 'dataAnalyse', },
{ name: 'BI分析模块', sort: 4, key: 'analyse', },
{ name: '最新动态', sort: 5, key: 'dynamic', },
{ name: '我常用的工具', sort: 6, key: 'tool', },
]
useEffect(() => {
@ -694,14 +697,17 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
setSetup(true)
setTableType('overall')
attribute('overall')
setSetData(5)
setSetData(6)
}} />
</div>
</div>
{/* 主体 */}
<div style={{ display: 'flex', width: '100%' }}>
{/* 左边 */}
<div style={{ width: 'calc(100% - 434px)' }}>
<div style={{
width: exhibition.current?.overall?.find(v => v.key == 'dynamic' || v.key == 'tool') ?
'calc(100% - 434px)' : "calc(100%)"
}}>
{/* 工作台和统计概览 */}
<div style={{ background: '#FFFFFF', boxShadow: '0px 0px 12px 2px rgba(220,222,224,0.2)', borderRadius: 2, padding: '20px 24px' }}>
{/* 我的工作台 */}
@ -794,7 +800,8 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
</div>
</div>
{/* 统计概览 */}
<div id='overviewCalc' style={{ width: 'calc(100%)', position: 'relative' }}>
<SimpleBar style={{ width: 'calc(100%)', height: 240 }} forceVisible="x" >
<div style={{ display: 'inline-flex', marginTop: 16 }}>
{/* 项目 */}
{
@ -1012,12 +1019,20 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
</div>
: ""}
</div>
</div></> : ""}
</SimpleBar>
</> : ""}
</div>
{/* 图表 */}
{
exhibition.current?.overall?.find(v => v.key == 'dataAnalyse') &&
<AlarmChart />
}
{/* BI分析模块 */}
{exhibition.current?.overall?.find(v => v.key == 'analyse') ?
<div style={{ background: '#FFFFFF', boxShadow: '0px 0px 12px 2px rgba(220,222,224,0.2)', borderRadius: 2, paddingTop: 20, paddingLeft: 24, marginTop: 22 }}>
{/* BI分析模块 */}
<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>
@ -1205,11 +1220,16 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
</div>
</div> : ""}
</div>
{/* 右边 */}
<div style={{ width: 415, marginLeft: 20 }}>
{exhibition.current?.overall?.find(v => v.key == 'dynamic' || v.key == 'tool')
&& <div style={{ width: 415, marginLeft: 20 }}>
{/* 最新动态 */}
<div style={{ width: 415, background: '#FFFFFF', boxShadow: '0px 0px 12px 2px rgba(220,222,224,0.2)', borderRadius: 2, paddingTop: 20, paddingLeft: 21, height: 639, }}>
{exhibition.current?.overall?.find(v => v.key == 'dynamic')
&& <div style={{ width: 415, background: '#FFFFFF', marginBottom: 20, boxShadow: '0px 0px 12px 2px rgba(220,222,224,0.2)', borderRadius: 2, paddingTop: 20, paddingLeft: 21, height: 639, }}>
<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>
@ -1270,10 +1290,10 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
</Timeline>
</div>
</div>
</div>
</div>}
{/* 我常用的工具 */}
{exhibition.current?.overall?.find(v => v.key == 'tool') ?
<div style={{ marginTop: 20, background: '#FFFFFF', boxShadow: '0px 0px 12px 2px rgba(220,222,224,0.2)', borderRadius: 2, padding: 20 }}>
<div style={{ background: '#FFFFFF', boxShadow: '0px 0px 12px 2px rgba(220,222,224,0.2)', borderRadius: 2, padding: 20 }}>
<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>
@ -1352,7 +1372,7 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
{toolData && toolData >= 10 ? <div style={{ color: 'red', marginTop: 8 }}>最多可添加10个应用</div> : ""}
</div> : ""}
</div>
</div>}
</div>
</div>
{/* 页面各个设置弹窗 */}
@ -1449,14 +1469,15 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
}
function mapStateToProps (state) {
const { auth, global, members, webSocket } = state;
const { auth, global, members, webSocket, ProjectPoms } = state;
return {
// loading: members.isRequesting,
user: auth.user,
actions: global.actions,
pepProjectId: global.pepProjectId,
// members: members.data,
socket: webSocket.socket
socket: webSocket.socket,
projectPoms: ProjectPoms?.data?.rows
};
}

25
web/client/src/utils/webapi.js

@ -43,8 +43,8 @@ export const ApiTable = {
groupStatisticAlarm: 'project/group/statistic/alarm',
groupProject: "project/group/list",
groupProjectDetail: "project/group/:groupId/detail",
projectWordOrders:'project/workOrders',
wordOrdersRepairRank:'project/workOrders/repairRank',
projectWordOrders: 'project/workOrders',
wordOrdersRepairRank: 'project/workOrders/repairRank',
//告警
@ -88,6 +88,11 @@ export const ApiTable = {
getAppAlarmsAggDay: 'app/alarms/agg/day', //查询BI分析数据-应用
getAlarmsHandleStatistics: '/alarms/handle/statistics', //查询BI分析数据-问题处理效率分析
getLatestDynamic: 'latest/dynamic', // 查询最新动态
getAlarmData: 'alarm/data', //查询数据告警
getAlarmUse: 'alarm/use', //查询应用告警
getStatisticOnline: 'statisticOnline', //查询在线率
getStrucSeries: 'strucSeries', //查询连续率
//资料库
addEditFile: 'file/addEdit', //添加、编辑文件夹
@ -147,21 +152,21 @@ export const ApiTable = {
respondRecord: 'respond-record',
//待办工单
workOrders:'unfinished',
workOrders: 'unfinished',
//获取设备型号
getDeviceType:'deviceType',
getDeviceType: 'deviceType',
//结构物和对应设备类型
getStruc:'structure',
getStruc: 'structure',
//获取固件包列表
getFirmware:'firmware',
getFirmware: 'firmware',
//增加/覆盖固件包
upgradeFirmware:'upgradeFirmware',
upgradeFirmware: 'upgradeFirmware',
//删除固件包
deleteFirmware:'deleteFirmware',
deleteFirmware: 'deleteFirmware',
//获取设备信息
getThingMessages:'getThingMessages',
getThingMessages: 'getThingMessages',
//下发配置(批量单个)
distributeConfiguration:'distributeConfiguration'
distributeConfiguration: 'distributeConfiguration'
};
// 项企的接口

Loading…
Cancel
Save