'use strict'; const moment = require('moment'); async function groupList (ctx) { try { const { models } = ctx.fs.dc; const { clickHouse } = ctx.app.fs const groupRes = await clickHouse.anxinyun.query(` SELECT * FROM t_alarm_group `).toPromise(); for (let g of groupRes) { g.unit = await await clickHouse.anxinyun.query(` SELECT * FROM t_alarm_group_unit WHERE group_id = ${g.id} `).toPromise(); } ctx.status = 200; ctx.body = groupRes } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: error`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function list (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, keyword, groupId, groupUnitId, sustainTimeStart, sustainTimeEnd, limit, page } = ctx.query const isSuper = judgeSuper(ctx) let anxinStrucIds = null if (!isSuper || pepProjectId) { anxinStrucIds = await anxinStrucIdRange({ ctx, pepProjectId }) } let whereOption = [] if (anxinStrucIds) { whereOption.push(`alarms.StructureId IN (${anxinStrucIds.join(",")})`) } if (groupId) { whereOption.push(`alarms.AlarmGroup IN (${groupId})`) } if (groupUnitId) { whereOption.push(`alarms.AlarmGroupUnit=${groupId}`) } if (sustainTimeStart && sustainTimeEnd) { let momentStart = moment(sustainTimeStart).format() let momentEnd = moment(sustainTimeEnd).format() whereOption.push(` ( alarms."StartTime" BETWEEN '${momentStart}' AND '${momentEnd}' OR "alarms"."EndTime" BETWEEN '${momentStart}' AND '${momentEnd}' OR ( "alarms"."StartTime" <= '${momentStart}' AND "alarms"."EndTime" >= '${momentEnd}' ) ) `) } const alarmRes = await clickHouse.dataAlarm.query(` SELECT alarms.AlarmId AS AlarmId, alarms.State AS State, SourceName, StartTime, EndTime, alarms.CurrentLevel AS CurrentLevel, SourceTypeId, AlarmAdviceProblem, AlarmGroup, AlarmGroupUnit, AlarmAdviceProblem, ${anxinyun}.t_structure.name AS StructureName, StructureId, ${anxinyun}.t_alarm_code.name AS AlarmCodeName FROM alarms LEFT JOIN ${anxinyun}.t_structure ON ${anxinyun}.t_structure.id = alarms.StructureId LEFT JOIN ${anxinyun}.t_alarm_code ON ${anxinyun}.t_alarm_code.code = alarms.AlarmTypeCode ${whereOption.length ? 'WHERE ' + whereOption.join(' AND ') : ''} ORDER BY alarms.StartTime DESC ${limit ? 'LIMIT ' + limit : ''} ${limit && page ? 'OFFSET ' + parseInt(limit) * parseInt(page) : ''} `).toPromise(); // alarm_details.Time, alarm_details.Content // LEFT JOIN alarm_details // ON alarms.AlarmId = alarm_details.AlarmId // AND alarm_details.Time = ( // SELECT MAX(alarm_details.Time) from alarm_details WHERE AlarmId = alarms.AlarmId // ) // State = 3 是 自动恢复 / 4 是 人工恢复 / 其他数字 是 需要恢复 ctx.status = 200; ctx.body = alarmRes } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: error`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function detail (ctx) { try { const { models } = ctx.fs.dc; const { clickHouse } = ctx.app.fs const { alarmId } = ctx.query const detailRes = await clickHouse.dataAlarm.query(` SELECT * FROM alarm_details WHERE AlarmId = '${alarmId}' ORDER BY Time ASC `).toPromise() ctx.status = 200; ctx.body = detailRes } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: error`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } function confirm (opts) { return async function (ctx) { try { const { models } = ctx.fs.dc; const { utils: { kfkSendAsync } } = ctx.app.fs const { clickHouse } = ctx.app.fs const { content = '', alarmId } = ctx.request.body // 发送告警恢复通知 // Topic: alarm /* * { * messageMode: "AlarmManElimination", * sourceId: "", * alarmTypeCode: "", * sponsor: userId, * content: "确认消息", * time: "YYYY-MM-DDTHH:mm:ss.SSSZ" * } */ const alarmRes = await clickHouse.dataAlarm.query(` SELECT * FROM alarms WHERE AlarmId = '${alarmId}' `).toPromise(); if (!alarmRes.length) { throw '没有查询到对应的告警信息' } const [corAlarm] = alarmRes if ([3, 4].some(s => s == corAlarm.State)) { throw '告警信息已确认' } const message = { messageMode: "AlarmManElimination", sourceId: corAlarm.SourceId, alarmTypeCode: corAlarm.AlarmTypeCode, sponsor: opts.anxinCloud.confirmAlarmAnxinUserId, content: content, time: moment().toISOString() }; const payloads = [{ topic: `${opts.kafka.topicPrefix}_alarm`, messages: [JSON.stringify(message)], partition: 0 }]; await kfkSendAsync(payloads) ctx.status = 204; } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: error`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } } async function detailAggregation (ctx) { try { const { models } = ctx.fs.dc; const { alarmId } = ctx.query const { clickHouse } = ctx.app.fs const alarmDetailAggRes = await clickHouse.dataAlarm.query(` SELECT formatDateTime(Time,'%F %H') hours, count(AlarmId) count FROM alarm_details WHERE AlarmId=${alarmId} GROUP BY hours; `).toPromise(); ctx.status = 200; ctx.body = alarmDetailAggRes } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: error`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function alarmCount (ctx) { try { const { models } = ctx.fs.dc; const { clickHouse } = ctx.app.fs const alarmUnconfirmedAggRes = await clickHouse.dataAlarm.query(` SELECT count(AlarmId) count, AlarmGroup from alarms GROUP BY AlarmGroup; `).toPromise(); ctx.status = 200; ctx.body = alarmUnconfirmedAggRes } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: error`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } module.exports = { list, detail, groupList, confirm, detailAggregation, alarmCount, };