'use strict'; const moment = require('moment'); async function personnelApp (ctx) { try { const models = ctx.fs.dc.models; const { clickHouse } = ctx.app.fs const sequelize = ctx.fs.dc.orm; const { userId, pepUserId, userInfo, pepUserInfo } = ctx.fs.api const { pepId } = ctx.query const excludeField = ['lastInTime', 'inTimes', 'onlineDuration', 'lastInAddress', 'deleted', 'updateTime'] let findOption = { attributes: { exclude: excludeField, // include: [[sequelize.fn('array_length', sequelize.col('role')), 'roleCount']] }, where: { deleted: false, $or: [{ $not: { role: { $contained: ['SuperAdmin', 'admin'] } } }, sequelize.where(sequelize.fn('cardinality', sequelize.col('role')), 0)], // $not: { // role: { $contained: ['SuperAdmin', 'admin'] } // } }, order: [['updateTime', 'DESC']] } const userRes = await models.User.findAndCountAll(findOption) const adminRes = await models.User.findAll({ where: { role: { $contains: ['admin'] } }, attributes: { exclude: excludeField, }, order: [['updateTime', 'DESC']] }) let userIds = new Set() let pomsProjectIds = new Set() for (let u of userRes.rows.concat(adminRes)) { userIds.add(u.pepUserId) for (let pid of u.correlationProject) { pomsProjectIds.add(pid) } } // 查用户所属的项企pep的部门、人员信息 let userPepRes = userIds.size ? await clickHouse.pepEmis.query(` SELECT DISTINCT user.id AS id, "user"."name" AS name, department.name AS depName, department.id AS depId FROM department_user LEFT JOIN user ON department_user.user=user.id LEFT JOIN department ON department.id=department_user.department WHERE user.id IN (${[...userIds].join(',')}, -1) AND department.delete='0'` ).toPromise() : [] // 查用户绑定的当前系统的项目 id let pomsProjectRes = await models.ProjectCorrelation.findAll({ where: { id: { $in: [...pomsProjectIds] }, // del: false } }) // 获取响应的绑定的 项企项目的 id let pepPojectIds = new Set() for (let p of pomsProjectRes) { if (p.pepProjectId && !isNaN(p.pepProjectId)) { pepPojectIds.add(p.pepProjectId) } } // 查对应的项企项目信息 let pepProjectRes = pepPojectIds.size ? await clickHouse.projectManage.query(` SELECT id, project_name, isdelete FROM t_pim_project WHERE id IN (${[...pepPojectIds].join(',')}, -1) `).toPromise() : [] // 遍历用户并将查到的信息拼合 for (let u of userRes.rows.concat(adminRes)) { // 用户信息 const corUsers = userPepRes.filter(up => up.id == u.pepUserId) u.dataValues.name = corUsers.length ? corUsers[0].name : '' u.dataValues.departments = corUsers.length ? corUsers.map(cu => { return { name: cu.depName, id: cu.depId } }) : [] // pep项目信息 u.dataValues.correlationProject = u.dataValues.correlationProject.map(cpid => { let returnData = { id: cpid, } const corPomsProject = pomsProjectRes.find(ppr => ppr.id == cpid) if (corPomsProject) { returnData.name = corPomsProject.name returnData.del = corPomsProject.del if (corPomsProject.pepProjectId) { returnData.pepProjectId = corPomsProject.pepProjectId const corPepProject = pepProjectRes.find(ppr => ppr.id == corPomsProject.pepProjectId) if (corPepProject) { returnData.pepProjectName = corPepProject.project_name returnData.pepIsdelete = corPepProject.isdelete } } } return returnData }) } let findOptions = { where: { del: false }, order: [['updateTime', 'desc']], attributes: ['id', 'pepProjectId', 'name', 'anxinProjectId'], distinct: true, include: { model: models.App, } } if (!userInfo.role.includes('SuperAdmin') && !userInfo.role.includes('admin')) { findOptions.where.id = { $in: userInfo.correlationProject } } if (pepId) { findOptions.where.id = { $in: pepId.split(',') } } const proRes = await models.ProjectCorrelation.findAndCountAll(findOptions) let pepProjectIds = new Set() let anxinProjectIds = new Set() for (let p of proRes.rows) { if (p.pepProjectId) { pepProjectIds.add(p.pepProjectId) } for (let ap of p.anxinProjectId) { if (ap) { anxinProjectIds.add(ap) } } } const pepProjectRess = pepProjectIds.size ? await clickHouse.projectManage.query( ` SELECT t_pim_project.id AS id, t_pim_project.project_name AS project_name, t_pim_project.isdelete AS isdelete, t_pim_project_construction.construction_status_id AS construction_status_id, t_pim_project_state.construction_status AS construction_status 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(',')}, -1) ` ).toPromise() : [] for (let p of proRes.rows) { const corPro = pepProjectRess.find(pp => pp.id == p.pepProjectId) || {} p.dataValues.pepProjectName = corPro.project_name p.dataValues.pepProjectIsDelete = corPro.isdelete delete p.dataValues.anxinProjectId } let webApp = [] let appproRes = proRes.rows.filter(v => v.dataValues.pepProjectIsDelete != 1).map(r => { if (r.dataValues.apps.length > 0) { r.dataValues.apps.map(vv => { if (!webApp.map(n => n.name).includes(vv.dataValues.name)) { webApp.push({ name: vv.dataValues.name, url: vv.dataValues.url }) } }) } }) let personnel = userRes.rows.filter(r => r.correlationProject.length > 0) if (pepId) { let pepIds = pepId.split(',') personnel = personnel.filter(r => r.dataValues.correlationProject.map(v => v.id).some(pepId => pepIds.includes(pepId))) } ctx.status = 200 ctx.body = { personnel: personnel.map(v => ({ name: v.dataValues.name, department: v.dataValues.departments.map(r => r.name) })), webApp: webApp } } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { } } } async function problem (ctx) { try { const { models } = ctx.fs.dc; const { clickHouse } = ctx.app.fs const { utils: { pomsProjectRange, anxinStrucIdRange } } = ctx.app.fs const { database: anxinyun } = clickHouse.anxinyun.opts.config const { pepProjectId, limit = 50, page = 0 } = ctx.query let anxinStruc = await anxinStrucIdRange({ ctx, pepProjectId }) let pomsProject = await pomsProjectRange({ ctx, pepProjectId, }) const pomsProjectIds = pomsProject.map(p => p.id) let whereOption = [] if (anxinStruc.length) { const anxinStrucIds = anxinStruc.map(a => a.strucId) whereOption.push(`alarms.StructureId IN (${anxinStrucIds.join(",")}, -1)`) const alarmRes = await clickHouse.dataAlarm.query(` SELECT AlarmId,State,AlarmGroup,AlarmGroupUnit,SourceName,StartTime,${anxinyun}.t_alarm_group_unit.name AS typeName FROM alarms LEFT JOIN ${anxinyun}.t_alarm_group_unit ON ${anxinyun}.t_alarm_group_unit.id = alarms.AlarmGroupUnit ${whereOption.length ? 'WHERE ' + whereOption.join(' AND ') + ' AND ' + 'alarms.State < 3' : ''} ${limit ? 'LIMIT ' + limit : ''} ${limit && page ? 'OFFSET ' + parseInt(limit) * parseInt(page) : ''} `).toPromise(); alarmRes.forEach(ar => { switch (ar.AlarmGroup) { case 1: ar.groupName = '数据中断' ar.url = '/problem/dataAlarm/dataLnterrupt' break; case 2: ar.groupName = '数据异常' ar.url = '/problem/dataAlarm/dataAbnormal' break; case 3: ar.groupName = '策略命中' ar.url = '/problem/dataAlarm/strategyHit' break; default: ar.groupName = '设备异常' ar.url = '/problem/deviceAlarm/deviceAbnormal' break; } }) const video = anxinStrucIds.length ? await clickHouse.vcmp.query( ` SELECT cameraAlarm.cameraId AS cameraId, cameraAlarm.cameraName AS cameraName, cameraAlarm.alarmId AS alarmId, cameraAlarm.createTime AS createTime, cameraAlarm.confirmTime AS confirmTime FROM ( SELECT camera.id AS cameraId, 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 WHERE camera.delete = '0' 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(',')}, -1)`} ) ${limit ? 'LIMIT ' + limit : ''} ${limit && page ? 'OFFSET ' + parseInt(limit) * parseInt(page) : ''} ) 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_video_ipc_station AS anxinIpcStation ON anxinIpcStation.ipc = anxinIpc.id WHERE cameraAlarm.confirmTime is null ` ).toPromise() : [] let returnD = [] let positionD = {} // 每个设备一个告警 for (let a of video) { if (!positionD[a.cameraId]) { let d = { cameraId: a.cameraId, SourceName: a.cameraName, StartTime: a.createTime, alarmId: a.alarmId, } returnD.push(d) positionD[a.cameraId] = { positionReturnD: returnD.length - 1 } } } returnD.forEach(v => { v.groupName = '视频异常' v.url = '/problem/dataAlarm/videoAbnormal' }) let findOption = { where: { '$app->projectCorrelations.id$': { $in: pomsProjectIds }, confirmTime: null }, attributes: ['createTime', 'type'], include: [{ model: models.App, where: { }, attributes: ['id', 'name'], include: [{ model: models.ProjectCorrelation, where: { }, attributes: ['id'], }] }] } const listRes = await models.AppAlarm.findAndCountAll(findOption) let app = listRes.rows.map(v => ({ StartTime: v.createTime, SourceName: v.app.name, type: v.type })) let typeData = { element: '元素异常', apiError: "接口报错", timeout: '加载超时' } app.forEach(v => { v.groupName = '应用异常' v.url = '/problem/useAlarm/useAbnormal', v.typeName = typeData[v.type] }) let sum = [...alarmRes, ...returnD, ...app] sum.sort((a, b) => { if (moment(a.StartTime).isBefore(b.StartTime)) { return 1 } else { return -1 } }) ctx.status = 200; ctx.body = sum } 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 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, strucId } = ctx.query let anxinStruc = await anxinStrucIdRange({ ctx, pepProjectId }) if (anxinStruc.length) { const anxinStrucIds = [strucId ? strucId : anxinStruc[0].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: [] } } const sensor = anxinStrucIds.length ? await clickHouse.anxinyun.query( `SELECT id,structure,name FROM t_sensor INNER JOIN t_structure ON t_structure.id = t_sensor.structure WHERE t_sensor.structure IN (${anxinStrucIds.join(',')})` ).toPromise() : [] for (let data of sensor) { let curSeries = seriesRes.hits.hits .filter((h) => h._source.sensor == data.id) .map(s => { return { ...s._source, } }) let struc = anxinStruc.find((h) => h.strucId == data.structure) data.series = curSeries data.struc = struc } ctx.status = 200; ctx.body = { sensor: sensor || [], anxinStruc: anxinStruc || [] }; } else { ctx.status = 200; ctx.body = { sensor: [], anxinStruc: [] }; } } 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, getAlarmData, getAlarmVideo, getAlarmUse, getStatisticOnline, getStrucSeries, }