Browse Source

(*)问题处置效率分析定时任务暂交; 获取处置效率接口

dev
wuqun 2 years ago
parent
commit
16ab1cf6c1
  1. 22
      api/app/lib/controllers/control/data.js
  2. 98
      api/app/lib/models/alarm_handle_statistics.js
  3. 3
      api/app/lib/routes/control/index.js
  4. 550
      api/app/lib/schedule/alarms_handle_statistics.js

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

@ -209,6 +209,26 @@ async function getVideoAlarmsAggDay(ctx) {
}
}
//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 {
@ -308,5 +328,7 @@ module.exports = {
getDataAlarmsAggDay,
getAppAlarmsAggDay,
getVideoAlarmsAggDay,
getAlarmsHandleStatistics,
getLatestDynamic
};

98
api/app/lib/models/alarm_handle_statistics.js

@ -0,0 +1,98 @@
/* eslint-disable*/
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const AlarmHandleStatistics = sequelize.define("alarmHandleStatistics", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "alarm_handle_statistics_id_uindex"
},
time: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "time",
autoIncrement: false
},
projectCorrelationId: {
type: DataTypes.INTEGER,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "project_correlation_id",
autoIncrement: false
},
day1: {
type: DataTypes.DOUBLE,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "day1",
autoIncrement: false
},
day3: {
type: DataTypes.DOUBLE,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "day3",
autoIncrement: false
},
day7: {
type: DataTypes.DOUBLE,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "day7",
autoIncrement: false
},
day15: {
type: DataTypes.DOUBLE,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "day15",
autoIncrement: false
},
day30: {
type: DataTypes.DOUBLE,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "day30",
autoIncrement: false
},
day30m: {
type: DataTypes.DOUBLE,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "day30m",
autoIncrement: false
}
}, {
tableName: "alarm_handle_statistics",
comment: "",
indexes: []
});
dc.models.AlarmHandleStatistics = AlarmHandleStatistics;
return AlarmHandleStatistics;
};

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

@ -36,6 +36,9 @@ module.exports = function (app, router, opts) {
app.fs.api.logAttr['GET/video/alarms/agg/day'] = { content: '查询BI分析数据-视频异常', visible: false };
router.get('/video/alarms/agg/day', csData.getVideoAlarmsAggDay);
app.fs.api.logAttr['GET/alarms/handle/statistics'] = { content: '查询BI分析数据-问题处理效率分析', visible: false };
router.get('/alarms/handle/statistics', csData.getAlarmsHandleStatistics);
//最新动态
app.fs.api.logAttr['GET/latest/dynamic'] = { content: '查询最新动态', visible: false };
router.get('/latest/dynamic', csData.getLatestDynamic);

550
api/app/lib/schedule/alarms_handle_statistics.js

@ -0,0 +1,550 @@
'use strict';
const moment = require('moment');
const request = require('superagent');
module.exports = function (app, opts) {
const { models } = app.fs.dc
const { clickHouse, utils: { anxinStrucIdRange } } = app.fs
const { database: anxinyun } = clickHouse.anxinyun.opts.config
const alarmHandleStatistics = app.fs.scheduleInit(
{
interval: '40 8 15 * * *',
// immediate: true,
//proRun: true,
},
async () => {
try {
let time = moment().format()
let anxinStruc = await getAxyStructs()
let pomsProject = await pomsProjectRange()
if (anxinStruc.length) {
let dataAlarms = await getDataAlarms(anxinStruc);//数据告警
let appAlarms = await getAppAlarms(pomsProject);//应用告警
let videoAlarms = await getVideoAlarms(anxinStruc);//视频告警
//算全局
let dataArrToSave = []
let dataMap = calculate(dataAlarms, appAlarms, videoAlarms)
let sum = dataAlarms.length + appAlarms.length + videoAlarms.length;
if (sum) {
dataArrToSave.push({
time: time,
projectCorrelationId: null,//全局
day1: parseFloat((100 * dataMap.day1 / sum).toFixed(2)),
day3: parseFloat((100 * dataMap.day3 / sum).toFixed(2)),
day7: parseFloat((100 * dataMap.day7 / sum).toFixed(2)),
day15: parseFloat((100 * dataMap.day15 / sum).toFixed(2)),
day30: parseFloat((100 * dataMap.day30 / sum).toFixed(2)),
day30m: parseFloat((100 * dataMap.day30m / sum).toFixed(2)),
})
}
//算单个项目
//pomsProject.map(p => {
//let pid = p.id;
let pid = 26
let pDataAlarms = dataAlarms.filter(da => da.pomsProject.map(dap => dap.id).indexOf(pid) != -1)
let pAppAlarms = appAlarms.filter(aa => aa.app.projectCorrelations.map(ap => ap.id).indexOf(pid) != -1)
let pVideoAlarms = videoAlarms.filter(va => va.pomsProject.map(dap => dap.id).indexOf(pid) != -1)
let pDataMap = calculate(pDataAlarms, pAppAlarms, pVideoAlarms)
let sm = pDataAlarms.length + pAppAlarms.length + pVideoAlarms.length;
if (sm) {
dataArrToSave.push({
time: time,
projectCorrelationId: pid,//单个项目
day1: parseFloat((100 * pDataMap.day1 / sum).toFixed(2)),
day3: parseFloat((100 * pDataMap.day3 / sum).toFixed(2)),
day7: parseFloat((100 * pDataMap.day7 / sum).toFixed(2)),
day15: parseFloat((100 * pDataMap.day15 / sum).toFixed(2)),
day30: parseFloat((100 * pDataMap.day30 / sum).toFixed(2)),
day30m: parseFloat((100 * pDataMap.day30m / sum).toFixed(2)),
})
}
//})
await models.AlarmHandleStatistics.bulkCreate(dataArrToSave)
}
} catch (error) {
console.error(error);
}
}
)
function calculate(dataAlarms, appAlarms, videoAlarms) {
try {
//算全局
let dataMap = {
day1: 0,//当日处理
day3: 0,//3日内
day7: 0,//7日内
day15: 0,//15日内
day30: 0,//30日内
day30m: 0//超过30日
}
dataAlarms.filter(d => d.State > 3).map(da => {
let range = moment(da.confirmTime).diff(moment(da.StartTime), 'day')
if (range <= 1) {
dataMap.day1++
} else if (range > 1 && range <= 3) {
dataMap.day3++
} else if (range > 3 && range <= 7) {
dataMap.day7++
} else if (range > 7 && range <= 15) {
dataMap.day15++
} else if (range > 15 && range <= 30) {
dataMap.day30++
} else if (range > 30) {
dataMap.day30m++
}
})
appAlarms.filter(d => d.confirmTime).map(da => {
let range = moment(da.confirmTime).diff(moment(da.createTime), 'day')
if (range < 1) {
dataMap.day1++
} else if (range >= 1 && range < 3) {
dataMap.day3++
} else if (range >= 3 && range < 7) {
dataMap.day7++
} else if (range >= 7 && range < 15) {
dataMap.day15++
} else if (range >= 15 && range < 30) {
dataMap.day30++
} else if (range >= 30) {
dataMap.day30m++
}
})
videoAlarms.filter(d => d.confirmTime || d.autoRestore).map(da => {
let range = moment(da.confirmTime).diff(moment(da.createTime), 'day')
if (range < 1) {
dataMap.day1++
} else if (range >= 1 && range < 3) {
dataMap.day3++
} else if (range >= 3 && range < 7) {
dataMap.day7++
} else if (range >= 7 && range < 15) {
dataMap.day15++
} else if (range >= 15 && range < 30) {
dataMap.day30++
} else if (range >= 30) {
dataMap.day30m++
}
})
return dataMap;
} catch (error) {
console.error(error);
}
}
async function getDataAlarms(anxinStruc) {
try {
const anxinStrucIds = anxinStruc.map(a => a.strucId)
let whereOption = []
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
LEFT JOIN ${anxinyun}.t_structure
ON ${anxinyun}.t_structure.id = alarms.StructureId
${whereOption.length ? 'WHERE ' + whereOption.join(' AND ') : ''}`
const alarmRes = await clickHouse.dataAlarm.query(`
SELECT
alarms.AlarmId AS AlarmId,
alarms.State AS State,
alarms.StructureId AS StructureId,
SourceName, StartTime, EndTime
${alarmQueryOptionStr}`).toPromise();
const confirmedAlarm = alarmRes.filter(ar => ar.State && ar.State > 2).map(ar => "'" + ar.AlarmId + "'");
const confirmedAlarmDetailMax = confirmedAlarm.length ?
await clickHouse.dataAlarm.query(`
SELECT
max(Time) AS Time, AlarmId , max(Content) AS Content
FROM
alarm_details
WHERE
AlarmId IN (${confirmedAlarm.join(',')})
GROUP BY AlarmId
`).toPromise() : [];
alarmRes.forEach(ar => {
ar.pomsProject = (
anxinStruc.find(as => as.strucId == ar.StructureId) ||
{
pomsProject: [
// TODO: 开发临时添加
]
}
).pomsProject
// 最新告警详情 - 确认信息
let corConfirmedData = (confirmedAlarmDetailMax.find(cdm => cdm.AlarmId == ar.AlarmId) || {});
ar.confirmTime = corConfirmedData.Time || ar.EndTime
})
return alarmRes;
} catch (error) {
console.error(error);
}
}
async function getAppAlarms(pomsProject) {
try {
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: {
exclude: ['projectId']
},
include: [{
model: models.ProjectCorrelation,
attributes: ['id']
}]
}]
}
findOption.where['$app->projectCorrelations.id$'] = {
$in: pomsProjectIds
}
const listRes = await models.AppAlarm.findAll(findOption)
return listRes
} catch (error) {
console.error(error);
}
}
async function getVideoAlarms(anxinStruc) {
try {
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 alarmRes = anxinStrucIds.length ? await clickHouse.vcmp.query(
`
SELECT
cameraAlarm.cameraId AS cameraId,
cameraAlarm.cameraName AS cameraName,
cameraAlarm.cameraKindId AS cameraKindId,
cameraAlarm.venderId AS venderId,
cameraAlarm.venderName AS venderName,
cameraAlarm.cameraSerialNo AS cameraSerialNo,
cameraAlarm.cameraChannelNo AS cameraChannelNo,
cameraAlarm.alarmId AS alarmId,
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.name AS cameraName,
camera.kind_id AS cameraKindId,
camera.vender_id AS venderId,
camera.yingshi_secret_id AS yingshiSecretId,
vender.name AS venderName,
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 = false
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
`).toPromise() : []
let returnD = []
let positionD = {}
// 每个设备一个告警
for (let a of alarmRes) {
if (positionD[a.cameraId]) {
let curD = returnD[positionD[a.cameraId].positionReturnD]
if (a.resolveId && !curD.resolve.some(r => r.id == a.resolveId)) {
curD.resolve.push({
id: a.resolveId,
resolve: a.resolve
})
}
if (a.strucId && !curD.struc.some(s => s.id == a.strucId)) {
curD.struc.push({
id: a.strucId,
projectId: a.projectId,
name: a.strucName
})
}
if (a.anxinStationId && !curD.station.some(s => s.id == a.anxinStationId)) {
curD.station.push({
id: a.anxinStationId,
name: a.anxinStationName,
position: a.anxinIpcPosition
})
}
} else {
let d = {
cameraId: a.cameraId,
cameraName: a.cameraName,
camerOnline: a.cameraOnline,
cameraSerialNo: a.cameraSerialNo,
cameraChannelNo: a.cameraChannelNo,
autoRestore: a.autoRestore,
createTime: a.createTime,
updateTime: a.updateTime,
platform: a.platform,
statusDescribe: a.statusDescribe,
alarmId: a.alarmId,
confirmContent: a.confirmContent,
confirmTime: a.confirmTime,
venderId: a.venderId,
venderName: a.venderName,
cameraKindId: a.cameraKindId,
yingshiToken: a.yingshiToken,
resolve: [],
struc: [],
station: []
}
// pep 项目
d.pomsProject = (
anxinStruc.find(as => as.strucId == a.strucId) ||
{
pomsProject: [
]
}
).pomsProject
if (a.resolveId) {
d.resolve.push({
id: a.resolveId,
resolve: a.resolve
})
}
if (a.strucId) {
d.struc.push({
id: a.strucId,
projectId: a.projectId,
name: a.strucName
})
}
if (a.anxinStationId) {
d.station.push({
id: a.anxinStationId,
name: a.anxinStationName,
position: a.anxinIpcPosition
})
}
returnD.push(d)
positionD[a.cameraId] = {
positionReturnD: returnD.length - 1
}
}
}
return returnD;
} catch (error) {
console.error(error);
}
}
async function pomsProjectRange() {
try {
const { pepProjectRes, bindRes } = await pomsWithPepRangeParams()
let pomsProject = []
for (let b of bindRes) {
if (b.pepProjectId) {
let corPepProject = pepProjectRes.find(pp => pp.id == b.pepProjectId) || {}
pomsProject.push({
...b.dataValues,
pepProject: corPepProject
})
} else {
pomsProject.push({
...b.dataValues
})
}
}
return pomsProject
} catch (error) {
console.error(error);
}
}
async function pomsWithPepRangeParams() {
try {
const bindRes = await models.ProjectCorrelation.findAll({ where: { del: false } });
// 获取不重复的 项企项目id
let pepProjectIds = []
for (let b of bindRes) {
if (b.pepProjectId) {
pepProjectIds.push(b.pepProjectId)
}
}
// 查询项企项目的信息
const pepProjectRes = pepProjectIds.length ?
await clickHouse.projectManage.query(
`SELECT
t_pim_project.id AS id,
t_pim_project.project_name AS projectName,
t_pim_project.isdelete AS isdelete,
t_pim_project_construction.construction_status_id AS constructionStatusId,
t_pim_project_state.construction_status AS constructionStatus
FROM
t_pim_project
LEFT JOIN t_pim_project_construction
ON t_pim_project.id = t_pim_project_construction.project_id
LEFT JOIN t_pim_project_state
ON t_pim_project_construction.construction_status_id = t_pim_project_state.id
WHERE
id IN (${pepProjectIds.join(',')})`
).toPromise() : [];
return {
pepProjectRes, bindRes
}
} catch (error) {
console.error(error);
}
}
async function getAxyStructs() {
try {
const { pepProjectRes, bindRes } = await pomsWithPepRangeParams()
// 获取不重复的 安心云项目 id
const anxinProjectIds = [
...(bindRes).reduce(
(arr, b) => {
for (let sid of b.anxinProjectId) {
arr.add(sid);
}
return arr;
},
new Set()
)
]
// 查询安心云项目及结构物信息
const undelStrucRes = anxinProjectIds.length ?
await clickHouse.anxinyun.query(
`SELECT
t_project.id AS projectId,
t_structure.id AS strucId,
t_structure.name AS strucName,
project_state
FROM
t_project
LEFT JOIN
t_project_structure
ON t_project_structure.project = t_project.id
LEFT JOIN
t_project_structuregroup
ON t_project_structuregroup.project = t_project.id
LEFT JOIN
t_structuregroup_structure
ON t_structuregroup_structure.structuregroup = t_project_structuregroup.structuregroup
LEFT JOIN
t_project_construction
ON t_project_construction.project = t_project.id
LEFT JOIN
t_structure_site
ON t_structure_site.siteid = t_project_construction.construction
RIGHT JOIN
t_structure
ON t_structure.id = t_project_structure.structure
OR t_structure.id = t_structuregroup_structure.structure
OR t_structure.id = t_structure_site.structid
WHERE
project_state != -1
AND
t_project.id IN (${anxinProjectIds.join(',')})`).toPromise() : []
// 构建安心云结构物和项企项目的关系
// 并保存信息至数据
let undelStruc = []
for (let s of undelStrucRes) {
if (!undelStruc.some(us => us.strucId == s.strucId)) {
let pomsProject = []
for (let { dataValues: br } of bindRes) {
if (br.anxinProjectId.some(braId => braId == s.projectId)) {
let corPepProject = pepProjectRes.find(pp => pp.id == br.pepProjectId)
pomsProject.push({
...br,
pepProject: corPepProject
})
}
}
undelStruc.push({
strucId: s.strucId,
strucName: s.strucName,
projectId: s.projectId,
pomsProject: pomsProject
})
}
}
return undelStruc
} catch (error) {
console.error(error);
}
}
return {
alarmHandleStatistics
}
}
Loading…
Cancel
Save