|
@ -4,7 +4,7 @@ let isDev = false |
|
|
// isDev = true
|
|
|
// isDev = true
|
|
|
|
|
|
|
|
|
let proDebug = false |
|
|
let proDebug = false |
|
|
proDebug = true |
|
|
// proDebug = true
|
|
|
|
|
|
|
|
|
module.exports = function (app, opts) { |
|
|
module.exports = function (app, opts) { |
|
|
const alarmsPush = app.fs.scheduleInit( |
|
|
const alarmsPush = app.fs.scheduleInit( |
|
@ -16,6 +16,7 @@ module.exports = function (app, opts) { |
|
|
async () => { |
|
|
async () => { |
|
|
try { |
|
|
try { |
|
|
const { models, ORM: sequelize } = app.fs.dc |
|
|
const { models, ORM: sequelize } = app.fs.dc |
|
|
|
|
|
const { apMergeDeVeAnxinProjectId = '' } = opts |
|
|
const { clickHouse } = app.fs |
|
|
const { clickHouse } = app.fs |
|
|
const { database: anxinyun } = clickHouse.anxinyun.opts.config |
|
|
const { database: anxinyun } = clickHouse.anxinyun.opts.config |
|
|
const { pushBySms, pushByEmail, sendNoticeToWeb } = app.fs.utils |
|
|
const { pushBySms, pushByEmail, sendNoticeToWeb } = app.fs.utils |
|
@ -73,7 +74,7 @@ module.exports = function (app, opts) { |
|
|
const { interval, deviceProportion } = c.tacticsParams |
|
|
const { interval, deviceProportion } = c.tacticsParams |
|
|
|
|
|
|
|
|
if ( |
|
|
if ( |
|
|
curMinOfYear % parseInt(interval) == 0 |
|
|
curMinOfYear % parseInt(interval) == 0 || isDev |
|
|
) { |
|
|
) { |
|
|
|
|
|
|
|
|
const corPomsProject = pomsProjectRes.filter(poms => pomsProjectId.includes(poms.id)) |
|
|
const corPomsProject = pomsProjectRes.filter(poms => pomsProjectId.includes(poms.id)) |
|
@ -110,7 +111,8 @@ module.exports = function (app, opts) { |
|
|
DISTINCT id, |
|
|
DISTINCT id, |
|
|
t_structure.id AS id, |
|
|
t_structure.id AS id, |
|
|
t_structure.name AS name, |
|
|
t_structure.name AS name, |
|
|
t_structure.iota_thing_id AS iotaThingId |
|
|
t_structure.iota_thing_id AS iotaThingId, |
|
|
|
|
|
t_project.id AS projectId |
|
|
FROM |
|
|
FROM |
|
|
t_project |
|
|
t_project |
|
|
LEFT JOIN |
|
|
LEFT JOIN |
|
@ -141,10 +143,14 @@ module.exports = function (app, opts) { |
|
|
).toPromise() : |
|
|
).toPromise() : |
|
|
[] |
|
|
[] |
|
|
let strucThingId = [] |
|
|
let strucThingId = [] |
|
|
|
|
|
let strucMap = {} |
|
|
let searchStrucIds = strucListRes.map(s => { |
|
|
let searchStrucIds = strucListRes.map(s => { |
|
|
if (s.iotaThingId) { |
|
|
if (s.iotaThingId) { |
|
|
strucThingId.push(s.iotaThingId) |
|
|
strucThingId.push(s.iotaThingId) |
|
|
} |
|
|
} |
|
|
|
|
|
strucMap[s.id] = { |
|
|
|
|
|
...s |
|
|
|
|
|
} |
|
|
return s.id |
|
|
return s.id |
|
|
}) |
|
|
}) |
|
|
|
|
|
|
|
@ -476,7 +482,8 @@ module.exports = function (app, opts) { |
|
|
n: '结构物', |
|
|
n: '结构物', |
|
|
k: '', |
|
|
k: '', |
|
|
f: (d) => { |
|
|
f: (d) => { |
|
|
return (strucListRes.find(s => s.id == d.StructureId) || { name: '' }).name |
|
|
return (strucMap[d.StructureId] || { name: '' }).name |
|
|
|
|
|
// return (strucListRes.find(s => s.id == d.StructureId) || { name: '' }).name
|
|
|
} |
|
|
} |
|
|
}, { |
|
|
}, { |
|
|
n: '告警源名称', |
|
|
n: '告警源名称', |
|
@ -549,13 +556,13 @@ module.exports = function (app, opts) { |
|
|
n: '测点', |
|
|
n: '测点', |
|
|
k: '', |
|
|
k: '', |
|
|
f: (d) => { |
|
|
f: (d) => { |
|
|
return d.station.map(ds => ds.name).join('、') |
|
|
return d.station ? d.station.map(ds => ds.name).join('、') : '' |
|
|
} |
|
|
} |
|
|
}, { |
|
|
}, { |
|
|
n: '位置', |
|
|
n: '位置', |
|
|
k: '', |
|
|
k: '', |
|
|
f: (d) => { |
|
|
f: (d) => { |
|
|
return d.station.map(ds => ds.position).join('、') |
|
|
return d.station ? d.station.map(ds => ds.position).join('、') : '' |
|
|
} |
|
|
} |
|
|
}, { |
|
|
}, { |
|
|
n: '告警信息', |
|
|
n: '告警信息', |
|
@ -621,15 +628,15 @@ module.exports = function (app, opts) { |
|
|
tableTitle += '</tr>' |
|
|
tableTitle += '</tr>' |
|
|
return tableTitle |
|
|
return tableTitle |
|
|
} |
|
|
} |
|
|
function packageTableData (data, titleArr) { |
|
|
function packageTableData ({ data, titleArr }) { |
|
|
let tableData = '<tr>' |
|
|
let tableData = '<tr>' |
|
|
for (let t of titleArr) { |
|
|
for (let t of titleArr) { |
|
|
if (t.v) { |
|
|
if (t.v) { |
|
|
tableData += `<td>${t.v}</td>` |
|
|
tableData += `<td>${t.v || ''}</td>` |
|
|
} else if (t.f) { |
|
|
} else if (t.f) { |
|
|
tableData += `<td>${t.f(data)}</td>` |
|
|
tableData += `<td>${t.f(data) || ''}</td>` |
|
|
} else if (t.k) { |
|
|
} else if (t.k) { |
|
|
tableData += `<td>${data[t.k]}</td>` |
|
|
tableData += `<td>${data[t.k] || ''}</td>` |
|
|
} else { |
|
|
} else { |
|
|
tableData += `<td></td>` |
|
|
tableData += `<td></td>` |
|
|
} |
|
|
} |
|
@ -638,33 +645,13 @@ module.exports = function (app, opts) { |
|
|
return tableData |
|
|
return tableData |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function packageAlarmData2Table (titlePrefix, alarmData, alarmTitleArr, keyOfStartTime = 'StartTime') { |
|
|
let apMergeDeVeAnxinProjectId_ = apMergeDeVeAnxinProjectId ? |
|
|
if (!alarmData.length) { |
|
|
apMergeDeVeAnxinProjectId.split(',') : []; |
|
|
return '' |
|
|
let apMergeDeVeAlarms = { |
|
|
} |
|
|
// 结构物id :{
|
|
|
ifEmailSend = true |
|
|
// data_exception 数据异常告警:[],
|
|
|
let tableTitlePrefix = titlePrefix + '告警源' |
|
|
// video_exception 视频异常告警:[]
|
|
|
let newAddCount = 0 |
|
|
// }
|
|
|
let alarmHtml = '<table border="1" cellspacing="0" style="border-collapse:collapse;border-spacing:0;border-left:1px solid #888;border-top:1px solid #888;">' |
|
|
|
|
|
let alarmContent = '' |
|
|
|
|
|
let alarmHtmlTitle = packageTableTitle(alarmTitleArr) |
|
|
|
|
|
|
|
|
|
|
|
for (let a of alarmData) { |
|
|
|
|
|
alarmContent += packageTableData(a, alarmTitleArr) |
|
|
|
|
|
if (a[keyOfStartTime] && moment(a[keyOfStartTime]).isBetween(newAddStartTime, newAddEndTime)) { |
|
|
|
|
|
newAddCount++ |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
tableTitlePrefix += |
|
|
|
|
|
c.tactics == 'abnormal_rate' ? |
|
|
|
|
|
`${alarmData.length}个` : |
|
|
|
|
|
`新增${newAddCount}个,未解决累计${alarmData.length}个` + tableTitlePostfix |
|
|
|
|
|
alarmHtml += `<tr><td colspan="${alarmTitleArr.length}" style="background-color:#ffff00">` + tableTitlePrefix + '</td></tr>' |
|
|
|
|
|
alarmHtml += alarmHtmlTitle |
|
|
|
|
|
alarmHtml += alarmContent |
|
|
|
|
|
alarmHtml += '</table><br/>' |
|
|
|
|
|
|
|
|
|
|
|
return alarmHtml |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
let dataAlarmG1 = []; |
|
|
let dataAlarmG1 = []; |
|
@ -693,6 +680,7 @@ module.exports = function (app, opts) { |
|
|
if (proDebug) { |
|
|
if (proDebug) { |
|
|
console.log(`pomsStrucFactorId:`, pomsStrucFactorId); |
|
|
console.log(`pomsStrucFactorId:`, pomsStrucFactorId); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
for (let d of dataAlarms) { |
|
|
for (let d of dataAlarms) { |
|
|
|
|
|
|
|
|
/** 按监测因素筛选 且为测点告警 */ |
|
|
/** 按监测因素筛选 且为测点告警 */ |
|
@ -717,6 +705,30 @@ module.exports = function (app, opts) { |
|
|
dataAlarmG1.push(d) |
|
|
dataAlarmG1.push(d) |
|
|
} else if (d.AlarmGroup == 2) { |
|
|
} else if (d.AlarmGroup == 2) { |
|
|
dataAlarmG2.push(d) |
|
|
dataAlarmG2.push(d) |
|
|
|
|
|
/** 注1 |
|
|
|
|
|
* 根据指定的安心云结构物把数据异常和视频告警合并在一起的代码 |
|
|
|
|
|
* 还要指定是扬尘设备 |
|
|
|
|
|
* 以测点关联 |
|
|
|
|
|
*/ |
|
|
|
|
|
if ( |
|
|
|
|
|
isDev || |
|
|
|
|
|
( |
|
|
|
|
|
apMergeDeVeAnxinProjectId_.length && |
|
|
|
|
|
d.SourceName && d.SourceName.includes('扬尘') && |
|
|
|
|
|
apMergeDeVeAnxinProjectId_.some(pid => pid == (strucMap[d.StructureId] || {}).projectId) |
|
|
|
|
|
) |
|
|
|
|
|
) { |
|
|
|
|
|
if (apMergeDeVeAlarms[d.StructureId]) { |
|
|
|
|
|
apMergeDeVeAlarms[d.StructureId].data_exception.push(d) |
|
|
|
|
|
} else { |
|
|
|
|
|
apMergeDeVeAlarms[d.StructureId] = { |
|
|
|
|
|
data_exception: [d], |
|
|
|
|
|
video_exception: [] |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
// 注1 END
|
|
|
|
|
|
|
|
|
} else if (d.AlarmGroup == 3) { |
|
|
} else if (d.AlarmGroup == 3) { |
|
|
|
|
|
|
|
|
/** 按监测因项 factor-item 的名称筛选*/ |
|
|
/** 按监测因项 factor-item 的名称筛选*/ |
|
@ -764,6 +776,17 @@ module.exports = function (app, opts) { |
|
|
|
|
|
|
|
|
emailSubTitle = emailSubTitle.replace('--%', rate.toFixed(1) + '%') |
|
|
emailSubTitle = emailSubTitle.replace('--%', rate.toFixed(1) + '%') |
|
|
} |
|
|
} |
|
|
|
|
|
// 注1
|
|
|
|
|
|
if (apMergeDeVeAnxinProjectId_.length || isDev) { |
|
|
|
|
|
for (let a of videoAlarms) { |
|
|
|
|
|
let existStruc = a.struc.find(asc => apMergeDeVeAlarms[asc.id] || isDev) |
|
|
|
|
|
if (existStruc) { |
|
|
|
|
|
apMergeDeVeAlarms[existStruc.id].video_exception.push(a) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 注1 END
|
|
|
let html = ` |
|
|
let html = ` |
|
|
<html> |
|
|
<html> |
|
|
<head> |
|
|
<head> |
|
@ -783,49 +806,123 @@ module.exports = function (app, opts) { |
|
|
</html> |
|
|
</html> |
|
|
<h5 style="margin-bottom:12px">${emailSubTitle}</h5> |
|
|
<h5 style="margin-bottom:12px">${emailSubTitle}</h5> |
|
|
` |
|
|
` |
|
|
|
|
|
|
|
|
|
|
|
function packageAlarmData2Table ({ |
|
|
|
|
|
titlePrefix, alarmData, alarmTitleArr, keyOfStartTime = 'StartTime' |
|
|
|
|
|
}) { |
|
|
|
|
|
if (!alarmData.length) { |
|
|
|
|
|
return '' |
|
|
|
|
|
} |
|
|
|
|
|
ifEmailSend = true |
|
|
|
|
|
let tableTitlePrefix = titlePrefix + '告警源' |
|
|
|
|
|
let newAddCount = 0 |
|
|
|
|
|
let alarmHtml = '<table border="1" cellspacing="0" style="border-collapse:collapse;border-spacing:0;border-left:1px solid #888;border-top:1px solid #888;">' |
|
|
|
|
|
let alarmContent = '' |
|
|
|
|
|
let alarmHtmlTitle = packageTableTitle(alarmTitleArr) |
|
|
|
|
|
|
|
|
|
|
|
for (let [index, a] of alarmData.entries()) { |
|
|
|
|
|
alarmContent += packageTableData({ data: a, titleArr: alarmTitleArr }) |
|
|
|
|
|
|
|
|
|
|
|
if (a[keyOfStartTime] && moment(a[keyOfStartTime]).isBetween(newAddStartTime, newAddEndTime)) { |
|
|
|
|
|
newAddCount++ |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
tableTitlePrefix += |
|
|
|
|
|
titlePrefix != '数据异常&视频异常' ? |
|
|
|
|
|
c.tactics == 'abnormal_rate' ? |
|
|
|
|
|
`${alarmData.length}个` : |
|
|
|
|
|
`新增${newAddCount}个,未解决累计${alarmData.length}个` + tableTitlePostfix |
|
|
|
|
|
: '' |
|
|
|
|
|
alarmHtml += `<tr><td colspan="${alarmTitleArr.length}" style="background-color:#ffff00">` + tableTitlePrefix + '</td></tr>' |
|
|
|
|
|
alarmHtml += alarmHtmlTitle |
|
|
|
|
|
alarmHtml += alarmContent |
|
|
|
|
|
alarmHtml += '</table><br/>' |
|
|
|
|
|
|
|
|
|
|
|
return alarmHtml |
|
|
|
|
|
} |
|
|
if (c.alarmType.includes('data_outages')) { |
|
|
if (c.alarmType.includes('data_outages')) { |
|
|
html += packageAlarmData2Table( |
|
|
html += packageAlarmData2Table({ |
|
|
'数据中断', |
|
|
titlePrefix: '数据中断', |
|
|
dataAlarmG1, |
|
|
alarmData: dataAlarmG1, |
|
|
dataAlarmTitle, |
|
|
alarmTitleArr: dataAlarmTitle, |
|
|
) |
|
|
}) |
|
|
} |
|
|
} |
|
|
if (c.alarmType.includes('data_exception')) { |
|
|
if (c.alarmType.includes('data_exception')) { |
|
|
html += packageAlarmData2Table( |
|
|
html += packageAlarmData2Table({ |
|
|
'数据异常', |
|
|
titlePrefix: '数据异常', |
|
|
dataAlarmG2, |
|
|
alarmData: dataAlarmG2, |
|
|
dataAlarmTitle, |
|
|
alarmTitleArr: dataAlarmTitle, |
|
|
) |
|
|
}) |
|
|
} |
|
|
} |
|
|
if (c.alarmType.includes('strategy_hit')) { |
|
|
if (c.alarmType.includes('strategy_hit')) { |
|
|
html += packageAlarmData2Table( |
|
|
html += packageAlarmData2Table({ |
|
|
'策略命中', |
|
|
titlePrefix: '策略命中', |
|
|
dataAlarmG3, |
|
|
alarmData: dataAlarmG3, |
|
|
dataAlarmTitle, |
|
|
alarmTitleArr: dataAlarmTitle, |
|
|
) |
|
|
}) |
|
|
} |
|
|
} |
|
|
if (c.alarmType.includes('video_exception')) { |
|
|
if (c.alarmType.includes('video_exception')) { |
|
|
html += packageAlarmData2Table( |
|
|
html += packageAlarmData2Table({ |
|
|
'视频异常', |
|
|
titlePrefix: '视频异常', |
|
|
videoAlarms, |
|
|
alarmData: videoAlarms, |
|
|
videoAlarmTitle, |
|
|
alarmTitleArr: videoAlarmTitle, |
|
|
'createTime', |
|
|
keyOfStartTime: 'createTime', |
|
|
) |
|
|
}) |
|
|
} |
|
|
} |
|
|
if (c.alarmType.includes('app_exception')) { |
|
|
if (c.alarmType.includes('app_exception')) { |
|
|
html += packageAlarmData2Table( |
|
|
html += packageAlarmData2Table({ |
|
|
'应用异常', |
|
|
titlePrefix: '应用异常', |
|
|
appAlarms, |
|
|
alarmData: appAlarms, |
|
|
appAlarmTitle, |
|
|
alarmTitleArr: appAlarmTitle, |
|
|
'createTime', |
|
|
keyOfStartTime: 'createTime', |
|
|
) |
|
|
}) |
|
|
} |
|
|
} |
|
|
if (c.alarmType.includes('device_exception')) { |
|
|
if (c.alarmType.includes('device_exception')) { |
|
|
html += packageAlarmData2Table( |
|
|
html += packageAlarmData2Table({ |
|
|
'设备异常', |
|
|
titlePrefix: '设备异常', |
|
|
dataAlarmG45, |
|
|
alarmData: dataAlarmG45, |
|
|
dataAlarmTitle, |
|
|
alarmTitleArr: dataAlarmTitle, |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (Object.keys(apMergeDeVeAlarms).length) { |
|
|
|
|
|
let alarmTitle = dataAlarmTitle.concat( |
|
|
|
|
|
videoAlarmTitle.slice(2).map(v => { |
|
|
|
|
|
return { |
|
|
|
|
|
...v, |
|
|
|
|
|
n: |
|
|
|
|
|
v.n == '持续时间' ? |
|
|
|
|
|
'摄像头告警' + v.n : |
|
|
|
|
|
'摄像头' + v.n |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
) |
|
|
) |
|
|
|
|
|
let alarmData = [] |
|
|
|
|
|
for (let aKey in apMergeDeVeAlarms) { |
|
|
|
|
|
let curStrucAlarm = apMergeDeVeAlarms[aKey] |
|
|
|
|
|
for (let de of curStrucAlarm.data_exception) { |
|
|
|
|
|
let corVideoException = curStrucAlarm.video_exception.filter(v => { |
|
|
|
|
|
// ! de.id 是告警的关联查出来的测点的id
|
|
|
|
|
|
return v.station.some(vs => vs.id == de.id) |
|
|
|
|
|
}) |
|
|
|
|
|
if (!corVideoException.length) { |
|
|
|
|
|
// 构造一个长度 以便在for循环里把 data_exception 放进去
|
|
|
|
|
|
corVideoException.push({}) |
|
|
|
|
|
} |
|
|
|
|
|
for (let ve of corVideoException) { |
|
|
|
|
|
alarmData.push({ |
|
|
|
|
|
...de, |
|
|
|
|
|
...ve |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
html += packageAlarmData2Table({ |
|
|
|
|
|
titlePrefix: '数据异常&视频异常', |
|
|
|
|
|
alarmData: alarmData, |
|
|
|
|
|
alarmTitleArr: alarmTitle, |
|
|
|
|
|
}) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (ifEmailSend) { |
|
|
if (ifEmailSend) { |
|
|