You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
399 lines
15 KiB
399 lines
15 KiB
'use strict';
|
|
const moment = require('moment');
|
|
|
|
//BI分析-数据
|
|
async function getDataAlarmsAggDay (ctx) {
|
|
try {
|
|
const { utils: { anxinStrucIdRange } } = ctx.app.fs
|
|
const { pepProjectId } = ctx.query
|
|
|
|
let dataAbnormal = [], dataInterrupt = [], policyHit = [], deviceAbnormal = [];
|
|
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(",")})`)
|
|
|
|
let start = moment().add(-1, 'year').format('YYYY-MM-DD HH:mm:ss');//最近一年
|
|
whereOption.push(`alarms.StartTime >= '${start}'`)
|
|
|
|
let alarmQueryOptionStr = `
|
|
FROM alarms
|
|
${whereOption.length ? 'WHERE ' + whereOption.join(' AND ') : ''}
|
|
`
|
|
dataAbnormal = await queryAlarm(ctx, alarmQueryOptionStr, [2]);//数据异常
|
|
dataInterrupt = await queryAlarm(ctx, alarmQueryOptionStr, [1]);//数据中断
|
|
policyHit = await queryAlarm(ctx, alarmQueryOptionStr, [3]);//策略命中
|
|
deviceAbnormal = await queryAlarm(ctx, alarmQueryOptionStr, [4, 5]);//设备异常
|
|
}
|
|
ctx.status = 200;
|
|
ctx.body = { dataAbnormal, dataInterrupt, policyHit, deviceAbnormal };
|
|
} catch (error) {
|
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
|
|
ctx.status = 400;
|
|
ctx.body = {
|
|
message: typeof error == 'string' ? error : undefined
|
|
}
|
|
}
|
|
}
|
|
|
|
async function queryAlarm (ctx, alarmQueryOptionStr, type) {
|
|
const { clickHouse } = ctx.app.fs
|
|
try {
|
|
const alarmRes = await clickHouse.dataAlarm.query(`
|
|
select days day, sum(count) total, sum(done) done from (
|
|
|
|
SELECT formatDateTime(StartTime,'%F') days, count(AlarmId) count, 0 done from
|
|
(SELECT
|
|
alarms.AlarmId AS AlarmId,
|
|
alarms.State AS State,
|
|
StartTime,
|
|
AlarmGroup
|
|
${alarmQueryOptionStr} and alarms.AlarmGroup in [${type}]) group by days
|
|
|
|
union all (SELECT formatDateTime(StartTime,'%F') days, 0 count, count(AlarmId) done from
|
|
(SELECT
|
|
alarms.AlarmId AS AlarmId,
|
|
alarms.State AS State,
|
|
StartTime,
|
|
AlarmGroup
|
|
${alarmQueryOptionStr} and alarms.AlarmGroup in [${type}] and alarms.State > 2) group by days)
|
|
|
|
) group by days ORDER BY days
|
|
`).toPromise();
|
|
return alarmRes;
|
|
} catch (error) {
|
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
|
|
ctx.status = 400;
|
|
ctx.body = {
|
|
message: typeof error == 'string' ? error : undefined
|
|
}
|
|
}
|
|
}
|
|
|
|
//BI分析-应用异常
|
|
async function getAppAlarmsAggDay (ctx) {
|
|
try {
|
|
const models = ctx.fs.dc.models;
|
|
const { utils: { pomsProjectRange } } = ctx.app.fs
|
|
const { pepProjectId } = ctx.query
|
|
|
|
let pomsProject = await pomsProjectRange({
|
|
ctx, pepProjectId
|
|
})
|
|
const pomsProjectIds = pomsProject.map(p => p.id)
|
|
let findOption = {
|
|
where: {
|
|
createTime: { $gte: moment().add(-1, 'year').format() },//最近一年
|
|
},
|
|
attributes: ['id', 'createTime', 'confirmTime'],
|
|
include: [{
|
|
model: models.App,
|
|
attributes: ['id'],
|
|
include: [{
|
|
model: models.ProjectCorrelation,
|
|
attributes: ['id']
|
|
}]
|
|
}]
|
|
}
|
|
findOption.where['$app->projectCorrelations.id$'] = {
|
|
$in: pomsProjectIds
|
|
}
|
|
const listRes = await models.AppAlarm.findAll(findOption)
|
|
let aggDayMap = [];
|
|
for (let a of listRes) {
|
|
let exist = aggDayMap.find(ad => ad.day == moment(a.createTime).format('YYYY-MM-DD'));
|
|
if (exist) {
|
|
exist.total++;//总数
|
|
if (a.confirmTime) {
|
|
exist.done++;//已恢复
|
|
}
|
|
} else {
|
|
aggDayMap.push({ day: moment(a.createTime).format('YYYY-MM-DD'), total: 1, done: a.confirmTime ? 1 : 0 });
|
|
}
|
|
}
|
|
aggDayMap.sort((a, b) => moment(a.day) - moment(b.day));//升序
|
|
ctx.status = 200;
|
|
ctx.body = aggDayMap;
|
|
} catch (error) {
|
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
|
|
ctx.status = 400;
|
|
ctx.body = {
|
|
message: typeof error == 'string' ? error : undefined
|
|
}
|
|
}
|
|
}
|
|
|
|
//BI分析-视频异常
|
|
async function getVideoAlarmsAggDay (ctx) {
|
|
try {
|
|
const { clickHouse, utils: { anxinStrucIdRange } } = ctx.app.fs
|
|
const { database: anxinyun } = clickHouse.anxinyun.opts.config
|
|
const { pepProjectId } = ctx.query
|
|
let anxinStruc = await anxinStrucIdRange({
|
|
ctx, pepProjectId
|
|
})
|
|
const anxinStrucIds = anxinStruc.map(a => a.strucId)
|
|
let statusAlarmWhereOption = []
|
|
let start = moment().add(-1, 'year').format('YYYY-MM-DD HH:mm:ss');//最近一年
|
|
statusAlarmWhereOption.push(`camera_status_alarm.create_time >= '${start}'`)
|
|
|
|
const videoAlarms = anxinStrucIds.length ? await clickHouse.vcmp.query(
|
|
`SELECT
|
|
cameraAlarm.cameraId AS cameraId,
|
|
cameraAlarm.alarmId AS alarmId,
|
|
cameraAlarm.createTime AS createTime,
|
|
cameraAlarm.confirmTime AS confirmTime,
|
|
${'cameraAlarm.autoRestore AS autoRestore,'}
|
|
anxinStruc.id AS strucId
|
|
FROM
|
|
(
|
|
SELECT
|
|
camera.id AS cameraId,
|
|
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.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
|
|
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(',')}, -1)`}
|
|
)
|
|
) 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 ${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(',')}, -1)
|
|
LEFT JOIN ${anxinyun}.t_video_ipc_station AS anxinIpcStation
|
|
ON anxinIpcStation.ipc = anxinIpc.id
|
|
`).toPromise() : []
|
|
|
|
let returnD = []
|
|
let positionD = {}
|
|
// 每个设备一个告警
|
|
for (let a of videoAlarms) {
|
|
if (positionD[a.cameraId]) {
|
|
} else {
|
|
let d = {
|
|
cameraId: a.cameraId,
|
|
autoRestore: a.autoRestore,
|
|
createTime: a.createTime,
|
|
alarmId: a.alarmId,
|
|
confirmTime: a.confirmTime,
|
|
}
|
|
d.pomsProject = (
|
|
anxinStruc.find(as => as.strucId == a.strucId) ||
|
|
{
|
|
pomsProject: [
|
|
|
|
]
|
|
}
|
|
).pomsProject.map(d => d.id)
|
|
returnD.push(d)
|
|
positionD[a.cameraId] = {
|
|
positionReturnD: returnD.length - 1
|
|
}
|
|
}
|
|
}
|
|
let aggDayMap = [];
|
|
for (let a of returnD) {
|
|
let exist = aggDayMap.find(ad => ad.day == moment(a.createTime).format('YYYY-MM-DD'));
|
|
if (exist) {
|
|
exist.total++;//总数
|
|
if (a.confirmTime || a.autoRestore) {
|
|
exist.done++;//已恢复
|
|
}
|
|
} else {
|
|
aggDayMap.push({ day: moment(a.createTime).format('YYYY-MM-DD'), total: 1, done: a.confirmTime || a.autoRestore ? 1 : 0 });
|
|
}
|
|
}
|
|
ctx.status = 200;
|
|
ctx.body = aggDayMap;
|
|
} catch (error) {
|
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
|
|
ctx.status = 400;
|
|
ctx.body = {
|
|
message: typeof error == 'string' ? error : undefined
|
|
}
|
|
}
|
|
}
|
|
|
|
//BI分析-问题处置效率分析
|
|
async function getAlarmsHandleStatistics (ctx) {
|
|
try {
|
|
const { projectCorrelationId } = ctx.query
|
|
const models = ctx.fs.dc.models;
|
|
const data = await models.AlarmHandleStatistics.findAll({
|
|
order: [['time', 'DESC']],
|
|
where: projectCorrelationId ? { projectCorrelationId: projectCorrelationId } : {},
|
|
limit: 1
|
|
})
|
|
ctx.status = 200;
|
|
ctx.body = data;
|
|
} catch (error) {
|
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
|
|
ctx.status = 400;
|
|
ctx.body = {
|
|
message: typeof error == 'string' ? error : undefined
|
|
}
|
|
}
|
|
}
|
|
//最新动态
|
|
async function getLatestDynamic (ctx) {
|
|
try {
|
|
const { models } = ctx.fs.dc;
|
|
const { limit, page, projectCorrelationId, types } = ctx.query;
|
|
const { userInfo } = ctx.fs.api;
|
|
const { clickHouse } = ctx.app.fs;
|
|
|
|
let where = { type: { $in: types.split(',') } }//传类型选择
|
|
if (!userInfo.role.includes('SuperAdmin') && !userInfo.role.includes('admin')) {
|
|
where.projectCorrelationId = { $in: userInfo.correlationProject }
|
|
}
|
|
if (projectCorrelationId) {//查指定项目,控制台全局切换
|
|
where.projectCorrelationId = projectCorrelationId
|
|
}
|
|
let news = await models.LatestDynamicList.findAll({//最新动态
|
|
include: [{
|
|
model: models.ProjectCorrelation,
|
|
where: { del: false },
|
|
attributes: ['id', 'name', 'pepProjectId'],
|
|
}, {
|
|
model: models.AlarmAppearRecord
|
|
}, {
|
|
model: models.EmailSendLog,
|
|
include: [{
|
|
model: models.AlarmPushConfig,
|
|
attributes: ['id', 'name'],
|
|
}]
|
|
}, {
|
|
model: models.AlarmConfirmLog
|
|
}],
|
|
where: where,
|
|
offset: Number(page) * Number(limit),
|
|
limit: Number(limit),
|
|
order: [['time', 'desc']],
|
|
});
|
|
|
|
//查项目名称 查用户名
|
|
let pepPojectIds = new Set(), notedUserIds = new Set(), emailSendPomsProjectIds = new Set();
|
|
for (let p of news) {
|
|
if (p.projectCorrelation && p.projectCorrelation.pepProjectId) {
|
|
pepPojectIds.add(p.projectCorrelation.pepProjectId);
|
|
}
|
|
|
|
if (p.emailSendLog) {
|
|
p.emailSendLog.toPepUserIds.map(u => {
|
|
notedUserIds.add(u);//通知 接收人
|
|
})
|
|
p.emailSendLog.projectCorrelationId.forEach(pid => emailSendPomsProjectIds.add(pid))
|
|
}
|
|
if (p.alarmConfirmLog && p.alarmConfirmLog.pepUserId) {
|
|
notedUserIds.add(p.alarmConfirmLog.pepUserId);//确认 操作者
|
|
}
|
|
}
|
|
|
|
// EM 推送的特殊处理
|
|
// 查找对应的 projectCorrelation
|
|
const emailLogProjectCorrelationRes =
|
|
emailSendPomsProjectIds.size ?
|
|
await models.ProjectCorrelation.findAll({
|
|
where: {
|
|
id: { $in: [...emailSendPomsProjectIds] }
|
|
}
|
|
}) : []
|
|
|
|
for (let { dataValues: p } of emailLogProjectCorrelationRes) {
|
|
if (p.pepProjectId) {
|
|
pepPojectIds.add(p.pepProjectId)
|
|
}
|
|
}
|
|
let pepProjects = pepPojectIds.size ? await clickHouse.projectManage.query(`
|
|
SELECT id, project_name FROM t_pim_project WHERE id IN (${[...pepPojectIds].join(',')},-1)
|
|
`).toPromise() : [];
|
|
|
|
let userPepRes = notedUserIds.size ? await clickHouse.pepEmis.query(
|
|
`SELECT DISTINCT user.id AS id, "user"."name" AS name FROM user WHERE user.id IN (${[...notedUserIds].join(',')},-1)
|
|
`).toPromise() : []
|
|
|
|
|
|
let appear = [], notice = [], confirm = [];
|
|
news.map(d => {
|
|
let projectName = d.projectCorrelation.name || pepProjects.find(pp => pp.id == d.projectCorrelation.pepProjectId).project_name;
|
|
if (d.alarmAppearId) {
|
|
appear.push({
|
|
projectName,
|
|
...d.alarmAppearRecord.dataValues
|
|
});
|
|
}
|
|
if (d.emailSendId) {
|
|
notice.push({
|
|
userName: userPepRes.filter(u => d.emailSendLog.toPepUserIds.indexOf(u.id) != -1),
|
|
projectName: d.emailSendLog.projectCorrelationId.map(p => {
|
|
let projectName = ''
|
|
if (p.pepProjectId) {
|
|
projectName = pepProjects.find(pp => pp.id == p.pepProjectId).project_name
|
|
} else {
|
|
projectName = p.name
|
|
}
|
|
return projectName
|
|
}).join('、'),
|
|
...d.emailSendLog.dataValues
|
|
});
|
|
}
|
|
if (d.alarmConfirmId) {
|
|
confirm.push({
|
|
userName: d.alarmConfirmLog.pepUserId ? userPepRes.find(u => u.id == d.alarmConfirmLog.pepUserId).name : '自动恢复',
|
|
projectName,
|
|
...d.alarmConfirmLog.dataValues
|
|
});
|
|
}
|
|
})
|
|
ctx.status = 200;
|
|
ctx.body = {
|
|
appear,//发现
|
|
notice,//通知
|
|
confirm//确认
|
|
};
|
|
} catch (error) {
|
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
|
|
ctx.status = 400;
|
|
ctx.body = {
|
|
message: typeof error == 'string' ? error : undefined
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
getDataAlarmsAggDay,
|
|
getAppAlarmsAggDay,
|
|
getVideoAlarmsAggDay,
|
|
getAlarmsHandleStatistics,
|
|
|
|
getLatestDynamic
|
|
};
|