wuqun 3 years ago
parent
commit
7badccc281
  1. 2
      api/.vscode/launch.json
  2. 218
      api/app/lib/controllers/control/toolLink.js
  3. 57
      web/client/src/sections/control/actions/control.js
  4. 135
      web/client/src/sections/control/containers/control.jsx
  5. 10
      web/client/src/sections/problem/containers/dataAlarm.jsx
  6. 2
      web/client/src/utils/webapi.js

2
api/.vscode/launch.json

@ -56,7 +56,7 @@
// "--clickHouseDataAlarm default",
//
"--clickHouseAnxincloud Anxinyun20",
"--clickHouseAnxincloud Anxinyun21",
"--clickHousePepEmis pepca8",
"--clickHouseProjectManage peppm8",
"--clickHouseVcmp video_access_dev",

218
api/app/lib/controllers/control/toolLink.js

@ -114,105 +114,235 @@ async function del (ctx) {
async function count (ctx) {
try {
const { models } = ctx.fs.dc;
const { userId, pepUserId, userInfo = {}, pepUserInfo } = ctx.fs.api
const { clickHouse } = ctx.app.fs
const { utils: { judgeSuper, anxinStrucIdRange } } = ctx.app.fs
const { utils: { judgeSuper, anxinStrucIdRange, pomsProjectRange } } = ctx.app.fs
const { database: anxinyun } = clickHouse.anxinyun.opts.config
const { pepProjectId } = ctx.request.body
const { pepProjectId } = ctx.request.query
let anxinStruc = await anxinStrucIdRange({
ctx, pepProjectId
})
let pomsProject = await pomsProjectRange({
ctx, pepProjectId,
})
const pomsProjectIds = pomsProject.map(p => p.id)
if (anxinStruc.length) {
const anxinStrucIds = anxinStruc.map(a => a.strucId) || []
const dataAlarm = await clickHouse.dataAlarm.query(`
SELECT
AlarmId,State,StartTime
AlarmId,State,StartTime,AlarmGroup
FROM
alarms
WHERE
alarms.StructureId IN (${anxinStrucIds.join(",")})
`).toPromise();
//数据告警总数
const alarm = await clickHouse.dataAlarm.query(`
SELECT
count(alarms.AlarmId) AS count
FROM
alarms
WHERE
alarms.StructureId IN (${anxinStrucIds.join(",")})
`).toPromise();
const confirmedAlarm = dataAlarm
// TODO: 开发临时注释
.filter(ar => ar.State && ar.State > 2)
.map(ar => "'" + ar.AlarmId + "'")
//剩余数据告警
const alarmSurplus = dataAlarm.filter(ar => ar.State && ar.State < 3).length || 0
const dataSurplus = dataAlarm.filter(ar => ar.State && ar.State < 3 && ar.AlarmGroup < 4).length || 0
//剩余设备告警
const toolSurplus = dataAlarm.filter(ar => ar.State && ar.State < 3 && ar.AlarmGroup > 3).length || 0
//今日新增数据告警
const alarmNewAdd = await clickHouse.dataAlarm.query(`
SELECT
count(alarms.StartTime) AS count
FROM
alarms
WHERE
alarms.StructureId IN (${anxinStrucIds.join(",")})
AND
alarms.StartTime >= '${moment().startOf('day').format('YYYY-MM-DD HH:mm:ss')}'
AND
alarms.StartTime <= '${moment().endOf('day').format('YYYY-MM-DD HH:mm:ss')}'
`).toPromise();
const dataNewAdd = dataAlarm.filter(r => moment(moment().startOf('day').format('YYYY-MM-DD HH:mm:ss')).isBefore(r.StartTime) && moment(r.createTime).isBefore(moment().endOf('day').format('YYYY-MM-DD HH:mm:ss')) && r.AlarmGroup < 4).length || 0
const toolNewAdd = dataAlarm.filter(r => moment(moment().startOf('day').format('YYYY-MM-DD HH:mm:ss')).isBefore(r.StartTime) && moment(r.createTime).isBefore(moment().endOf('day').format('YYYY-MM-DD HH:mm:ss')) && r.AlarmGroup > 3).length || 0
//今日确认数据告警
const confirmedAlarmDetailMax = confirmedAlarm.length ?
const dataConfirme = confirmedAlarm.length ?
await clickHouse.dataAlarm.query(`
SELECT
max(Time) AS Time, AlarmId , max(Content) AS Content
max(Time) AS Time, AlarmId , max(Content) AS Content,
alarms.AlarmGroup AS AlarmGroup
FROM
alarm_details
LEFT JOIN alarms
ON alarm_details.AlarmId=alarms.AlarmId
WHERE
AlarmId IN (${confirmedAlarm.join(',')})
AND
alarm_details.Time >= '${moment().startOf('day').format('YYYY-MM-DD HH:mm:ss')}'
AND
alarm_details.Time <= '${moment().endOf('day').format('YYYY-MM-DD HH:mm:ss')}'
GROUP BY AlarmId
GROUP BY AlarmId,AlarmGroup
`).toPromise() :
[];
let findOption = {
where: {
'$app->projectCorrelations.id$': {
$in: pomsProjectIds
}
},
attributes: ['createTime', 'confirmTime'],
include: [{
model: models.App,
where: {
},
attributes: ['id', 'name'],
include: [{
model: models.ProjectCorrelation,
where: {
},
attributes: ['id'],
}]
}]
}
//应用总告警
const listRes = await models.AppAlarm.findAndCountAll(findOption)
//剩余应用告警
const appSurplus = listRes.rows.filter(r => !r.confirmTime).length || 0
//今日新增应用告警
const appNewAdd = listRes.rows.filter(r => moment(moment().startOf('day').format('YYYY-MM-DD HH:mm:ss')).isBefore(r.createTime) && moment(r.createTime).isBefore(moment().endOf('day').format('YYYY-MM-DD HH:mm:ss'))).length || 0
//今日确认应用告警
const appConfirme = listRes.rows.filter(r => moment(moment().startOf('day').format('YYYY-MM-DD HH:mm:ss')).isBefore(r.confirmTime) && moment(r.confirmTime).isBefore(moment().endOf('day').format('YYYY-MM-DD HH:mm:ss'))).length || 0
const alarmRes = anxinStrucIds.length ? await clickHouse.vcmp.query(
`
SELECT
cameraAlarm.cameraId AS cameraId,
cameraAlarm.cameraName AS cameraName,
cameraAlarm.cameraSerialNo AS cameraSerialNo,
cameraAlarm.cameraChannelNo AS cameraChannelNo,
cameraAlarm.alarmId AS alarmId,
cameraAlarm.createTime AS createTime,
cameraAlarm.platform AS platform,
cameraAlarm.confirmTime AS confirmTime,
camera_status_resolve.id AS resolveId,
camera_status.describe AS statusDescribe,
camera_status_resolve.resolve AS resolve,
"gbCamera".online AS cameraOnline,
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.name AS cameraName,
camera_status_alarm.id AS alarmId,
camera_status_alarm.create_time AS createTime,
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_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 = false
AND camera.recycle_time is null
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 ${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
`
).toPromise() : []
let returnD = []
let positionD = {}
// 每个设备一个告警
for (let a of alarmRes) {
if (positionD[a.cameraId]) {
let curD = returnD[positionD[a.cameraId].positionReturnD]
} else {
let d = {
cameraId: a.cameraId,
cameraName: a.cameraName,
createTime: a.createTime,
alarmId: a.alarmId,
confirmTime: a.confirmTime,
}
returnD.push(d)
positionD[a.cameraId] = {
positionReturnD: returnD.length - 1
}
}
}
//剩余视频告警
const videoSurplus = returnD.filter(r => !r.confirmTime).length || 0
//今日新增视频告警
const videoNewAdd = returnD.filter(r => moment(moment().startOf('day').format('YYYY-MM-DD HH:mm:ss')).isBefore(r.createTime) && moment(r.createTime).isBefore(moment().endOf('day').format('YYYY-MM-DD HH:mm:ss'))).length || 0
//今日确认视频告警
const videoConfirme = returnD.filter(r => moment(moment().startOf('day').format('YYYY-MM-DD HH:mm:ss')).isBefore(r.confirmTime) && moment(r.confirmTime).isBefore(moment().endOf('day').format('YYYY-MM-DD HH:mm:ss'))).length || 0
let findOptions = {
where: {
del: false
},
attributes: []
}
if (!userInfo.role.includes('SuperAdmin') && !userInfo.role.includes('admin')) {
findOptions.where.id = { $in: userInfo.correlationProject }
}
const projects = await models.ProjectCorrelation.findAndCountAll(findOptions)
ctx.status = 200;
ctx.body = {
dataSurplus: dataSurplus + videoSurplus,
dataNewAdd: dataNewAdd + videoNewAdd,
dataConfirme: appConfirme + dataConfirme.filter(r => r.AlarmGroup < 4).length,
toolSurplus: toolSurplus,
toolNewAdd: toolNewAdd,
toolConfirme: dataConfirme.filter(r => r.AlarmGroup > 3).length,
ctx.status = 200;
ctx.body = {
dataAlarm: {
alarm: alarm[0].count || 0,
alarmSurplus: alarmSurplus,
alarmNewAdd: alarmNewAdd[0].count || 0,
confirmedAlarmDetailMax: confirmedAlarmDetailMax.length || 0,
},
videoAlarm:{
}
appSurplus: appSurplus,
appNewAdd: appNewAdd,
appConfirme: appConfirme,
projects: projects.count,
}
} else {

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

@ -1,37 +1,48 @@
'use strict';
import { ApiTable ,basicAction} from '$utils'
import { ApiTable, basicAction } from '$utils'
export function getConsoleToollink () { //获取常用工具
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_CONSLE_TOOLLINK',
url: `${ApiTable.consoleToollink}`,
msg: { option: '获取常用工具' },
reducer: { name: '' }
});
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_CONSLE_TOOLLINK',
url: `${ApiTable.consoleToollink}`,
msg: { option: '获取常用工具' },
reducer: { name: '' }
});
}
export function putConsoleToollink (data) { //编辑常用工具
return dispatch => basicAction({
type: 'put',
dispatch: dispatch,
data,
actionType: 'PUT_CONSLE_TOOLLINK',
url: `${ApiTable.consoleToollink}`,
msg: { option: '编辑常用工具' },
reducer: { name: '' }
type: 'put',
dispatch: dispatch,
data,
actionType: 'PUT_CONSLE_TOOLLINK',
url: `${ApiTable.consoleToollink}`,
msg: { option: '编辑常用工具' },
reducer: { name: '' }
});
}
export function deleteConsoleToollink (orgId) { //删除常用工具
console.log(orgId);
return dispatch => basicAction({
type: 'delete',
dispatch: dispatch,
actionType: 'DELETE_CONSLE_TOOLLINK',
url: `${ApiTable.deleteConsoleToollink.replace('{linkId}', orgId)}`,
msg: { option: '删除常用工具' },
reducer: { name: '' }
type: 'delete',
dispatch: dispatch,
actionType: 'DELETE_CONSLE_TOOLLINK',
url: `${ApiTable.deleteConsoleToollink.replace('{linkId}', orgId)}`,
msg: { option: '删除常用工具' },
reducer: { name: '' }
});
}
export function geteteConsoleCount (query) { //工作台数量查询
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
query,
actionType: 'GET_CONSLE_COUNT',
url: `${ApiTable.geteteConsoleCount}`,
msg: { option: '工作台数量查询' },
reducer: { name: '' }
});
}

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

@ -18,7 +18,7 @@ let alarmScrollbar;
const Control = (props) => {
const { dispatch, actions, user, loading, socket } = props
const { dispatch, actions, user, loading, socket ,pepProjectId} = props
const { control } = actions
const stationList = [
'url(/assets/images/console/lan_1.png)',
@ -43,6 +43,7 @@ const Control = (props) => {
const [toolShow, setToolShow] = useState([]); //
const [tableSetup, setTableSetup] = useState([]); //
const [exhibition, setExhibition] = useState({ workbench: [] }); //
const [workData, setWorkData] = useState({}); //
const FormApi = useRef()
@ -50,7 +51,6 @@ const Control = (props) => {
useEffect(() => {
consoleToollink()
//
let data = ['workbench']
data.map(v => {
@ -63,55 +63,61 @@ const Control = (props) => {
}, [])
useEffect(() => {
// newScrollbar = new PerfectScrollbar("#news", {
// suppressScrollX: true,
// });
// const domProject = document.getElementById("news");
// if (domProject && newScrollbar) {
// newScrollbar.update();
// }
// overviewScrollbar = new PerfectScrollbar("#overview", {
// suppressScrollY: true,
// });
// const domProject1 = document.getElementById("overview");
// if (domProject1 && overviewScrollbar) {
// overviewScrollbar.update();
// }
// memberScrollbar = new PerfectScrollbar("#member", {
// suppressScrollX: true,
// });
// const domProject2 = document.getElementById("member");
// if (domProject2 && memberScrollbar) {
// memberScrollbar.update();
// }
// equipmentScrollbar = new PerfectScrollbar("#equipment", {
// suppressScrollX: true,
// });
// const domProject3 = document.getElementById("equipment");
// if (domProject3 && equipmentScrollbar) {
// equipmentScrollbar.update();
// }
// webScrollbar = new PerfectScrollbar("#web", {
// suppressScrollX: true,
// });
// const domProject4 = document.getElementById("web");
// if (domProject4 && webScrollbar) {
// webScrollbar.update();
// }
// problemsScrollbar = new PerfectScrollbar("#problems", {
// suppressScrollX: true,
// });
// const domProject5 = document.getElementById("problems");
// if (domProject5 && problemsScrollbar) {
// problemsScrollbar.update();
// }
// alarmScrollbar = new PerfectScrollbar("#alarm", {
// suppressScrollY: true,
// });
// const domProject6 = document.getElementById("alarm");
// if (domProject6 && alarmScrollbar) {
// alarmScrollbar.update();
// }
dispatch(control.geteteConsoleCount({pepProjectId:pepProjectId})).then(res => {
if (res.success) setWorkData(res.payload.data)
})
}, [pepProjectId])
useEffect(() => {
newScrollbar = new PerfectScrollbar("#news", {
suppressScrollX: true,
});
const domProject = document.getElementById("news");
if (domProject && newScrollbar) {
newScrollbar.update();
}
overviewScrollbar = new PerfectScrollbar("#overview", {
suppressScrollY: true,
});
const domProject1 = document.getElementById("overview");
if (domProject1 && overviewScrollbar) {
overviewScrollbar.update();
}
memberScrollbar = new PerfectScrollbar("#member", {
suppressScrollX: true,
});
const domProject2 = document.getElementById("member");
if (domProject2 && memberScrollbar) {
memberScrollbar.update();
}
equipmentScrollbar = new PerfectScrollbar("#equipment", {
suppressScrollX: true,
});
const domProject3 = document.getElementById("equipment");
if (domProject3 && equipmentScrollbar) {
equipmentScrollbar.update();
}
webScrollbar = new PerfectScrollbar("#web", {
suppressScrollX: true,
});
const domProject4 = document.getElementById("web");
if (domProject4 && webScrollbar) {
webScrollbar.update();
}
problemsScrollbar = new PerfectScrollbar("#problems", {
suppressScrollX: true,
});
const domProject5 = document.getElementById("problems");
if (domProject5 && problemsScrollbar) {
problemsScrollbar.update();
}
alarmScrollbar = new PerfectScrollbar("#alarm", {
suppressScrollY: true,
});
const domProject6 = document.getElementById("alarm");
if (domProject6 && alarmScrollbar) {
alarmScrollbar.update();
}
// ACTION
// dispatch(actions.example.getMembers(user.orgId))
@ -138,13 +144,17 @@ const Control = (props) => {
}
let listAll = [
{ name: '关注的项目', sort: 1, key: 'project', data: 1, img: 'url(/assets/images/console/lan_1.png)' },
{ name: '数据告警', sort: 2, key: 'data', data: 2, img: 'url(/assets/images/console/lv_1.png)' },
{ name: '应用告警', sort: 2, key: 'app', data: 3, img: 'url(/assets/images/console/hong_1.png)' },
{ name: '设备告警', sort: 2, key: 'device', data: 225, img: 'url(/assets/images/console/hong_1.png)' },
{ name: '关注的项目', sort: 1, key: 'project', data: workData?.projects, img: 'url(/assets/images/console/lan_1.png)' },
{ name: '数据告警', sort: 2, key: 'data', data: workData?.dataSurplus, img: 'url(/assets/images/console/lv_1.png)' },
{ name: '应用告警', sort: 2, key: 'app', data: workData?.appSurplus, img: 'url(/assets/images/console/hong_1.png)' },
{ name: '设备告警', sort: 2, key: 'device', data: workData?.toolSurplus, img: 'url(/assets/images/console/hong_1.png)' },
]
console.log(workData);
console.log(listAll);
useEffect(() => {
attribute('workbench')
}, [workData])
const attribute = (title) => {
let take = localStorage.getItem(title)
@ -152,10 +162,8 @@ const Control = (props) => {
: [];
let data = Select[title].map(v => {
let dataTitle = listAll.find(vv => v == vv.key) || {}
console.log(dataTitle);
return { name: dataTitle.name, value: dataTitle.key }
})
console.log(data);
let TableDisplay = take?.map(v => listAll?.find(vv => v == vv.key))
TableDisplay.sort((a, b) => a.sort - b.sort)
setExhibition({ ...exhibition, [title]: TableDisplay })
@ -165,7 +173,7 @@ const Control = (props) => {
return (
11 ? <img src="/assets/images/install/watting.png" alt="" style={{ width: 'calc(100% + 16px)', position: "relative", top: -12, left: -8, }} /> :
// 11 ? <img src="/assets/images/install/watting.png" alt="" style={{ width: 'calc(100% + 16px)', position: "relative", top: -12, left: -8, }} /> :
<>
<div style={{ padding: '0px 40px', width: '100%' }} className='console'>
{/* 头部 */}
@ -209,7 +217,7 @@ const Control = (props) => {
剩余问题:
</div>
<div style={{ fontSize: 16, color: '#4A4A4A', width: 91 }}>
122
{(workData?.appSurplus + workData?.dataSurplus + workData?.toolSurplus) || 0}
</div>
</div>
<div style={{ display: 'flex', alignItems: 'center', marginTop: 26 }}>
@ -218,7 +226,7 @@ const Control = (props) => {
</div>
<div style={{ fontSize: 16, color: '#4A4A4A', width: 91, display: 'flex' }}>
<div>
12223
{(workData?.appNewAdd + workData?.dataNewAdd + workData?.toolNewAdd) || 0}
</div>
<div style={{ display: 'flex', alignItems: 'center', marginLeft: 4 }}>
<img title='设置' src="/assets/images/console/icon_up.png" style={{ width: 18, height: 18 }} />
@ -230,13 +238,13 @@ const Control = (props) => {
今日处理:
</div>
<div style={{ fontSize: 16, color: '#4A4A4A', width: 91 }}>
3
{(workData?.appConfirme + workData?.dataConfirme + workData?.toolConfirme) || 0}
</div>
</div>
</div>
{/* 循环类型 */}
<div id='alarm' style={{ width: 'calc(100% - 200px)', position: 'relative', whiteSpace: 'nowrap', }}>
{exhibition['workbench'].map((item, index) => {
{exhibition['workbench']?.map((item, index) => {
return (
<div key={item.name} style={{ background: item.img, backgroundSize: "100% 100%", display: "inline-block", width: 270, height: 135, marginRight: 26 }}>
<div style={{ margin: '35px 0px 0px 134px' }}>
@ -634,6 +642,7 @@ function mapStateToProps (state) {
// loading: members.isRequesting,
user: auth.user,
actions: global.actions,
pepProjectId: global.pepProjectId,
// members: members.data,
// socket: webSocket.socket
};

10
web/client/src/sections/problem/containers/dataAlarm.jsx

@ -136,10 +136,10 @@ const DataAlarm = ({ match, dispatch, actions, user, loading, socket, iotVcmpWeb
}],
deviceAbnormal: [ // (deviceAbnormal)
{ name: '搜索', field: '1' },
{
name: '设备类型', field: 'groupUnitId',
data: genre
},
// {
// name: '', field: 'groupUnitId',
// data: genre
// },
{
name: '异常状态', field: 'state',
data: [
@ -165,7 +165,7 @@ const DataAlarm = ({ match, dispatch, actions, user, loading, socket, iotVcmpWeb
strategyHit: ['index', 'projectName', 'StructureName', 'SourceName', 'Strategy', 'State', 'createTime', 'sustainTime', 'AlarmContent', 'CurrentLevel', 'updateTime', 'detailCount', 'confirm', 'confirmTime'],
videoAbnormal: ['index', 'projectName', 'StructureName', 'SourceName', 'station', 'cameraKindId', 'sustainTime', 'venderName', 'point', 'cameraSerialNo', 'cameraChannelNo', 'platform', 'AlarmContent', 'resolve', 'createTime', 'updateTime', 'confirm', 'confirmTime',],
useAbnormal: ['index', 'projectName', 'appName', 'url', 'type', 'alarmContent', 'createTime', 'sustainTime', 'updateTime', 'confirm', 'confirmTime'],
deviceAbnormal: ['index', 'projectName', 'StructureName', 'SourceName', 'station', 'type', 'cameraKindId', 'sustainTime', 'venderName', 'AlarmContent', 'AlarmCodeName', 'createTime', 'updateTime', 'confirm', 'confirmTime'],
deviceAbnormal: ['index', 'projectName', 'StructureName', 'SourceName', 'station', 'sustainTime', 'venderName', 'AlarmContent', 'AlarmCodeName', 'createTime', 'updateTime', 'confirm', 'confirmTime'],
}
//
const columns = {

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

@ -54,7 +54,9 @@ export const ApiTable = {
//控制台
consoleToollink: 'console/toollink', //常用工具
deleteConsoleToollink: 'console/toollink/{linkId}', //删除常用工具
geteteConsoleCount: 'console/count', //工作台数量查询
};
export const RouteTable = {
apiRoot: "/api/root",

Loading…
Cancel
Save