wuqun 2 years ago
parent
commit
3a916b4763
  1. 11
      api/.vscode/launch.json
  2. 38
      api/Dockerfile
  3. 11
      api/app/lib/controllers/alarm/data.js
  4. 14
      api/app/lib/controllers/alarm/video.js
  5. 13
      api/app/lib/controllers/auth/index.js
  6. 31
      api/app/lib/controllers/control/data.js
  7. 3
      api/app/lib/controllers/project/bind.js
  8. 77
      api/app/lib/controllers/project/index.js
  9. 36
      api/app/lib/controllers/push/config.js
  10. 4
      api/app/lib/index.js
  11. 20
      api/app/lib/models/alarm_push_config.js
  12. 2
      api/app/lib/models/email_send_log.js
  13. 2
      api/app/lib/models/latest_dynamic_list.js
  14. 504
      api/app/lib/schedule/alarms_push.js
  15. 2
      api/app/lib/utils/alarmHandle.js
  16. 5
      api/config.js
  17. 12
      jenkinsfile_poms_api
  18. 12
      jenkinsfile_poms_web
  19. 16
      script/0.10/schema/1.alter_alarm_push_config.sql
  20. 4
      script/0.11/schema/1.alter_alarm_push_config.sql
  21. 6
      script/0.11/schema/2.alter_email_send_log.sql
  22. 1
      script/0.11/schema/3.alert_latest_dynamic_list.sql
  23. 44
      web/Dockerfile
  24. BIN
      web/client/assets/images/background/B.png
  25. BIN
      web/client/assets/images/background/General.png
  26. 2
      web/client/src/layout/actions/global.js
  27. 6
      web/client/src/layout/reducers/global.js
  28. 64
      web/client/src/sections/control/containers/control.jsx
  29. 4
      web/client/src/sections/control/containers/userCenter.jsx
  30. 28
      web/client/src/sections/facility/containers/monitor.jsx
  31. 1
      web/client/src/sections/facility/nav-item.jsx
  32. 2
      web/client/src/sections/install/containers/system.jsx
  33. 6
      web/client/src/sections/problem/actions/problem.jsx
  34. 18
      web/client/src/sections/problem/components/tableData.jsx
  35. 490
      web/client/src/sections/service/components/pushModal.jsx
  36. 97
      web/client/src/sections/service/containers/emPush.jsx
  37. 8
      web/client/src/sections/service/containers/reportManagement.jsx
  38. 8
      web/config.js
  39. 2
      web/package.json
  40. 4
      web/routes/attachment/index.js

11
api/.vscode/launch.json

@ -16,13 +16,14 @@
"-p 4600", "-p 4600",
"-f http://localhost:4600", "-f http://localhost:4600",
// //
"-g postgres://postgres:123@10.8.30.32:5432/orational_service", // "-g postgres://postgres:123@10.8.30.32:5432/orational_service",
// //
// "-g postgres://FashionAdmin:123456@10.8.30.156:5432/POMS", "-g postgres://FashionAdmin:123456@10.8.30.156:5432/POMS",
"-k 10.8.30.72:29092,10.8.30.73:29092,10.8.30.74:29092", "-k 10.8.30.72:29092,10.8.30.73:29092,10.8.30.74:29092",
"--iotaProxy http://10.8.30.157:17007", "--iotaProxy http://10.8.30.157:17007",
"--redisHost 10.8.30.112", "--redisHost localhost",
"--redisPort 6379", "--redisPort 6379",
"--apMergeDeVeAnxinProjectId 1,2,3",
"--axyApiUrl http://127.0.0.1:4100", "--axyApiUrl http://127.0.0.1:4100",
// "--apiEmisUrl http://10.8.30.112:14000", // "--apiEmisUrl http://10.8.30.112:14000",
// //
@ -43,11 +44,9 @@
"--clickHouseUrl http://10.8.30.161", "--clickHouseUrl http://10.8.30.161",
// "--clickHouseUrl https://clickhouse01.anxinyun.cn/play", // "--clickHouseUrl https://clickhouse01.anxinyun.cn/play",
"--clickHousePort 30123", "--clickHousePort 30123",
// * 2 // * 2
// "--clickHouseUser ", // "--clickHouseUser ",
// "--clickHousePassword ", // "--clickHousePassword ",
// //
// "--clickHouseAnxincloud anxinyun", // "--clickHouseAnxincloud anxinyun",
// "--clickHousePepEmis pepca", // "--clickHousePepEmis pepca",
@ -55,7 +54,6 @@
// "--clickHouseVcmp video_accrss1", // "--clickHouseVcmp video_accrss1",
// "--clickHouseDataAlarm default", // "--clickHouseDataAlarm default",
// "--clickHouseIot iot", // "--clickHouseIot iot",
// //
"--clickHouseAnxincloud anxinyun88", "--clickHouseAnxincloud anxinyun88",
"--clickHousePepEmis pepca8", "--clickHousePepEmis pepca8",
@ -63,7 +61,6 @@
"--clickHouseVcmp video_access_dev", "--clickHouseVcmp video_access_dev",
"--clickHouseDataAlarm default", "--clickHouseDataAlarm default",
"--clickHouseIot iot", "--clickHouseIot iot",
"--confirmAlarmAnxinUserId 1", "--confirmAlarmAnxinUserId 1",
"--vcmpAppId 5048b08d-c449-4d7f-b1ec-f741012aefe8", "--vcmpAppId 5048b08d-c449-4d7f-b1ec-f741012aefe8",
"--vcmpAppSecret 5ba8c0ab-9fbd-4f07-9817-c48017c3cbad", "--vcmpAppSecret 5ba8c0ab-9fbd-4f07-9817-c48017c3cbad",

38
api/Dockerfile

@ -1,36 +1,36 @@
# FROM repository.anxinyun.cn/devops/node:12-dev as builder FROM registry.cn-hangzhou.aliyuncs.com/fs-devops/node:12-dev as builder
# COPY . /var/app COPY . /var/app
# WORKDIR /var/app WORKDIR /var/app
# EXPOSE 8080 EXPOSE 8080
# RUN npm config set registry=http://10.8.30.22:7000 RUN npm config set registry=http://10.8.30.22:7000
# RUN echo "{\"time\":\"$BUILD_TIMESTAMP\",\"build\": \"$BUILD_NUMBER\",\"revision\": \"$SVN_REVISION_1\",\"URL\":\"$SVN_URL_1\"}" > version.json RUN echo "{\"time\":\"$BUILD_TIMESTAMP\",\"build\": \"$BUILD_NUMBER\",\"revision\": \"$SVN_REVISION_1\",\"URL\":\"$SVN_URL_1\"}" > version.json
# RUN npm cache clean -f RUN npm cache clean -f
# RUN rm -rf package-lock.json RUN rm -rf package-lock.json
# RUN npm install --registry http://10.8.30.22:7000 RUN npm install --registry http://10.8.30.22:7000
# FROM registry.cn-hangzhou.aliyuncs.com/fs-devops/node:12 FROM registry.cn-hangzhou.aliyuncs.com/fs-devops/node:12
# COPY --from=builder --chown=node /var/app /home/node/app COPY --from=builder --chown=node /var/app /home/node/app
# WORKDIR /home/node/app WORKDIR /home/node/app
# CMD ["node", "server.js"] CMD ["node", "server.js"]
# 旧版本构建方式 # 旧版本构建方式
FROM repository.anxinyun.cn/base-images/nodejs12:20.10.12.2 # FROM repository.anxinyun.cn/base-images/nodejs12:20.10.12.2
COPY . /var/app # COPY . /var/app
WORKDIR /var/app # WORKDIR /var/app
EXPOSE 8080 # EXPOSE 8080
CMD ["-u", "http://localhost:8088"] # CMD ["-u", "http://localhost:8088"]
ENTRYPOINT [ "node", "server.js" ] # ENTRYPOINT [ "node", "server.js" ]

11
api/app/lib/controllers/alarm/data.js

@ -8,17 +8,23 @@ async function groupList (ctx) {
const { clickHouse } = ctx.app.fs const { clickHouse } = ctx.app.fs
const { database: dataAlarm } = clickHouse.dataAlarm.opts.config const { database: dataAlarm } = clickHouse.dataAlarm.opts.config
const { showAll } = ctx.query
const groupRes = await clickHouse.anxinyun.query(` const groupRes = await clickHouse.anxinyun.query(`
SELECT * FROM t_alarm_group SELECT * FROM t_alarm_group
`).toPromise(); `).toPromise();
let whereOption = []
if (!showAll) {
whereOption.push(` INNER JOIN ${dataAlarm}.alarms
ON t_alarm_group_unit.id = ${dataAlarm}.alarms.AlarmGroupUnit`)
}
for (let g of groupRes) { for (let g of groupRes) {
g.unit = await await clickHouse.anxinyun.query(` g.unit = await await clickHouse.anxinyun.query(`
SELECT DISTINCT SELECT DISTINCT
t_alarm_group_unit.id AS id,t_alarm_group_unit.name AS name,t_alarm_group_unit.group_id AS groupId t_alarm_group_unit.id AS id,t_alarm_group_unit.name AS name,t_alarm_group_unit.group_id AS groupId
FROM t_alarm_group_unit FROM t_alarm_group_unit
INNER JOIN ${dataAlarm}.alarms ${whereOption}
ON t_alarm_group_unit.id = ${dataAlarm}.alarms.AlarmGroupUnit
WHERE group_id = ${g.id} WHERE group_id = ${g.id}
`).toPromise(); `).toPromise();
} }
@ -143,7 +149,6 @@ async function list (ctx) {
`).toPromise(); `).toPromise();
const confirmedAlarm = alarmRes const confirmedAlarm = alarmRes
// TODO: 开发临时注释
.filter(ar => ar.State && ar.State > 2) .filter(ar => ar.State && ar.State > 2)
.map(ar => "'" + ar.AlarmId + "'") .map(ar => "'" + ar.AlarmId + "'")
const confirmedAlarmDetailMax = confirmedAlarm.length ? const confirmedAlarmDetailMax = confirmedAlarm.length ?

14
api/app/lib/controllers/alarm/video.js

@ -8,11 +8,18 @@ async function deviceType (ctx) {
const { clickHouse } = ctx.app.fs const { clickHouse } = ctx.app.fs
const { database: anxinyun } = clickHouse.anxinyun.opts.config const { database: anxinyun } = clickHouse.anxinyun.opts.config
const { utils: { judgeSuper, anxinStrucIdRange } } = ctx.app.fs const { utils: { judgeSuper, anxinStrucIdRange } } = ctx.app.fs
const { showAll } = ctx.query
let anxinStruc = await anxinStrucIdRange({ let anxinStruc = await anxinStrucIdRange({
ctx, ctx,
}) })
const anxinStrucIds = anxinStruc.map(a => a.strucId) const anxinStrucIds = anxinStruc.map(a => a.strucId)
let whereOption = []
if (!showAll) {
whereOption.push(`INNER 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(',')})`}`)
}
const kindRes = await clickHouse.vcmp.query(` const kindRes = await clickHouse.vcmp.query(`
SELECT DISTINCT SELECT DISTINCT
camera_kind.id AS id,camera_kind.kind AS kind camera_kind.id AS id,camera_kind.kind AS kind
@ -22,10 +29,7 @@ async function deviceType (ctx) {
INNER JOIN camera_status_alarm INNER JOIN camera_status_alarm
ON camera.channel_no = camera_status_alarm.channel_no ON camera.channel_no = camera_status_alarm.channel_no
AND camera.serial_no = camera_status_alarm.serial_no AND camera.serial_no = camera_status_alarm.serial_no
INNER JOIN ${anxinyun}.t_video_ipc ${whereOption}
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(',')})`}
`).toPromise() `).toPromise()
ctx.status = 200; ctx.status = 200;
ctx.body = kindRes ctx.body = kindRes

13
api/app/lib/controllers/auth/index.js

@ -10,9 +10,18 @@ async function login (ctx, next) {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
const params = ctx.request.body; const params = ctx.request.body;
const emisLoginRes = await ctx.app.fs.emisRequest.post('login', { let emisLoginRes = null
data: params if (params.username && params.password) {
emisLoginRes = await ctx.app.fs.emisRequest.post('login', {
data: { ...params, code: 'POMS' }
}) })
} else if (params.token) {
emisLoginRes = await ctx.app.fs.emisRequest.get('user-info', {
query: {
token: params.token, code: 'POMS'
}
})
}
if (!emisLoginRes) { if (!emisLoginRes) {
throw "无此用户,请使用正确的登录信息" throw "无此用户,请使用正确的登录信息"

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

@ -12,10 +12,8 @@ async function getDataAlarmsAggDay(ctx) {
ctx, pepProjectId ctx, pepProjectId
}) })
let whereOption = [] let whereOption = []
// ! 1 开发临时增加
if (anxinStruc.length) { if (anxinStruc.length) {
const anxinStrucIds = anxinStruc.map(a => a.strucId) const anxinStrucIds = anxinStruc.map(a => a.strucId)
// ! 开发临时注释
whereOption.push(`alarms.StructureId IN (${anxinStrucIds.join(",")})`) whereOption.push(`alarms.StructureId IN (${anxinStrucIds.join(",")})`)
let start = moment().add(-1, 'year').format('YYYY-MM-DD HH:mm:ss');//最近一年 let start = moment().add(-1, 'year').format('YYYY-MM-DD HH:mm:ss');//最近一年
@ -303,7 +301,7 @@ async function getLatestDynamic(ctx) {
}); });
//查项目名称 查用户名 //查项目名称 查用户名
let pepPojectIds = new Set(), notedUserIds = new Set(); let pepPojectIds = new Set(), notedUserIds = new Set(), emailSendPomsProjectIds = new Set();
for (let p of news) { for (let p of news) {
if (p.projectCorrelation && p.projectCorrelation.pepProjectId) { if (p.projectCorrelation && p.projectCorrelation.pepProjectId) {
pepPojectIds.add(p.projectCorrelation.pepProjectId); pepPojectIds.add(p.projectCorrelation.pepProjectId);
@ -313,11 +311,28 @@ async function getLatestDynamic(ctx) {
p.emailSendLog.toPepUserIds.map(u => { p.emailSendLog.toPepUserIds.map(u => {
notedUserIds.add(u);//通知 接收人 notedUserIds.add(u);//通知 接收人
}) })
p.emailSendLog.projectCorrelationId.forEach(pid => emailSendPomsProjectIds.add(pid))
} }
if (p.alarmConfirmLog && p.alarmConfirmLog.pepUserId) { if (p.alarmConfirmLog && p.alarmConfirmLog.pepUserId) {
notedUserIds.add(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(` let pepProjects = pepPojectIds.size ? await clickHouse.projectManage.query(`
SELECT id, project_name FROM t_pim_project WHERE id IN (${[...pepPojectIds].join(',')},-1) SELECT id, project_name FROM t_pim_project WHERE id IN (${[...pepPojectIds].join(',')},-1)
`).toPromise() : []; `).toPromise() : [];
@ -339,7 +354,15 @@ async function getLatestDynamic(ctx) {
if (d.emailSendId) { if (d.emailSendId) {
notice.push({ notice.push({
userName: userPepRes.filter(u => d.emailSendLog.toPepUserIds.indexOf(u.id) != -1), userName: userPepRes.filter(u => d.emailSendLog.toPepUserIds.indexOf(u.id) != -1),
projectName, 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 ...d.emailSendLog.dataValues
}); });
} }

3
api/app/lib/controllers/project/bind.js

@ -105,6 +105,9 @@ async function bindAnxin2pep (ctx) {
// 但是有之前的数据 // 但是有之前的数据
if (existRes.del) { if (existRes.del) {
// 不过之前的删除了 // 不过之前的删除了
storageData.createUser = userId
storageData.updateTime = now.format()
storageData.createTime = now.format()
await models.ProjectCorrelation.update(storageData, { await models.ProjectCorrelation.update(storageData, {
where: { where: {
pepProjectId: pepProjectId pepProjectId: pepProjectId

77
api/app/lib/controllers/project/index.js

@ -126,7 +126,7 @@ async function pomsProject (ctx) {
ctx.status = 200; ctx.status = 200;
ctx.body = proRes ctx.body = proRes
} catch (error) { } catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400; ctx.status = 400;
ctx.body = { ctx.body = {
message: typeof error == 'string' ? error : undefined message: typeof error == 'string' ? error : undefined
@ -210,20 +210,33 @@ async function strucWithPomsProject (ctx) {
const { clickHouse } = ctx.app.fs const { clickHouse } = ctx.app.fs
const { pomsProjectId } = ctx.query const { pomsProjectId } = ctx.query
const bindRes = await models.ProjectCorrelation.findOne({ const bindRes = await models.ProjectCorrelation.findAll({
where: { where: {
id: pomsProjectId id: { $in: pomsProjectId.split(',') }
} }
}) })
let anxinProjectIds = new Set()
for (let b of bindRes) {
if (b.anxinProjectId.length) {
for (let aid of b.anxinProjectId) {
anxinProjectIds.add(aid)
}
}
}
let undelStruc = [] let undelStruc = []
if (bindRes) { if (bindRes) {
const undelStrucRes = bindRes.anxinProjectId.length ? const undelStrucRes = anxinProjectIds.size ?
await clickHouse.anxinyun.query( await clickHouse.anxinyun.query(
` `
SELECT SELECT
t_structure.id AS strucId, t_structure.id AS strucId,
t_structure.name AS strucName t_structure.name AS strucName,
t_factor.id AS factorId,
t_factor.name AS factorName,
t_factor.proto AS factorProto,
t_factor_proto_item.name AS factorItemName,
t_factor_proto_item.id AS factorItemId
FROM FROM
t_project t_project
LEFT JOIN LEFT JOIN
@ -246,20 +259,70 @@ async function strucWithPomsProject (ctx) {
ON t_structure.id = t_project_structure.structure ON t_structure.id = t_project_structure.structure
OR t_structure.id = t_structuregroup_structure.structure OR t_structure.id = t_structuregroup_structure.structure
OR t_structure.id = t_structure_site.structid OR t_structure.id = t_structure_site.structid
LEFT JOIN t_structure_factor
ON t_structure_factor.structure = t_structure.id
LEFT JOIN t_factor
ON t_structure_factor.factor = t_factor.id
LEFT JOIN t_factor_proto_item
ON t_factor_proto_item.proto = t_factor.proto
WHERE WHERE
project_state != -1 project_state != -1
AND AND
t_project.id IN (${bindRes.anxinProjectId.join(',')}) t_project.id IN (${[...anxinProjectIds].join(',')}, -1)
ORDER BY strucId ORDER BY strucId
` `
).toPromise() : ).toPromise() :
[] []
for (let s of undelStrucRes) { for (let s of undelStrucRes) {
if (!undelStruc.some(us => us.id == s.strucId)) { let corStrut = undelStruc.find(us => us.id == s.strucId)
if (!corStrut) {
let nextFacor = []
if (s.factorId) {
let nextFactorItem = []
if (s.factorItemId) {
nextFactorItem.push({
id: s.factorItemId,
name: s.factorItemName,
})
}
nextFacor.push({
id: s.factorId,
name: s.factorName,
proto: s.factorProto,
item: nextFactorItem,
})
}
undelStruc.push({ undelStruc.push({
id: s.strucId, id: s.strucId,
name: s.strucName, name: s.strucName,
factor: nextFacor
}) })
} else {
if (s.factorId) {
let corFactor = corStrut.factor.find(v => v.id == s.factorId)
let nextFactorItem = null
if (s.factorItemId) {
nextFactorItem = {
id: s.factorItemId,
name: s.factorItemName,
}
}
if (corFactor) {
if (!corFactor.item.some(fi => fi.id == s.factorItemId) && nextFactorItem) {
corFactor.item.push(nextFactorItem)
}
} else {
corStrut.factor.push({
id: s.factorId,
name: s.factorName,
proto: s.factorProto,
item: nextFactorItem ? [{
id: s.factorItemId,
name: s.factorItemName,
}] : [],
})
}
}
} }
} }
} }

36
api/app/lib/controllers/push/config.js

@ -8,23 +8,11 @@ async function list (ctx) {
const { clickHouse } = ctx.app.fs const { clickHouse } = ctx.app.fs
const { utils: { anxinStrucIdRange, pomsProjectRange } } = ctx.app.fs const { utils: { anxinStrucIdRange, pomsProjectRange } } = ctx.app.fs
const { keyword, keywordTarget, alarmType, state, tactics, pomsProjectId } = ctx.query const { keyword, keywordTarget, alarmType, state, tactics, pomsProjectId } = ctx.query
let projectCorrelationWhere = {
del: false,
}
if (state == 'notYet') {
projectCorrelationWhere.pepProjectId = { $ne: null }
}
let findOption = { let findOption = {
where: { where: {
del: false del: false
}, },
order: [['id', 'desc']], order: [['id', 'desc']],
include: [{
model: models.ProjectCorrelation,
where: projectCorrelationWhere,
required: true
}]
} }
let anxinStrucsRange = await anxinStrucIdRange({ let anxinStrucsRange = await anxinStrucIdRange({
@ -48,7 +36,7 @@ async function list (ctx) {
ctx, pepProjectId: pomsProjectId, keywordTarget, keyword ctx, pepProjectId: pomsProjectId, keywordTarget, keyword
}) })
let pomsProjectIds = pomsProjectRes.map(p => p.id) let pomsProjectIds = pomsProjectRes.map(p => p.id)
findOption.where.pomsProjectId = { $in: pomsProjectIds } findOption.where.pomsProjectId = { $overlap: pomsProjectIds }
if (alarmType) { if (alarmType) {
findOption.where.alarmType = { $contains: [alarmType] } findOption.where.alarmType = { $contains: [alarmType] }
@ -65,6 +53,7 @@ async function list (ctx) {
} }
const listRes = await models.AlarmPushConfig.findAll(findOption) const listRes = await models.AlarmPushConfig.findAll(findOption)
// const listRes = await models.AlarmPushConfig.findAll({})
let allStrucIds = new Set() let allStrucIds = new Set()
let allConfigId = [] let allConfigId = []
let allReceiverIds = new Set() let allReceiverIds = new Set()
@ -104,7 +93,11 @@ async function list (ctx) {
let returnD = [] let returnD = []
for (let { dataValues: p } of listRes) { for (let { dataValues: p } of listRes) {
// 查对应的 poms 绑定的结构物绑定关系 // 查对应的 poms 绑定的结构物绑定关系
const corBind = pomsProjectRes.find(ppj => ppj.id == p.pomsProjectId) const corBinds = pomsProjectRes.filter(ppj => p.pomsProjectId.includes(ppj.id))
let filterBinds = []
for (let corBind of corBinds) {
if (corBind.pepProjectId) { if (corBind.pepProjectId) {
if (state == 'notYet') { if (state == 'notYet') {
if (corBind.pepProject && p.timeType.some(pt => pt == corBind.pepProject.constructionStatusId)) { if (corBind.pepProject && p.timeType.some(pt => pt == corBind.pepProject.constructionStatusId)) {
@ -115,6 +108,13 @@ async function list (ctx) {
continue continue
} }
} }
} else if (state == 'notYet') {
continue
}
filterBinds.push(corBind)
}
if (!filterBinds.length) {
continue
} }
// 结构物信息 // 结构物信息
@ -129,7 +129,7 @@ async function list (ctx) {
returnStruc.push({ returnStruc.push({
id: sid, id: sid,
name: structure.name, name: structure.name,
unbind: !anxinStrucSeen || !corBind.anxinProjectId.includes(anxinStrucSeen.projectId) unbind: !anxinStrucSeen || corBinds.every(corBinds => !corBinds.anxinProjectId.includes(anxinStrucSeen.projectId))
}) })
} else { } else {
// 这个结构物已删 // 这个结构物已删
@ -142,7 +142,7 @@ async function list (ctx) {
const corReceiver = userRes.filter(u => p.receiverPepUserId.some(prId => u.id == prId)) const corReceiver = userRes.filter(u => p.receiverPepUserId.some(prId => u.id == prId))
returnD.push({ returnD.push({
...p, ...p,
pomsProject: corBind, pomsProject: corBinds,
structure: returnStruc, structure: returnStruc,
pushCount: corLogCount ? corLogCount.dataValues.count : 0, pushCount: corLogCount ? corLogCount.dataValues.count : 0,
receiverPepUser: corReceiver receiverPepUser: corReceiver
@ -165,11 +165,11 @@ async function edit (ctx) {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
const { userId, pepUserId } = ctx.fs.api const { userId, pepUserId } = ctx.fs.api
const { pushId, name, pomsProjectId, alarmType = [], receiverPepUserId = [], timeType = [], disable, const { pushId, name, pomsProjectId, alarmType = [], receiverPepUserId = [], timeType = [], disable,
strucId = [], tactics, tacticsParams } = ctx.request.body strucId = [], tactics, tacticsParams, alarmSubType = {}, pomsStrucFactorId = {} } = ctx.request.body
let storageData = { let storageData = {
name, pomsProjectId, alarmType, receiverPepUserId, timeType, disable, name, pomsProjectId, alarmType, receiverPepUserId, timeType, disable,
strucId, tactics, tacticsParams strucId, tactics, tacticsParams, alarmSubType, pomsStrucFactorId
} }
let repeatOption = { let repeatOption = {

4
api/app/lib/index.js

@ -77,8 +77,8 @@ module.exports.models = function (dc) { // dc = { orm: Sequelize对象, ORM: Seq
AppAlarm.belongsTo(App, { foreignKey: 'projectAppId', targetKey: 'id' }); AppAlarm.belongsTo(App, { foreignKey: 'projectAppId', targetKey: 'id' });
App.hasMany(AppAlarm, { foreignKey: 'projectAppId', sourceKey: 'id' }); App.hasMany(AppAlarm, { foreignKey: 'projectAppId', sourceKey: 'id' });
AlarmPushConfig.belongsTo(ProjectCorrelation, { foreignKey: 'pomsProjectId', targetKey: 'id' }); // AlarmPushConfig.belongsTo(ProjectCorrelation, { foreignKey: 'pomsProjectId', targetKey: 'id' });
ProjectCorrelation.hasMany(AlarmPushConfig, { foreignKey: 'pomsProjectId', sourceKey: 'id' }); // ProjectCorrelation.hasMany(AlarmPushConfig, { foreignKey: 'pomsProjectId', sourceKey: 'id' });
AlarmAppearRecord.belongsTo(ProjectCorrelation, { foreignKey: 'projectCorrelationId', targetKey: 'id' }); AlarmAppearRecord.belongsTo(ProjectCorrelation, { foreignKey: 'projectCorrelationId', targetKey: 'id' });
ProjectCorrelation.hasMany(AlarmAppearRecord, { foreignKey: 'projectCorrelationId', sourceKey: 'id' }); ProjectCorrelation.hasMany(AlarmAppearRecord, { foreignKey: 'projectCorrelationId', sourceKey: 'id' });

20
api/app/lib/models/alarm_push_config.js

@ -25,7 +25,7 @@ module.exports = dc => {
autoIncrement: false autoIncrement: false
}, },
pomsProjectId: { pomsProjectId: {
type: DataTypes.INTEGER, type: DataTypes.ARRAY(DataTypes.INTEGER),
allowNull: false, allowNull: false,
defaultValue: null, defaultValue: null,
comment: null, comment: null,
@ -42,6 +42,24 @@ module.exports = dc => {
field: "alarm_type", field: "alarm_type",
autoIncrement: false autoIncrement: false
}, },
alarmSubType: {
type: DataTypes.JSONB,
allowNull: true,
defaultValue: null,
comment: "监听的告警类型的子类id的关联",
primaryKey: false,
field: "alarm_sub_type",
autoIncrement: false
},
pomsStrucFactorId: {
type: DataTypes.JSONB,
allowNull: true,
defaultValue: null,
comment: "结构物与监测项id的关联",
primaryKey: false,
field: "poms_struc_factor_id",
autoIncrement: false
},
receiverPepUserId: { receiverPepUserId: {
type: DataTypes.ARRAY(DataTypes.INTEGER), type: DataTypes.ARRAY(DataTypes.INTEGER),
allowNull: true, allowNull: true,

2
api/app/lib/models/email_send_log.js

@ -53,7 +53,7 @@ module.exports = dc => {
autoIncrement: false autoIncrement: false
}, },
projectCorrelationId: { projectCorrelationId: {
type: DataTypes.INTEGER, type: DataTypes.ARRAY(DataTypes.INTEGER),
allowNull: false, allowNull: false,
defaultValue: null, defaultValue: null,
comment: null, comment: null,

2
api/app/lib/models/latest_dynamic_list.js

@ -54,7 +54,7 @@ module.exports = dc => {
}, },
projectCorrelationId: { projectCorrelationId: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: false, allowNull: true,
defaultValue: null, defaultValue: null,
comment: null, comment: null,
primaryKey: false, primaryKey: false,

504
api/app/lib/schedule/alarms_push.js

@ -1,15 +1,22 @@
const moment = require('moment') const moment = require('moment')
let isDev = false
// isDev = true
let proDebug = false
proDebug = true
module.exports = function (app, opts) { module.exports = function (app, opts) {
const alarmsPush = app.fs.scheduleInit( const alarmsPush = app.fs.scheduleInit(
{ {
interval: '12 */1 * * * *', interval: '12 */1 * * * *',
// immediate: true, // dev immediate: isDev,
proRun: true, proRun: !isDev,
}, },
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
@ -20,18 +27,22 @@ module.exports = function (app, opts) {
disable: false disable: false
}, },
order: ['id'], order: ['id'],
include: [{
model: models.ProjectCorrelation,
where: {
del: false,
},
required: true
}],
}) })
let pomsProjectId = new Set()
let pepProjectIds = new Set() let pepProjectIds = new Set()
for (let { dataValues: c } of configListRes) { for (let { dataValues: c } of configListRes) {
if (c.projectCorrelation.pepProjectId) { if (c.pomsProjectId) {
pepProjectIds.add(c.projectCorrelation.pepProjectId) c.pomsProjectId.forEach(pid => pomsProjectId.add(pid))
}
}
const pomsProjectRes = pomsProjectId.size ? await models.ProjectCorrelation.findAll({
where: {
id: { $in: [...pomsProjectId] }
}
}) : []
for (let { dataValues: c } of pomsProjectRes) {
if (c.pepProjectId) {
pepProjectIds.add(c.pepProjectId)
} }
} }
const pepProjectRes = pepProjectIds.size ? const pepProjectRes = pepProjectIds.size ?
@ -55,24 +66,42 @@ module.exports = function (app, opts) {
for (let { dataValues: c } of configListRes) { for (let { dataValues: c } of configListRes) {
if (c.tacticsParams && c.tactics) { if (c.tacticsParams && c.tactics) {
const { projectCorrelation, strucId, pomsProjectId, } = c if (proDebug) {
console.log(`当前运行EM配置:id=${c.id} name=${c.name}`);
}
// pomsProjectId 是个数组 []
const { strucId, pomsProjectId, pomsStrucFactorId } = c
const { interval, deviceProportion } = c.tacticsParams const { interval, deviceProportion } = c.tacticsParams
if ( if (
curMinOfYear % parseInt(interval) == 0 curMinOfYear % parseInt(interval) == 0 || isDev
) { ) {
const corPepProject = projectCorrelation.pepProjectId ?
pepProjectRes.find(p => p.id == projectCorrelation.pepProjectId)
: null
if (
!projectCorrelation.pepProjectId
|| (
corPepProject
&& c.timeType.some(ct => ct == corPepProject.construction_status_id)
)
) {
const { anxinProjectId, pepProjectId } = projectCorrelation
const corPomsProject = pomsProjectRes.filter(poms => pomsProjectId.includes(poms.id))
let curAnxinProjectId = new Set()
let pepProjectName_ = []
for (let { dataValues: poms } of corPomsProject) {
if (poms.pepProjectId) {
// 找对应的项企项目
const corPepProject =
pepProjectRes.find(p => p.id == poms.pepProjectId)
if (corPepProject && c.timeType.some(ct => ct == corPepProject.construction_status_id)) {
pepProjectName_.push(corPepProject.project_name)
} else {
// 不符合当前项目的时间节点
continue
}
} else {
// 是自定义项目
poms.name ? pepProjectName_.push(poms.name) : null
}
// 筛选全部的 anxinProjectId pepProjectId
for (let axId of poms.anxinProjectId) {
curAnxinProjectId.add(axId)
}
}
const anxinProjectId = [...curAnxinProjectId]
// 查当前 poms 下的结构物 并把不包含的去掉 // 查当前 poms 下的结构物 并把不包含的去掉
// 可能有结构物已解绑 // 可能有结构物已解绑
const strucListRes = strucId.length && anxinProjectId.length ? const strucListRes = strucId.length && anxinProjectId.length ?
@ -82,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
@ -109,32 +139,45 @@ module.exports = function (app, opts) {
project_state != -1 project_state != -1
AND t_project.id IN (${anxinProjectId.join(',')}) AND t_project.id IN (${anxinProjectId.join(',')})
AND t_structure.id IN (${strucId.join(',')}) AND t_structure.id IN (${strucId.join(',')})
` `
).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
}) })
// 开发测试用的数据 // !开发测试用的数据
// searchStrucIds = searchStrucIds.concat([991, 1052, 700]) if (isDev) {
searchStrucIds = searchStrucIds.concat([991, 1052, 700])
}
if (searchStrucIds.length) { if (searchStrucIds.length) {
searchStrucIds.unshift(-1) searchStrucIds.unshift(-1)
} else {
// 没有结构物可查
continue
} }
let pepProjectName = pepProjectId ? let pepProjectName =
pepProjectRes.find(p => p.id == pepProjectId).project_name pepProjectName_.length ?
: projectCorrelation.name pepProjectName_.join('<br/>')
let emailTitle = `${pepProjectName}-${c.name}-` : ''
let emailTitle = `${pepProjectName_.length ?
pepProjectName_.join('、')
: ''}-${c.name}-`
let emailSubTitle = '' let emailSubTitle = ''
let dataAlarmOption = [] let dataAlarmOption = []
let dataAlarmGroupOption = [] let dataAlarmGroupOption = []
let dataAlarmSubType = []
let dataAlarms = [] let dataAlarms = []
let videoAlarmWhereOption = [] let videoAlarmWhereOption = []
@ -211,15 +254,26 @@ module.exports = function (app, opts) {
// 判断告警数据范围 // 判断告警数据范围
if (c.alarmType.includes('data_outages')) { if (c.alarmType.includes('data_outages')) {
dataAlarmGroupOption.push(1) dataAlarmGroupOption.push(1)
if (c.alarmSubType) dataAlarmSubType = dataAlarmSubType.concat(c.alarmSubType['data_outages'])
} }
if (c.alarmType.includes('data_exception')) { if (c.alarmType.includes('data_exception')) {
dataAlarmGroupOption.push(2) dataAlarmGroupOption.push(2)
if (c.alarmSubType) dataAlarmSubType = dataAlarmSubType.concat(c.alarmSubType['data_exception'])
} }
if (c.alarmType.includes('strategy_hit')) { if (c.alarmType.includes('strategy_hit')) {
dataAlarmGroupOption.push(3) dataAlarmGroupOption.push(3)
if (c.alarmSubType) dataAlarmSubType = dataAlarmSubType.concat(c.alarmSubType['strategy_hit'])
} }
if (c.alarmType.includes('video_exception')) { if (c.alarmType.includes('video_exception')) {
videoAlarms = searchStrucIds.length ? await clickHouse.vcmp.query( let videoAlarmSubType = c.alarmSubType ? c.alarmSubType['video_exception'] : []
if (videoAlarmSubType.length == 1) {
videoAlarmSubType.push(-1)
}
videoAlarms =
searchStrucIds.length && (
!c.alarmSubType || videoAlarmSubType.length > 0
) ?
await clickHouse.vcmp.query(
` `
SELECT SELECT
cameraAlarm.cameraId AS cameraId, cameraAlarm.cameraId AS cameraId,
@ -237,6 +291,7 @@ module.exports = function (app, opts) {
anxinIpc.t_video_ipc.name AS anxinIpcPosition, anxinIpc.t_video_ipc.name AS anxinIpcPosition,
anxinStation.id AS anxinStationId, anxinStation.id AS anxinStationId,
anxinStation.name AS anxinStationName, anxinStation.name AS anxinStationName,
anxinStation.factor AS anxinStationFactorId,
anxinStruc.name AS strucName, anxinStruc.name AS strucName,
anxinStruc.id AS strucId anxinStruc.id AS strucId
FROM ( FROM (
@ -263,6 +318,7 @@ module.exports = function (app, opts) {
AND camera.channel_no = camera_status_alarm.channel_no AND camera.channel_no = camera_status_alarm.channel_no
AND camera.delete = false AND camera.delete = false
AND camera.recycle_time is null AND camera.recycle_time is null
${c.alarmSubType ? `AND camera.kind_id in (${videoAlarmSubType.join(',')})` : ""}
WHERE WHERE
camera_status_alarm.confirm_time IS null camera_status_alarm.confirm_time IS null
${videoAlarmWhereOption.length ? ` AND ${videoAlarmWhereOption.join(' AND ')}` : ''} ${videoAlarmWhereOption.length ? ` AND ${videoAlarmWhereOption.join(' AND ')}` : ''}
@ -310,6 +366,21 @@ module.exports = function (app, opts) {
}) })
} }
} else { } else {
/**按监测因素 factor 筛选告警*/
// if (pomsStrucFactorId) {
// if (!a.strucId || !a.anxinStationFactorId) {
// // 当前告警没有绑定结构物或者摄像头没有绑定测点
// continue
// } else if (!pomsStrucFactorId[a.strucId]) {
// // 推送配置没配置这个结构物
// continue
// } else if (!pomsStrucFactorId[a.strucId].includes(a.anxinStationFactorId)) {
// // 不包含这个监测因素
// continue
// }
// }
let d = { let d = {
cameraId: a.cameraId, cameraId: a.cameraId,
cameraName: a.cameraName, cameraName: a.cameraName,
@ -325,6 +396,7 @@ module.exports = function (app, opts) {
confirmContent: a.confirmContent, confirmContent: a.confirmContent,
confirmTime: a.confirmTime, confirmTime: a.confirmTime,
cameraKind: a.cameraKind, cameraKind: a.cameraKind,
factorId: a.anxinStationFactorId,
struc: [], struc: [],
station: [] station: []
} }
@ -349,11 +421,14 @@ module.exports = function (app, opts) {
} }
} }
} }
let p = 1
videoAlarms = returnD videoAlarms = returnD
} }
if (c.alarmType.includes('app_exception')) { if (c.alarmType.includes('app_exception')) {
appAlarms = await models.AppAlarm.findAll({ if (c.alarmSubType) {
appAlarmWhereOption.type = { $in: c.alarmSubType['app_exception'] || [] }
}
appAlarms = c.alarmSubType && c.alarmSubType['app_exception'].length ?
await models.AppAlarm.findAll({
where: appAlarmWhereOption, where: appAlarmWhereOption,
order: [['createTime', 'DESC']], order: [['createTime', 'DESC']],
include: [{ include: [{
@ -362,31 +437,41 @@ module.exports = function (app, opts) {
include: [{ include: [{
model: models.ProjectApp, model: models.ProjectApp,
where: { where: {
projectId: pomsProjectId projectId: { $in: pomsProjectId }
}, },
required: true, required: true,
}] }]
}] }]
}) }) : []
} }
if (c.alarmType.includes('device_exception')) { if (c.alarmType.includes('device_exception')) {
dataAlarmGroupOption.push(4) dataAlarmGroupOption.push(4)
dataAlarmGroupOption.push(5) dataAlarmGroupOption.push(5)
if (c.alarmSubType) dataAlarmSubType = dataAlarmSubType.concat(c.alarmSubType['device_exception'])
} }
// 查数据告警 三警合一 // 查数据告警 三警合一
if (dataAlarmGroupOption.length && searchStrucIds.length) { if (dataAlarmGroupOption.length && searchStrucIds.length) {
dataAlarmGroupOption.push(-1) dataAlarmGroupOption.push(-1)
dataAlarmOption.push(`AlarmGroup IN (${dataAlarmGroupOption.join(',')})`) dataAlarmOption.push(`AlarmGroup IN (${dataAlarmGroupOption.join(',')})`)
dataAlarms = await clickHouse.dataAlarm.query(` if (c.alarmSubType && dataAlarmSubType.length) {
dataAlarmSubType.push(-1)
dataAlarmOption.push(`AlarmGroupUnit IN (${dataAlarmSubType.join(',')})`)
}
dataAlarms =
!c.alarmSubType || dataAlarmSubType.length ?
await clickHouse.dataAlarm.query(`
SELECT * FROM alarms SELECT * FROM alarms
LEFT JOIN ${anxinyun}.t_sensor
AS anxinStation
ON toString(anxinStation.id) = alarms.SourceId
AND alarms.SourceTypeId = 2
WHERE WHERE
${`State NOT IN (3, 4) AND `} ${`State NOT IN (3, 4) AND `}
StructureId IN (${searchStrucIds.join(',')}) StructureId IN (${searchStrucIds.join(',')})
${dataAlarmOption.length ? ' AND ' + dataAlarmOption.join(' AND ') : ''} ${dataAlarmOption.length ? ' AND ' + dataAlarmOption.join(' AND ') : ''}
ORDER BY StartTime DESC ORDER BY StartTime DESC
`).toPromise() `).toPromise() : []
console.log(dataAlarms);
} }
let dataAlarmTitle = [{ let dataAlarmTitle = [{
@ -397,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: '告警源名称',
@ -470,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: '告警信息',
@ -542,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>`
} }
@ -559,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 = [];
@ -593,12 +659,114 @@ module.exports = function (app, opts) {
let dataAlarmG3 = []; let dataAlarmG3 = [];
let dataAlarmG45 = []; let dataAlarmG45 = [];
let deviceStatistic = new Set() let deviceStatistic = new Set()
let dataAlarmDetails = []
if (proDebug) {
console.log(`查得数据告警 ${dataAlarms.length}`);
console.log(dataAlarms);
}
if (dataAlarms.length) {
const alarmIds = dataAlarms
.map(ar => "'" + ar.AlarmId + "'")
dataAlarmDetails =
await clickHouse.dataAlarm.query(`
SELECT * FROM alarm_details
WHERE AlarmId IN (${alarmIds.join(',')}, '-1')
AND AlarmState = 0
`).toPromise()
}
if (proDebug) {
console.log(`查得数据告警详情数据 ${dataAlarmDetails.length}`);
}
if (proDebug) {
console.log(`pomsStrucFactorId:`, pomsStrucFactorId);
}
let deviceIds = new Set()
for (let d of dataAlarms) { for (let d of dataAlarms) {
d = { ...d, stationId: d.id }
/** 按监测因素筛选 且为测点告警 */
// if (pomsStrucFactorId && d.SourceTypeId == 2) {
// // 做了监测因素筛选 且当前告警有监测因素
// if (!d.factor || d.factor == 0) {
// // 监测因素不对劲
// continue
// } else if (!d.StructureId) {
// // 当前告警没有绑定结构物
// continue
// } else if (!pomsStrucFactorId[d.StructureId]) {
// // 推送配置没配置这个结构物
// continue
// } else if (!pomsStrucFactorId[d.StructureId].includes(d.factor)) {
// // 不包含这个监测因素
// continue
// }
// }
if (d.AlarmGroup == 1) { if (d.AlarmGroup == 1) {
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)
)
) {
// SourceTypeId 0: 'DTU' / 1: '传感器' / 2: '测点'
if (d.SourceTypeId != 2) {
deviceIds.add(d.SourceId)
}
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 的名称筛选*/
if (pomsStrucFactorId) {
// 兼容之前的设置 有这个信息才进行判断
if (!d.StructureId) {
// 当前告警没有绑定结构物
continue
} else if (!pomsStrucFactorId[d.StructureId]) {
// 推送配置没配置这个结构物
continue
} else {
let corDetail = dataAlarmDetails.find(da => da.AlarmId == d.AlarmId)
if (proDebug) {
console.log(`相应告警详情(策略命中):`, corDetail);
}
if (corDetail) {
// 判断告警详情信息里有没有监测项关键字
if (!pomsStrucFactorId[d.StructureId].some(factorItemName => {
return corDetail.Content.includes(factorItemName)
})) {
continue
}
} else {
continue
}
}
}
if (proDebug) {
console.log(`符合条件的策略命中 + 1`, d);
}
dataAlarmG3.push(d) dataAlarmG3.push(d)
} else if (d.AlarmGroup == 4 || d.AlarmGroup == 5) { } else if (d.AlarmGroup == 4 || d.AlarmGroup == 5) {
dataAlarmG45.push(d) dataAlarmG45.push(d)
@ -609,11 +777,23 @@ module.exports = function (app, opts) {
let rate = ((deviceStatistic.size + videoAlarms.length) / (parseInt(deviceCount) + parseInt(cameraCount))); let rate = ((deviceStatistic.size + videoAlarms.length) / (parseInt(deviceCount) + parseInt(cameraCount)));
if (rate < parseFloat(deviceProportion)) { if (rate < parseFloat(deviceProportion)) {
// 设备异常率低于设定值
continue continue
} }
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>
@ -633,49 +813,151 @@ 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) {
if (proDebug) {
console.log(`查得数据异常、视频异常合并の告警:`);
console.log(apMergeDeVeAlarms);
}
let deviceSensorRes = []
if (deviceIds.size) {
const device4Search = [...deviceIds]
.map(id => "'" + id + "'")
deviceSensorRes = await clickHouse.anxinyun.query(`
SELECT
iota_device_id, sensor
FROM t_device_sensor
WHERE iota_device_id
${device4Search.length > 1 ? `IN (${device4Search.join(',')})` : `= ${device4Search[0]}`}
`).toPromise()
}
if (proDebug) {
console.log(`相关设备及测点信息:`);
console.log(deviceSensorRes);
}
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) {
if (!de.id) {
let corSensor = deviceSensorRes.find(ds => ds.iota_device_id == de.SourceId)
if (corSensor) {
de.id = corSensor.sensor
}
}
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) {
@ -687,13 +969,19 @@ module.exports = function (app, opts) {
`).toPromise() `).toPromise()
: [] : []
let receiverId = [] let receiverId = []
const emails = receiverRes.reduce((arr, r) => { let emails = receiverRes.reduce((arr, r) => {
if (r.email) { if (r.email) {
arr.push(r.email) arr.push(r.email)
receiverId.push({ id: r.id, name: r.name }) receiverId.push({ id: r.id, name: r.name })
} }
return arr return arr
}, []) }, [])
if (isDev) {
// !开发测试用的数据
emails = ['1650192445@qq.com']
}
if (emails.length) { if (emails.length) {
await pushByEmail({ await pushByEmail({
email: emails, email: emails,
@ -717,12 +1005,11 @@ module.exports = function (app, opts) {
let dynamic = { let dynamic = {
time: r.dataValues.time, time: r.dataValues.time,
emailSendId: r.dataValues.id, emailSendId: r.dataValues.id,
projectCorrelationId: r.dataValues.projectCorrelationId, // projectCorrelationId: r.dataValues.projectCorrelationId,
type: 2//通知 type: 2//通知
} }
await models.LatestDynamicList.create(dynamic); await models.LatestDynamicList.create(dynamic);
//消息推送到前端 //消息推送到前端
await sendNoticeToWeb(receiverId, dataToSave); await sendNoticeToWeb(receiverId, dataToSave);
} }
@ -730,7 +1017,6 @@ module.exports = function (app, opts) {
} }
} }
} }
}
} catch (error) { } catch (error) {
console.error(error); console.error(error);

2
api/app/lib/utils/alarmHandle.js

@ -110,7 +110,7 @@ module.exports = function (app, opts) {
} }
let pepProjects = pepPojectIds.size ? await clickHouse.projectManage.query(` let pepProjects = pepPojectIds.size ? await clickHouse.projectManage.query(`
SELECT id, project_name FROM t_pim_project WHERE id IN (${[...pepPojectIds]}, -1)` SELECT id, project_name FROM t_pim_project WHERE id IN (${[...pepPojectIds].join(',')}, -1)`
).toPromise() : []; ).toPromise() : [];
return { projects, pepProjects }; return { projects, pepProjects };

5
api/config.js

@ -19,6 +19,8 @@ args.option('redisHost', 'redisHost');
args.option('redisPort', 'redisPort'); args.option('redisPort', 'redisPort');
args.option('redisPswd', 'redisPassword'); args.option('redisPswd', 'redisPassword');
args.option('apMergeDeVeAnxinProjectId', '告警推送自定义の合并数据异常(De)视频异常(Ve)的指定的结构物id');
args.option('axyApiUrl', '安心云 api'); args.option('axyApiUrl', '安心云 api');
args.option('apiEmisUrl', '企业管理 api'); args.option('apiEmisUrl', '企业管理 api');
args.option('apiVcmpUrl', '视频平台 api'); args.option('apiVcmpUrl', '视频平台 api');
@ -67,6 +69,8 @@ const IOTA_REDIS_SERVER_HOST = process.env.IOTA_REDIS_SERVER_HOST || flags.redis
const IOTA_REDIS_SERVER_PORT = process.env.IOTA_REDIS_SERVER_PORT || flags.redisPort || "6379";//redis 端口 const IOTA_REDIS_SERVER_PORT = process.env.IOTA_REDIS_SERVER_PORT || flags.redisPort || "6379";//redis 端口
const IOTA_REDIS_SERVER_PWD = process.env.IOTA_REDIS_SERVER_PWD || flags.redisPswd || "";//redis 密码 const IOTA_REDIS_SERVER_PWD = process.env.IOTA_REDIS_SERVER_PWD || flags.redisPswd || "";//redis 密码
const AP_MERGE_DEVE_ANXINPROJECT_ID = process.env.AP_MERGE_DEVE_ANXINPROJECT_ID || flags.apMergeDeVeAnxinProjectId || "";
// 安心云api // 安心云api
const API_ANXINYUN_URL = process.env.API_ANXINYUN_URL || flags.axyApiUrl; const API_ANXINYUN_URL = process.env.API_ANXINYUN_URL || flags.axyApiUrl;
// 企业管理 api // 企业管理 api
@ -155,6 +159,7 @@ const product = {
{ p: '/alarm/application/api', o: 'POST' }, { p: '/alarm/application/api', o: 'POST' },
{ p: '/alarm/video/added_log', o: 'POST' } { p: '/alarm/video/added_log', o: 'POST' }
], // 不做认证的路由,也可以使用 exclude: ["*"] 跳过所有路由 ], // 不做认证的路由,也可以使用 exclude: ["*"] 跳过所有路由
apMergeDeVeAnxinProjectId: AP_MERGE_DEVE_ANXINPROJECT_ID,
anxinCloud: { anxinCloud: {
confirmAlarmAnxinUserId: CONFIRM_ALARM_ANXIN_USER_ID confirmAlarmAnxinUserId: CONFIRM_ALARM_ANXIN_USER_ID
}, },

12
jenkinsfile_poms_api

@ -6,13 +6,13 @@ pipeline {
} }
stages { stages {
stage('Testing poms ......') { stage('Testing site......') {
steps { steps {
sh 'switch-auth.sh anxinyun' buildName "#${BUILD_NUMBER} ~/iot/${JOB_NAME}:${IMAGE_VERSION}"
buildName "#${BUILD_NUMBER} ~/fs-cloud/${JOB_NAME}:${IMAGE_VERSION}" buildDescription "harbor.anxinyun.cn/iot/${JOB_NAME}:${IMAGE_VERSION}"
buildDescription "registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION}" sh 'nerdctl build -t harbor.anxinyun.cn/iot/${JOB_NAME}:${IMAGE_VERSION} ./api'
sh 'docker build -t registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION} ./api' sh 'nerdctl push harbor.anxinyun.cn/iot/${JOB_NAME}:${IMAGE_VERSION}'
sh 'docker push registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION}'
} }
} }
} }

12
jenkinsfile_poms_web

@ -6,13 +6,13 @@ pipeline {
} }
stages { stages {
stage('Testing poms ......') { stage('Testing site......') {
steps { steps {
sh 'switch-auth.sh anxinyun' buildName "#${BUILD_NUMBER} ~/iot/${JOB_NAME}:${IMAGE_VERSION}"
buildName "#${BUILD_NUMBER} ~/fs-cloud/${JOB_NAME}:${IMAGE_VERSION}" buildDescription "harbor.anxinyun.cn/iot/${JOB_NAME}:${IMAGE_VERSION}"
buildDescription "registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION}" sh 'nerdctl build -t harbor.anxinyun.cn/iot/${JOB_NAME}:${IMAGE_VERSION} ./web'
sh 'docker build -t registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION} ./web' sh 'nerdctl push harbor.anxinyun.cn/iot/${JOB_NAME}:${IMAGE_VERSION}'
sh 'docker push registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION}'
} }
} }
} }

16
script/0.10/schema/1.alter_alarm_push_config.sql

@ -0,0 +1,16 @@
alter table alarm_push_config
add alarm_sub_type jsonb;
comment on column alarm_push_config.alarm_sub_type is '存对应监听模块(alarm_type)的子类(
alarms.AlarmGroupUnit,
camera.kind_id,
app_alarm.errType
)';
ALTER TABLE alarm_push_config ALTER COLUMN poms_project_id TYPE INTEGER []
USING CASE
WHEN poms_project_id is NULL
then NULL
ELSE array [poms_project_id]
END ::INTEGER [];

4
script/0.11/schema/1.alter_alarm_push_config.sql

@ -0,0 +1,4 @@
alter table alarm_push_config
add poms_struc_factor_id jsonb;
comment on column alarm_push_config.poms_struc_factor_id is '结构物对应监测项 id';

6
script/0.11/schema/2.alter_email_send_log.sql

@ -0,0 +1,6 @@
ALTER TABLE email_send_log ALTER COLUMN project_correlation_id TYPE INTEGER []
USING CASE
WHEN project_correlation_id is NULL
then NULL
ELSE array [project_correlation_id]
END ::INTEGER [];

1
script/0.11/schema/3.alert_latest_dynamic_list.sql

@ -0,0 +1 @@
alter table latest_dynamic_list alter column project_correlation_id drop not null;

44
web/Dockerfile

@ -1,40 +1,40 @@
# FROM repository.anxinyun.cn/devops/node:12-dev as builder FROM registry.cn-hangzhou.aliyuncs.com/fs-devops/node:12-dev as builder
# COPY . /var/app COPY . /var/app
# WORKDIR /var/app WORKDIR /var/app
# EXPOSE 8080 EXPOSE 8080
# RUN npm config set registry=http://10.8.30.22:7000 RUN npm config set registry=http://10.8.30.22:7000
# RUN echo "{\"time\":\"$BUILD_TIMESTAMP\",\"build\": \"$BUILD_NUMBER\",\"revision\": \"$SVN_REVISION_1\",\"URL\":\"$SVN_URL_1\"}" > version.json RUN echo "{\"time\":\"$BUILD_TIMESTAMP\",\"build\": \"$BUILD_NUMBER\",\"revision\": \"$SVN_REVISION_1\",\"URL\":\"$SVN_URL_1\"}" > version.json
# RUN npm cache clean -f RUN npm cache clean -f
# RUN npm install --registry http://10.8.30.22:7000 RUN npm install --registry http://10.8.30.22:7000
# RUN npm run build RUN npm run build
# RUN rm -rf client/src RUN rm -rf client/src
# RUN rm -rf node_modules RUN rm -rf node_modules
# RUN npm install --production --registry http://10.8.30.22:7000 RUN npm install --production --registry http://10.8.30.22:7000
# FROM registry.cn-hangzhou.aliyuncs.com/fs-devops/node-16:7.22-06-20 FROM registry.cn-hangzhou.aliyuncs.com/fs-devops/node-16:7.22-06-20
# COPY --from=builder --chown=node /var/app /home/node/app COPY --from=builder --chown=node /var/app /home/node/app
# WORKDIR /home/node/app WORKDIR /home/node/app
# CMD ["node", "server.js"] CMD ["node", "server.js"]
# 旧版本构建方式 # 旧版本构建方式
FROM repository.anxinyun.cn/base-images/nodejs12:20.10.12.2 # FROM repository.anxinyun.cn/base-images/nodejs12:20.10.12.2
COPY . /var/app # COPY . /var/app
WORKDIR /var/app # WORKDIR /var/app
EXPOSE 8080 # EXPOSE 8080
CMD ["-u", "http://localhost:8088"] # CMD ["-u", "http://localhost:8088"]
ENTRYPOINT [ "node", "server.js" ] # ENTRYPOINT [ "node", "server.js" ]

BIN
web/client/assets/images/background/B.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
web/client/assets/images/background/General.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

2
web/client/src/layout/actions/global.js

@ -39,6 +39,8 @@ export function initApiRoot () {
payload: { payload: {
apiRoot: res.root, apiRoot: res.root,
iotVcmpWeb:res.iotVcmpWeb, iotVcmpWeb:res.iotVcmpWeb,
pomsMonitor:res.pomsMonitor,
dcWeb:res.dcWeb,
} }
}) })
}); });

6
web/client/src/layout/reducers/global.js

@ -12,6 +12,8 @@ function global (state = {
clientWidth: 1024, clientWidth: 1024,
apiRoot: '', apiRoot: '',
iotVcmpWeb: '', iotVcmpWeb: '',
pomsMonitor:'',
dcWeb:'',
}, action) { }, action) {
const payload = action.payload; const payload = action.payload;
switch (action.type) { switch (action.type) {
@ -31,7 +33,9 @@ function global (state = {
case INIT_API_ROOT: case INIT_API_ROOT:
return Immutable.fromJS(state).merge({ return Immutable.fromJS(state).merge({
apiRoot: payload.apiRoot, apiRoot: payload.apiRoot,
iotVcmpWeb: payload.iotVcmpWeb iotVcmpWeb: payload.iotVcmpWeb,
pomsMonitor:payload.pomsMonitor,
dcWeb:payload.dcWeb,
}).toJS(); }).toJS();
case PEPPROJECTID: case PEPPROJECTID:
return Immutable.fromJS(state).merge({ return Immutable.fromJS(state).merge({

64
web/client/src/sections/control/containers/control.jsx

@ -8,7 +8,6 @@ import repairFQA from '../../means/containers/repairFQA';
import { Setup, OutHidden } from "$components"; import { Setup, OutHidden } from "$components";
import ReactECharts from 'echarts-for-react'; import ReactECharts from 'echarts-for-react';
import moment from "moment"; import moment from "moment";
import { log } from 'ezuikit-js';
let newScrollbar; let newScrollbar;
let overviewScrollbar; let overviewScrollbar;
@ -43,7 +42,7 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
const [videoBI, setVideoBI] = useState([]); //BI- const [videoBI, setVideoBI] = useState([]); //BI-
const [appBI, setAppBI] = useState([]); //BI- const [appBI, setAppBI] = useState([]); //BI-
const [efficiencyBI, setEfficiencyBI] = useState({}); //BI- const [efficiencyBI, setEfficiencyBI] = useState({}); //BI-
const [query, setQuery] = useState({ limit: 10, page: 0, projectCorrelationId: '', types: '1' }); // const [query, setQuery] = useState({ limit: 23, page: 0, projectCorrelationId: '', types: '1' }); //
const [querydata1, setQueryData1] = useState([]); // const [querydata1, setQueryData1] = useState([]); //
const [long, setLong] = useState(''); // const [long, setLong] = useState(''); //
const [pomsList, setPomsList] = useState([]); // const [pomsList, setPomsList] = useState([]); //
@ -398,6 +397,7 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
})) }))
} }
if (exhibition?.current?.dynamic?.find(v => v.key == 'notice')) { if (exhibition?.current?.dynamic?.find(v => v.key == 'notice')) {
// EM
res.payload.data?.notice?.map(v => data.push({ res.payload.data?.notice?.map(v => data.push({
seed: 'notice', seed: 'notice',
time: v.time, time: v.time,
@ -444,14 +444,26 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
const line = document.getElementById("line") const line = document.getElementById("line")
const news = document.getElementById("news") const news = document.getElementById("news")
if (line && news) { if (line && news) {
news.onscroll = () => { news.onscroll = (e) => {
e.stopPropagation();
if ((line.clientHeight - 578) < news.scrollTop + 10) { if ((line.clientHeight - 578) < news.scrollTop + 10) {
setQuery({ ...query, page: query.page + 1 }) setQuery({ ...query, page: query.page + 1 })
if (exhibition?.current?.dynamic?.length > 0) { if (exhibition?.current?.dynamic?.length > 0) {
dispatch(control.getLatestDynamic({ ...query, projectCorrelationId: pepProjectId, page: query.page + 1 })).then(res => { dispatch(control.getLatestDynamic({ ...query, projectCorrelationId: pepProjectId, page: query.page + 1 })).then(res => {
news.scrollTop = news.scrollTop - 640 // news.scrollTop = news.scrollTop - 640
let data = querydata.current let data = querydata.current
if (res.success) { if (res.success) {
let returnJudge = true
for (let k in res.payload.data) {
if (res.payload.data[k].length) {
returnJudge = false
break
}
}
if (returnJudge) {
return
}
if (exhibition?.current?.dynamic?.find(v => v.key == 'discovery')) { if (exhibition?.current?.dynamic?.find(v => v.key == 'discovery')) {
res.payload.data?.appear?.map(v => data.push({ res.payload.data?.appear?.map(v => data.push({
seed: 'discovery', seed: 'discovery',
@ -503,9 +515,6 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
const domProject = document.getElementById("news"); const domProject = document.getElementById("news");
if (domProject) { if (domProject) {
// newScrollbar = new PerfectScrollbar("#news", {
// suppressScrollX: true,
// });
if (domProject && newScrollbar) { if (domProject && newScrollbar) {
newScrollbar.update(); newScrollbar.update();
} }
@ -513,9 +522,6 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
const pomsList = document.getElementById("pomsList"); const pomsList = document.getElementById("pomsList");
if (pomsList) { if (pomsList) {
// pomsListScrollbar = new PerfectScrollbar("#pomsList", {
// suppressScrollX: true,
// });
if (pomsList && pomsListScrollbar) { if (pomsList && pomsListScrollbar) {
pomsListScrollbar.update(); pomsListScrollbar.update();
} }
@ -523,9 +529,6 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
const domProject1 = document.getElementById("overviewCalc"); const domProject1 = document.getElementById("overviewCalc");
if (domProject1) { if (domProject1) {
// overviewScrollbar = new PerfectScrollbar("#overviewCalc", {
// suppressScrollY: true,
// });
if (domProject1 && overviewScrollbar) { if (domProject1 && overviewScrollbar) {
overviewScrollbar.update(); overviewScrollbar.update();
} }
@ -533,9 +536,6 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
const domProject2 = document.getElementById("member"); const domProject2 = document.getElementById("member");
if (domProject2) { if (domProject2) {
// memberScrollbar = new PerfectScrollbar("#member", {
// suppressScrollX: true,
// });
if (domProject2 && memberScrollbar) { if (domProject2 && memberScrollbar) {
memberScrollbar.update(); memberScrollbar.update();
} }
@ -543,9 +543,6 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
const domProject3 = document.getElementById("equipment"); const domProject3 = document.getElementById("equipment");
if (domProject3) { if (domProject3) {
// equipmentScrollbar = new PerfectScrollbar("#equipment", {
// suppressScrollX: true,
// });
if (domProject3 && equipmentScrollbar) { if (domProject3 && equipmentScrollbar) {
equipmentScrollbar.update(); equipmentScrollbar.update();
} }
@ -553,9 +550,6 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
const domProject4 = document.getElementById("web"); const domProject4 = document.getElementById("web");
if (domProject4) { if (domProject4) {
// webScrollbar = new PerfectScrollbar("#web", {
// suppressScrollX: true,
// })
if (domProject4 && webScrollbar) { if (domProject4 && webScrollbar) {
webScrollbar.update(); webScrollbar.update();
} }
@ -563,9 +557,6 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
const domProject5 = document.getElementById("problems"); const domProject5 = document.getElementById("problems");
if (domProject5) { if (domProject5) {
// problemsScrollbar = new PerfectScrollbar("#problems", {
// suppressScrollX: true,
// });
if (domProject5 && problemsScrollbar) { if (domProject5 && problemsScrollbar) {
problemsScrollbar.update(); problemsScrollbar.update();
} }
@ -573,17 +564,11 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
const domProject6 = document.getElementById("alarm"); const domProject6 = document.getElementById("alarm");
if (domProject6) { if (domProject6) {
// alarmScrollbar = new PerfectScrollbar("#alarm", {
// suppressScrollY: true,
// });
if (domProject6 && alarmScrollbar) { if (domProject6 && alarmScrollbar) {
alarmScrollbar.update(); alarmScrollbar.update();
} }
} }
// ACTION
// dispatch(actions.example.getMembers(user.orgId))
}) })
const consoleToollink = () => { const consoleToollink = () => {
@ -625,8 +610,6 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
let Select = { let Select = {
overall: ['workbench', 'statistical', 'analyse', 'dynamic', 'tool'], overall: ['workbench', 'statistical', 'analyse', 'dynamic', 'tool'],
workbench: ['project', 'data', 'app', 'device'], workbench: ['project', 'data', 'app', 'device'],
@ -672,8 +655,6 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
{ name: 'BI分析模块', sort: 3, key: 'analyse', }, { name: 'BI分析模块', sort: 3, key: 'analyse', },
{ name: '最新动态', sort: 4, key: 'dynamic', }, { name: '最新动态', sort: 4, key: 'dynamic', },
{ name: '我常用的工具', sort: 5, key: 'tool', }, { name: '我常用的工具', sort: 5, key: 'tool', },
] ]
useEffect(() => { useEffect(() => {
@ -1245,8 +1226,8 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
}} /> }} />
</div> </div>
</div> </div>
<div id='news' style={{ height: 578, position: 'relative', marginTop: 10, }}> <div id='news' style={{ height: 578, position: 'relative', marginTop: 10, overscrollBehavior: 'contain', }}>
<div id='line' style={{ width: '100%' }}> <div id='line' style={{ width: '100%', }}>
<Timeline mode="center" style={{ marginLeft: '-56px', width: 400 }}> <Timeline mode="center" style={{ marginLeft: '-56px', width: 400 }}>
{querydata.current?.map((v, index) => { {querydata.current?.map((v, index) => {
let title = '' let title = ''
@ -1256,8 +1237,13 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
title = v.userName ? (v.userName + '确认并关闭' + v.project + '【' + v.sources + '】' + v.type + '的问题') : title = v.userName ? (v.userName + '确认并关闭' + v.project + '【' + v.sources + '】' + v.type + '的问题') :
v.project + '【' + v.sources + '】' + v.type + '已恢复' v.project + '【' + v.sources + '】' + v.type + '已恢复'
} else { } else {
title = '【信鸽-' + v.alarmPushConfig + '】已邮件通知' + title =
v.userName?.map((u, i) => (i > 0 ? ',' + u : u)) + '【' + v.project + '】【' + '【信鸽-' + v.alarmPushConfig + '】已邮件通知'
+
v.userName?.map((u, i) => (i > 0 ? ',' + u : u))
+ '【' + v.project
+ '】【'
+
(v.tactics == 'immediately' ? (v.tactics == 'immediately' ?
'发现在' + v.interval + '分钟内,有告警源新增' : '发现在' + v.interval + '分钟内,有告警源新增' :
(v.tactics == 'continue' ? '告警源持续产生时间超过' + v.interval + '分钟' : '异常设备数量达到项目或结构物内设备总数量的' + (v.tactics == 'continue' ? '告警源持续产生时间超过' + v.interval + '分钟' : '异常设备数量达到项目或结构物内设备总数量的' +

4
web/client/src/sections/control/containers/userCenter.jsx

@ -16,10 +16,10 @@ const UserCenter = (props) => {
<div style={{ margin: '4px 0px 14px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}> <div style={{ margin: '4px 0px 14px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', alignItems: 'center' }}> <div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ color: '#4A4A4A', fontSize: 14 }}> <div style={{ color: '#4A4A4A', fontSize: 14 }}>
HI欢迎回来行业服务部 HI欢迎回来{user?.department[0]?.name}
</div> </div>
<div style={{ fontFamily: 'YouSheBiaoTiHei', fontSize: 20, color: '#005ABD', marginLeft: 4 }}> <div style={{ fontFamily: 'YouSheBiaoTiHei', fontSize: 20, color: '#005ABD', marginLeft: 4 }}>
刘昊然 {user?.name}
</div> </div>
</div> </div>
</div> </div>

28
web/client/src/sections/facility/containers/monitor.jsx

@ -4,7 +4,7 @@ import { connect } from 'react-redux';
const Server = (props) => { const Server = (props) => {
const { dispatch, actions, user, loading, socket } = props const { dispatch, actions, user, loading, socket, pomsMonitor } = props
useEffect(() => { useEffect(() => {
@ -13,13 +13,32 @@ const Server = (props) => {
return ( return (
<> <>
<div> <div style={{
<img src="/assets/images/install/watting.png" alt="" style={{ width: 'calc(100% + 16px)', position: "relative", top: -12, left: -8, }} /> height: 'calc(100vh - 60px)', width: 'calc(100% + 16px)',
backgroundImage: "url('/assets/images/background/General.png')",
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
position: 'relative',
top: -12, left: -8,
}}>
<div style={{ position: 'absolute', top: 'calc(50%)', left: 'calc(10%)', }}>
<div style={{
width: 184, height: 48, fontWeight: 400, color: '#FFFFFF', lineHeight: '48px', backgroundImage: "url('/assets/images/background/B.png')", textAlign: 'center',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
}}>
<a target='_blank' href={pomsMonitor}
style={{width:'100%',height:'100%',display: 'block'}}
> 进入Grafana</a>
</div>
<div style={{ width: 679, height: 40, fontSize: 28, fontWeight: 400, color: '#146AD7', lineHeight: '40px', marginTop: 40 }}>
点击可跳转服务器监控网站Grafana</div>
</div>
{/* <iframe frameBorder="0" src={pomsMonitor} style={{height: 'calc(100vh - 80px)', width: 'calc(100%)'}} /> */}
</div> </div>
</> </>
) )
} }
function mapStateToProps (state) { function mapStateToProps (state) {
const { auth, global, members, webSocket } = state; const { auth, global, members, webSocket } = state;
return { return {
@ -28,6 +47,7 @@ function mapStateToProps (state) {
// actions: global.actions, // actions: global.actions,
// members: members.data, // members: members.data,
// socket: webSocket.socket // socket: webSocket.socket
pomsMonitor: global.pomsMonitor,
}; };
} }

1
web/client/src/sections/facility/nav-item.jsx

@ -41,3 +41,4 @@ export function getNavItem (user, dispatch) {
] ]
); );
} }

2
web/client/src/sections/install/containers/system.jsx

@ -258,7 +258,7 @@ const Example = (props) => {
}, },
{ {
title: "管理", title: "管理",
width: "20%", width: "150px",
dataIndex: "text", dataIndex: "text",
key: 'text', key: 'text',
render: (_, row) => { render: (_, row) => {

6
web/client/src/sections/problem/actions/problem.jsx

@ -64,10 +64,11 @@ export function postApiConfirm (data) { //确认应用接口/元素错误信
}); });
} }
export function getAlarmDataGroup () { // export function getAlarmDataGroup (query) { //
return dispatch => basicAction({ return dispatch => basicAction({
type: 'get', type: 'get',
dispatch: dispatch, dispatch: dispatch,
query,
actionType: 'GET_ALARM_DATA_GROUP', actionType: 'GET_ALARM_DATA_GROUP',
url: `${ApiTable.getAlarmDataGroup}`, url: `${ApiTable.getAlarmDataGroup}`,
msg: { option: '获取数据告警分类' }, msg: { option: '获取数据告警分类' },
@ -138,10 +139,11 @@ export function getAlarmVideoList (query) { //查询视频告警列表
export function getAlarmVideoDeviceKind () { // export function getAlarmVideoDeviceKind (query) { //
return dispatch => basicAction({ return dispatch => basicAction({
type: 'get', type: 'get',
dispatch: dispatch, dispatch: dispatch,
query,
actionType: 'GET_ALARM_VIDEO_DEVICE_KIND', actionType: 'GET_ALARM_VIDEO_DEVICE_KIND',
url: `${ApiTable.getAlarmVideoDeviceKind}`, url: `${ApiTable.getAlarmVideoDeviceKind}`,
msg: { option: '查询视频设备类型' }, msg: { option: '查询视频设备类型' },

18
web/client/src/sections/problem/components/tableData.jsx

@ -379,12 +379,23 @@ const TableData = ({ route, dispatch, actions, collectData, setSetup, exhibition
placeholder={SkeletonScreen()} placeholder={SkeletonScreen()}
> >
{(() => { {(() => {
// console.log(tableData); console.log(tableData);
console.log((route == 'useAbnormal' || route == 'videoAbnormal') ?
(tableData?.slice(query.page * query.limit, (query.page + 1) * query.limit) || [])
: tableData);
return <Table return <Table
columns={exhibition} columns={exhibition}
dataSource={route == 'useAbnormal' || route == 'videoAbnormal' ? tableData.slice(query.page * query.limit, (query.page + 1) * query.limit) || [] : tableData} dataSource={
(route == 'useAbnormal' || route == 'videoAbnormal') ?
(tableData?.slice(query.page * query.limit, (query.page + 1) * query.limit) || [])
: tableData
}
bordered={false} bordered={false}
empty={<div><img src="/assets/images/problem/shield.png" style={{ width: 20 }} />暂无告警数据</div>} empty={
<div>
<img src="/assets/images/problem/shield.png" style={{ width: 20 }} />暂无告警数据
</div>
}
style={{}} style={{}}
pagination={false} pagination={false}
onRow={(record, index) => { onRow={(record, index) => {
@ -457,7 +468,6 @@ const TableData = ({ route, dispatch, actions, collectData, setSetup, exhibition
pageSizeOpts={[10, 20, 30, 40]} pageSizeOpts={[10, 20, 30, 40]}
onChange={(currentPage, pageSize) => { onChange={(currentPage, pageSize) => {
setQuery({ limit: pageSize, page: currentPage - 1 }); setQuery({ limit: pageSize, page: currentPage - 1 });
}} }}
/> />
</div> : ""} </div> : ""}

490
web/client/src/sections/service/components/pushModal.jsx

@ -1,6 +1,6 @@
import React, { useState, useRef, useEffect } from "react"; import React, { useState, useRef, useEffect } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Modal, Form, Notification } from "@douyinfe/semi-ui"; import { Modal, Form, Notification, Tooltip } from "@douyinfe/semi-ui";
import { IconAlertCircle } from '@douyinfe/semi-icons'; import { IconAlertCircle } from '@douyinfe/semi-icons';
import './pushModal.less' import './pushModal.less'
@ -15,9 +15,10 @@ function pushModal (props) {
actions, actions,
pushEdit,// pushEdit,//
editObj, editObj,
user user,
subTypeData
} = props; } = props;
const { service } = actions; const { service, problem } = actions;
const form = useRef();// const form = useRef();//
const [abnormal, setAbnormal] = useState(false); //disable const [abnormal, setAbnormal] = useState(false); //disable
const [usersList, setUsersList] = useState([]); // const [usersList, setUsersList] = useState([]); //
@ -32,22 +33,24 @@ function pushModal (props) {
const [interval2, setInterval2] = useState(undefined); // const [interval2, setInterval2] = useState(undefined); //
const [interval3, setInterval3] = useState(undefined); // const [interval3, setInterval3] = useState(undefined); //
const [deviceProportion, setDeviceProportion] = useState(undefined); // const [deviceProportion, setDeviceProportion] = useState(undefined); //
const [subType, setSubType] = useState([]); //
const [factorShow, setFactorShow] = useState([]); //
const [firstPass, setFirstPass] = useState(true)
// //
useEffect(() => { useEffect(() => {
if (editObj?.alarmType) setSubType(editObj?.alarmType)
getOrganizationUsersList()// getOrganizationUsersList()//
getProjectPomsList()// getProjectPomsList()//
if (editObj.id) { if (editObj.id) {
getProjectStructureList(editObj.pomsProjectId) getProjectStructureList(editObj.pomsProjectId, editObj)
if (editObj.pomsProject?.pepProjectId) { let division = editObj?.pomsProject?.map(v => (v.pepProject?.id || 'POMS'))
getProjectStatusList()// if (division.length == 1 && division?.includes('POMS')) {
}
else {
setProjectStatus([{ construction_status: 'POMS', id: 'POMS' }]) setProjectStatus([{ construction_status: 'POMS', id: 'POMS' }])
timeTypePOMS.current = ['POMS'] timeTypePOMS.current = ['POMS']
} else {
getProjectStatusList()//
} }
if (editObj.tactics == 'immediately') { if (editObj.tactics == 'immediately') {
setInterval1(editObj.tacticsParams?.interval) setInterval1(editObj.tacticsParams?.interval)
@ -58,7 +61,7 @@ function pushModal (props) {
setDeviceProportion(editObj.tacticsParams?.deviceProportion) setDeviceProportion(editObj.tacticsParams?.deviceProportion)
} }
} }
}, []); }, [])
function getOrganizationUsersList () {// function getOrganizationUsersList () {//
dispatch(service.getOrganizationUsers()).then((res) => { dispatch(service.getOrganizationUsers()).then((res) => {
if (res.success) { if (res.success) {
@ -73,15 +76,34 @@ function pushModal (props) {
} }
}) })
} }
function getProjectStructureList (value) {// function getProjectStructureList (value, alter) {//
dispatch(service.getProjectStructure({ pomsProjectId: value })).then((res) => { dispatch(service.getProjectStructure({ pomsProjectId: value.join(',') })).then((res) => {
if (res.success) { if (res.success) {
let mylist = [] let data = []
for (let i = 0; i < res.payload?.data.length; i++) { let ProjectId = []
mylist.push(res.payload?.data[i].id) let factorId = []
res.payload?.data.map(v => {
if (ProjectId.includes(v.id)) {
} else {
ProjectId.push(v.id)
data.push(v)
}
})
setProjectStructure(data)
if (editObj.id && firstPass) {
let FactorId = []
if (alter?.pomsStrucFactorId) {
for (let key in alter?.pomsStrucFactorId) {
FactorId.push(key)
}
setFactorShow(FactorId?.map(Number))
} else {
setFactorShow(ProjectId)
}
setFirstPass(false)
} else {
form.current.setValue('strucId', ProjectId)
} }
setProjectStructure(res.payload?.data)
form.current.setValue('strucId', mylist)
form.current.validate(['strucId', 'timeType']) form.current.validate(['strucId', 'timeType'])
setStructure(false) setStructure(false)
setTimeTypeDis(false) setTimeTypeDis(false)
@ -93,286 +115,88 @@ function pushModal (props) {
if (res.success) { if (res.success) {
setProjectStatus(res.payload?.data) setProjectStatus(res.payload?.data)
let mylist = [] let mylist = []
if (editObj?.id) {
mylist = editObj?.timeType.map(Number) || []
} else {
for (let i = 0; i < res.payload?.data.length; i++) { for (let i = 0; i < res.payload?.data.length; i++) {
mylist.push(res.payload?.data[i].id) mylist.push(res.payload?.data[i].id)
} }
}
form.current.setValue('timeType', mylist) form.current.setValue('timeType', mylist)
form.current.validate(['strucId', 'timeType']) form.current.validate(['strucId', 'timeType'])
} }
}) })
} }
function handleOk () { function caution (tactics, interval, deviceProportion, data) {
//
form.current
.validate()
.then((values) => {
if (pushEdit) {
let obj = JSON.parse(JSON.stringify(values))
if (obj.timeType[0] == 'POMS') {
obj.timeType = []
}
let regu = /^[0-9]*[1-9][0-9]*$/;
if (obj.tactics == 'immediately') {
if (obj.interval1) {
if (regu.test(obj.interval1)) {
if (obj.interval1 <= 1440) {
obj.tacticsParams = {
interval: obj.interval1
}
delete obj.interval1
delete obj.interval2
delete obj.interval3
delete obj.deviceProportion
dispatch(service.postPush({ pushId: editObj.id, ...obj, msg: '编辑推送配置' })).then((res) => {//(PEP)
if (res.success) {
close();
}
})
} else {
Notification.error({
content: '即时推送时间不能大于1440分钟',
duration: 2,
})
}
} else {
Notification.error({
content: '即时推送时间应为正整数',
duration: 2,
})
}
} else {
Notification.error({
content: '即时推送时间应为正整数',
duration: 2,
})
}
}
else if (obj.tactics == 'continue') {
if (obj.interval2) {
if (regu.test(obj.interval2)) {
if (obj.interval2 <= 1440) {
obj.tacticsParams = {
interval: obj.interval2
}
delete obj.interval1
delete obj.interval2
delete obj.interval3
delete obj.deviceProportion
dispatch(service.postPush({ pushId: editObj.id, ...obj, msg: '编辑推送配置' })).then((res) => {//(PEP)
if (res.success) {
close();
}
})
} else {
Notification.error({
content: '持续时长推送时间不能大于1440分钟',
duration: 2,
})
}
} else {
Notification.error({
content: '持续时长推送时间应为正整数',
duration: 2,
})
}
} else {
Notification.error({
content: '持续时长推送时间应为正整数',
duration: 2,
})
}
}
else {
if (regu.test(obj.interval3) && regu.test(obj.deviceProportion)) {
if (obj.interval3 <= 720 && obj.deviceProportion <= 100) {
obj.tacticsParams = {
interval: obj.interval3,
deviceProportion: obj.deviceProportion
}
delete obj.interval1
delete obj.interval2
delete obj.interval3
delete obj.deviceProportion
dispatch(service.postPush({ pushId: editObj.id, ...obj, msg: '编辑推送配置' })).then((res) => {//(PEP)
if (res.success) {
close();
}
})
} else if (obj.interval3 <= 720 && obj.deviceProportion > 100) {
Notification.error({
content: '异常率推送异常率不能超过100%',
duration: 2,
})
} else if (obj.interval3 > 720 && obj.deviceProportion <= 100) {
Notification.error({
content: '异常率推送时间不能超过720小时',
duration: 2,
})
} else {
Notification.error({
content: '异常率推送时间不能超过720小时',
duration: 2,
})
Notification.error({
content: '异常率推送异常率不能超过100%',
duration: 2,
})
}
} else if (regu.test(obj.interval3) && !regu.test(obj.deviceProportion)) {
Notification.error({
content: '异常率推送异常率应为正整数',
duration: 2,
})
} else if (!regu.test(obj.interval3) && regu.test(obj.deviceProportion)) {
Notification.error({
content: '异常率推送时间应为正整数',
duration: 2,
})
} else {
Notification.error({
content: '异常率推送异常率应为正整数',
duration: 2,
})
Notification.error({
content: '异常率推送时间应为正整数',
duration: 2,
})
}
}
}
else {
let obj = JSON.parse(JSON.stringify(values))
if (obj.timeType[0] == 'POMS') {
obj.timeType = []
}
let regu = /^[0-9]*[1-9][0-9]*$/; let regu = /^[0-9]*[1-9][0-9]*$/;
if (obj.tactics == 'immediately') { let title = tactics == 'immediately' ? '即时' : tactics == 'continue' ? '持续时长' : '异常率'
if (obj.interval1) { if (!regu.test(interval) || (tactics == 'abnormal_rate' && interval > 720) || interval > 1440) {
if (regu.test(obj.interval1)) {
if (obj.interval1 <= 1440) {
obj.tacticsParams = {
interval: obj.interval1
}
delete obj.interval1
delete obj.interval2
delete obj.interval3
delete obj.deviceProportion
dispatch(service.postPush({ ...obj, msg: '新增推送配置' })).then((res) => {//(PEP)
if (res.success) {
close();
}
})
} else {
Notification.error({ Notification.error({
content: '即时推送时间不能大于1440分钟', content: title + (interval ? `推送时间不能大于${tactics == 'abnormal_rate' ? 720 : 1440}分钟` : '推送时间应为正整数'),
duration: 2, duration: 2,
}) })
return false
} }
} else { if (!deviceProportion || deviceProportion > 100) {
Notification.error({
content: '即时推送时间应为正整数',
duration: 2,
})
}
} else {
Notification.error({ Notification.error({
content: '即时推送时间应为正整数', content: '异常率推送异常率应为正整数且不超过100%',
duration: 2, duration: 2,
}) })
return false
} }
if (data.alarmType?.includes('strategy_hit')) {
let factorItem = []
for (let key in data.pomsStrucFactorId) {
factorItem = [...factorItem, ...data.pomsStrucFactorId[key]]
} }
else if (obj.tactics == 'continue') { if (factorItem.length > 0 && data.alarmSubType['strategy_hit']?.length > 0) {
if (obj.interval2) { return true
if (regu.test(obj.interval2)) {
if (obj.interval2 <= 1440) {
obj.tacticsParams = {
interval: obj.interval2
}
delete obj.interval1
delete obj.interval2
delete obj.interval3
delete obj.deviceProportion
dispatch(service.postPush({ ...obj, msg: '新增推送配置' })).then((res) => {//(PEP)
if (res.success) {
close();
}
})
} else {
Notification.error({
content: '持续时长推送时间不能大于1440分钟',
duration: 2,
})
}
} else {
Notification.error({
content: '持续时长推送时间应为正整数',
duration: 2,
})
}
} else { } else {
Notification.error({ Notification.error({
content: '持续时长推送时间应为正整数', content: '勾选策略命中监听模块后,策略命中细项与监测项都必须勾选一项',
duration: 2, duration: 3,
}) })
} }
return false
} }
else { return true
if (regu.test(obj.interval3) && regu.test(obj.deviceProportion)) {
if (obj.interval3 <= 720 && obj.deviceProportion <= 100) {
obj.tacticsParams = {
interval: obj.interval3,
deviceProportion: obj.deviceProportion
} }
delete obj.interval1
delete obj.interval2 function handleOk () {
delete obj.interval3 //
delete obj.deviceProportion form.current
dispatch(service.postPush({ ...obj, msg: '新增推送配置' })).then((res) => {//(PEP) .validate()
.then((v) => {
let data = {
name: v.name,
pomsProjectId: v.pomsProjectId,
strucId: v.strucId || [],
tactics: v.tactics,
tacticsParams: {
interval: v.tactics == 'immediately' ? v.interval1 : (v.tactics == 'continue' ? v.interval2 : v.interval3),
deviceProportion: v.deviceProportion
},
alarmType: v.alarmType,
timeType: v.timeType[0] == 'POMS' ? [] : v.timeType,
receiverPepUserId: v.receiverPepUserId || [],
disable: v.disable,
alarmSubType: {},
pomsStrucFactorId: {}
}
for (let key in v) {
if (['app_exception', 'data_exception', 'data_outages', 'device_exception', 'video_exception', 'strategy_hit'].includes(key)) {
data.alarmSubType = { ...data.alarmSubType, [key]: v[key] }
} else if (key.indexOf('factor') == 0) {
data.pomsStrucFactorId = { ...data.pomsStrucFactorId, [key.slice(6)]: v[key] }
}
}
if (caution(data.tactics, data.tacticsParams.interval, data.tacticsParams.deviceProportion, data)) {
dispatch(service.postPush({ pushId: editObj.id, ...data, msg: pushEdit ? '编辑推送配置' : "新增推送策略" })).then((res) => {//(PEP)
if (res.success) { if (res.success) {
close(); close();
} }
}) })
} else if (obj.interval3 <= 720 && obj.deviceProportion > 100) {
Notification.error({
content: '异常率推送异常率不能超过100%',
duration: 2,
})
} else if (obj.interval3 > 720 && obj.deviceProportion <= 100) {
Notification.error({
content: '异常率推送时间不能超过720小时',
duration: 2,
})
} else {
Notification.error({
content: '异常率推送时间不能超过720小时',
duration: 2,
})
Notification.error({
content: '异常率推送异常率不能超过100%',
duration: 2,
})
}
} else if (regu.test(obj.interval3) && !regu.test(obj.deviceProportion)) {
Notification.error({
content: '异常率推送异常率应为正整数',
duration: 2,
})
} else if (!regu.test(obj.interval3) && regu.test(obj.deviceProportion)) {
Notification.error({
content: '异常率推送时间应为正整数',
duration: 2,
})
} else {
Notification.error({
content: '异常率推送异常率应为正整数',
duration: 2,
})
Notification.error({
content: '异常率推送时间应为正整数',
duration: 2,
})
}
}
} }
}) })
} }
@ -393,35 +217,46 @@ function pushModal (props) {
> >
<div> <div>
<Form <Form
allowEmpty
labelPosition="left" labelPosition="left"
labelAlign="right" labelAlign="right"
labelWidth="120px" labelWidth="128px"
onValueChange={(values, field) => { onValueChange={(values, field) => {
for (var key in field) { for (var key in field) {
if (key == 'tactics') { if (key == 'tactics') {
if (values.tactics == 'abnormal_rate') { if (values.tactics == 'abnormal_rate') {
form.current.setValue('alarmType', undefined) form.current.setValue('alarmType', undefined)
setAbnormal(true) setAbnormal(true)
} } else {
else {
setAbnormal(false) setAbnormal(false)
} }
} } else if (key == 'pomsProjectId') {
if (key == 'pomsProjectId') { if (values.pomsProjectId.length > 0) {
getProjectStructureList(values.pomsProjectId)// getProjectStructureList(values.pomsProjectId)//
for (let i = 0; i < projectPoms.length; i++) { let pepProjectId = []
if (values.pomsProjectId == projectPoms[i].id) { let projectData = values.pomsProjectId?.map(v => {
if (projectPoms[i].pepProjectId) { let data = projectPoms?.filter(u => u.id == v) || []
getProjectStatusList()// if (data.length) {
pepProjectId.push(data[0].pepProjectId || 'POMS')
} }
else { })
if (pepProjectId.length == 1 && pepProjectId.includes('POMS')) {
setProjectStatus([{ construction_status: 'POMS', id: 'POMS' }]) setProjectStatus([{ construction_status: 'POMS', id: 'POMS' }])
form.current.setValue('timeType', ['POMS']) form.current.setValue('timeType', ['POMS'])
form.current.validate() form.current.validate()
} else {
getProjectStatusList()//
} }
} else {
setProjectStructure([])
form.current.setValue('strucId', [])
setProjectStatus([])
form.current.setValue('timeType', [])
} }
}
} else if (key == 'strucId') {
setFactorShow(values.strucId)
} else if (key == 'alarmType') {
setSubType(field['alarmType'])
} }
} }
}} }}
@ -436,7 +271,7 @@ function pushModal (props) {
label='策略名称:' label='策略名称:'
maxLength={15} maxLength={15}
disabled={pushEdit} disabled={pushEdit}
style={{ width: 695 }} style={{ width: 678 }}
initValue={editObj?.name || ""} initValue={editObj?.name || ""}
placeholder="请输入策略名称" placeholder="请输入策略名称"
showClear showClear
@ -447,9 +282,10 @@ function pushModal (props) {
label="请选择项目:" label="请选择项目:"
field="pomsProjectId" field="pomsProjectId"
placeholder="请选择项目" placeholder="请选择项目"
style={{ width: 695 }} style={{ width: 678 }}
rules={[{ required: true, message: "请选择项目" }]} rules={[{ required: true, message: "请选择项目" }]}
initValue={editObj?.pomsProjectId || ""} initValue={editObj?.pomsProjectId || ""}
multiple
filter filter
> >
{ {
@ -465,10 +301,13 @@ function pushModal (props) {
</div> </div>
<div> <div>
<Form.Select <Form.Select
label="请选择结构物:" label={<>请选择结构物
<Tooltip content={'选择结构物,若该结构物下没有监测项则下方不展示,反之展示结构物对应的监测项'} style={{ lineHeight: 2 }}>
<img src="/assets/images/install/table_question.png" alt="" style={{ height: 14, width: 14 }} />
</Tooltip>:</>}
field="strucId" field="strucId"
placeholder="请选择结构物" placeholder="请选择结构物"
style={{ width: 695 }} style={{ width: 678 }}
rules={[{ required: true, message: "请选择结构物" }]} rules={[{ required: true, message: "请选择结构物" }]}
initValue={editObj?.strucId || []} initValue={editObj?.strucId || []}
disabled={structure} disabled={structure}
@ -487,6 +326,27 @@ function pushModal (props) {
}) })
} }
</Form.Select> </Form.Select>
{projectStructure?.filter(v => (factorShow?.includes(v.id) && v.factor?.length > 0))?.map((u, index) => {
let factorItem = []
u.factor?.map(v => {
v.item.map(vv => factorItem.push(vv.name))
})
return <Form.CheckboxGroup
label={u.name + ':'}
key={u.name + index}
field={'factor' + u.id}
style={{ width: 695 }}
initValue={editObj?.pomsStrucFactorId ? editObj?.pomsStrucFactorId[u.id] : []}
direction='horizontal'
showClear
>
{
[...new Set(factorItem)].map((v, index) =>
<Form.Checkbox value={v} key={v} style={{ width: 150 }}>{v}</Form.Checkbox>)
}
</Form.CheckboxGroup>
})
}
</div> </div>
<div className='pushInput'> <div className='pushInput'>
<Form.RadioGroup <Form.RadioGroup
@ -496,11 +356,12 @@ function pushModal (props) {
direction='horizontal' direction='horizontal'
initValue={editObj?.tactics || ''} initValue={editObj?.tactics || ''}
rules={[{ required: true, message: '请选择推送策略' }]}> rules={[{ required: true, message: '请选择推送策略' }]}>
<div style={{ display: 'flex', alignItems: 'flex-start' }}>
<Form.Radio <Form.Radio
value='immediately' value='immediately'
extra={ extra={
<span style={{ fontSize: 13 }}> <span style={{ fontSize: 13 }}>
发现在 中台每分钟查询若有告警源新增则每
<Form.Input <Form.Input
field="interval1" field="interval1"
pure pure
@ -508,10 +369,10 @@ function pushModal (props) {
initValue={interval1 || "10"} initValue={interval1 || "10"}
// rules={[{ pattern: "^[0-9]*[1-9][0-9]*$", message: "" }]} // rules={[{ pattern: "^[0-9]*[1-9][0-9]*$", message: "" }]}
/> />
分钟有告警源新增通过信鸽服务发送一条通知信息 分钟通过信鸽服务发送一条通知信息
</span> </span>
} }
style={{ width: 198 }}> style={{ width: 217 }}>
即时推送机制 即时推送机制
</Form.Radio> </Form.Radio>
<Form.Radio <Form.Radio
@ -529,7 +390,7 @@ function pushModal (props) {
分钟则通过信鸽服务发送一条通知信息 分钟则通过信鸽服务发送一条通知信息
</span> </span>
} }
style={{ width: 198 }}> style={{ width: 173 }}>
持续时长推送机制 持续时长推送机制
</Form.Radio> </Form.Radio>
<Form.Radio <Form.Radio
@ -558,6 +419,7 @@ function pushModal (props) {
style={{ width: 260 }}> style={{ width: 260 }}>
异常率推送机制 异常率推送机制
</Form.Radio> </Form.Radio>
</div>
</Form.RadioGroup> </Form.RadioGroup>
</div> </div>
<div> <div>
@ -570,13 +432,49 @@ function pushModal (props) {
direction='horizontal' direction='horizontal'
showClear showClear
> >
<Form.Checkbox value="data_outages">数据中断</Form.Checkbox> {
<Form.Checkbox value="data_exception">数据异常</Form.Checkbox> [
<Form.Checkbox value="strategy_hit" disabled={abnormal}>策略命中</Form.Checkbox> { name: '数据中断', value: "data_outages" },
<Form.Checkbox value="video_exception">视频异常</Form.Checkbox> { name: '数据异常', value: "data_exception" },
<Form.Checkbox value="app_exception" disabled={abnormal}>应用异常</Form.Checkbox> { name: '策略命中', value: "strategy_hit" },
<Form.Checkbox value="device_exception">设备异常</Form.Checkbox> { name: '视频异常', value: "video_exception" },
{ name: '应用异常', value: "app_exception" },
{ name: '设备异常', value: "device_exception" },
].map((v, index) =>
<Form.Checkbox value={v.value}
key={v.value}
disabled={index == 2 || index == 4 ? abnormal : false}>
{v.name}</Form.Checkbox>)
}
</Form.CheckboxGroup>
{[
{ name: '数据中断', value: "data_outages", data: subTypeData['data_outages'][0] },
{ name: '数据异常', value: "data_exception", data: subTypeData['data_exception'][0] },
{ name: '策略命中', value: "strategy_hit", data: subTypeData['strategy_hit'][0] },
{ name: '视频异常', value: "video_exception", data: subTypeData['video_exception'][0]?.map(v => ({ id: v.id, name: v.kind })) },
{ name: '应用异常', value: "app_exception", data: subTypeData['app_exception'][0] },
{ name: '设备异常', value: "device_exception", data: [...subTypeData['device_exception'][0], ...subTypeData['device_exception'][1]] },
].filter(v => subType?.includes(v.value))?.map((u, index) => {
return <Form.CheckboxGroup
label={u.name + ':'}
key={u.name + u.index}
field={u.value}
style={{ width: 695 }}
initValue={
editObj?.id ?
editObj?.alarmSubType ?
editObj?.alarmSubType[u.value] : u.data.map(v => v.id)
: []}
direction='horizontal'
showClear
>
{
u.data?.map((v, index) =>
<Form.Checkbox value={v.id} key={v.id} style={{ width: 150 }}>{v.name}</Form.Checkbox>)
}
</Form.CheckboxGroup> </Form.CheckboxGroup>
})
}
</div> </div>
<div style={{ color: '#4A4A4A', fontSize: 14, fontWeight: 600, marginLeft: 6 }}> <div style={{ color: '#4A4A4A', fontSize: 14, fontWeight: 600, marginLeft: 6 }}>
接收信息配置 接收信息配置

97
web/client/src/sections/service/containers/emPush.jsx

@ -11,7 +11,7 @@ import { Setup } from "$components";
const EmPush = (props) => { const EmPush = (props) => {
const form = useRef();// const form = useRef();//
const { dispatch, actions, user, loading, socket } = props const { dispatch, actions, user, loading, socket } = props
const { service } = actions; const { service, problem } = actions;
const [setup, setSetup] = useState(false); // const [setup, setSetup] = useState(false); //
const [setupp, setSetupp] = useState([]);// const [setupp, setSetupp] = useState([]);//
const [query, setQuery] = useState({ limit: 10, page: 0 }); // const [query, setQuery] = useState({ limit: 10, page: 0 }); //
@ -23,6 +23,14 @@ const EmPush = (props) => {
const [allTableData, setAllTableData] = useState([]) // const [allTableData, setAllTableData] = useState([]) //
const [editObj, setEditObj] = useState({});// const [editObj, setEditObj] = useState({});//
const [projectStatus, setProjectStatus] = useState([]); // const [projectStatus, setProjectStatus] = useState([]); //
const [subTypeData, setSubTypedata] = useState({
data_outages: [],
data_exception: [],
strategy_hit: [],
video_exception: [],
app_exception: [],
device_exception: [],
}); //
const page = useRef(query.page);// const page = useRef(query.page);//
const EMPUSH = "empush"; const EMPUSH = "empush";
const tableList = [// const tableList = [//
@ -80,7 +88,34 @@ const EmPush = (props) => {
: ""; : "";
getProjectStatusList() getProjectStatusList()
getPushList(query); getPushList(query);
//
dispatch(problem.getAlarmDataGroup({ showAll: 'true' })).then((res) => {
if (res.success) {
let data = { ...subTypeData }
res.payload.data?.map(v => {
if (v.id === 1) {
data['data_outages'].push(v.unit)
} else if (v.id === 2) {
data['data_exception'].push(v.unit)
} else if (v.id == 3) {
data['strategy_hit'].push(v.unit)
} else {
data['device_exception'].push(v.unit)
}
})
//
dispatch(problem.getAlarmVideoDeviceKind({ showAll: true })).then((res) => {
if (res.success) {
data['video_exception'].push(res.payload.data)
}
})
data['app_exception'].push([{ id: 'apiError', name: "接口报错", }, { id: 'element', name: "元素异常", }, { id: 'timeout', name: "加载超时", },])
setSubTypedata(data)
}
})
}, []) }, [])
useEffect(() => { useEffect(() => {
let showTableData = JSON.parse(JSON.stringify(allTableData)).slice(query.page * query.limit, (query.page + 1) * query.limit) let showTableData = JSON.parse(JSON.stringify(allTableData)).slice(query.page * query.limit, (query.page + 1) * query.limit)
setTableData(showTableData) setTableData(showTableData)
@ -210,17 +245,27 @@ const EmPush = (props) => {
dataIndex: "projectName", dataIndex: "projectName",
key: "projectName", key: "projectName",
render: (_, row) => { render: (_, row) => {
let projectData = []
row.pomsProject?.map(v => {
projectData.push({
projectName: v.pepProject?.projectName,
name: v.name,
anxinerror: v.del,
constructionStatus: v.pepProject?.constructionStatus,
})
})
let anxinerror = false let anxinerror = false
let anxinerrorArr = '' let anxinerrorArr = ''
if (row.pomsProject.del == true) { if (row.pomsProject.del == true) {
anxinerror = true anxinerror = true
anxinerrorArr = row.pomsProject.pepProject?.projectName || row.pomsProject.name anxinerrorArr = row.pomsProject.pepProject?.projectName || row.pomsProject.name
} }
return ( return (
<div style={{ display: 'flex', alignItems: 'center' }}> projectData.map((u, index) => <div key={'projecname' + index} style={{ display: 'flex', alignItems: 'center' }}>
{ {
anxinerror ? ( u.anxinerror ? (
<Tooltip content={anxinerrorArr + ',项目已在【项企PEP】或【映射关系】中被删除,请重选项目!'}> <Tooltip content={(u.projectName || u.name) + ',项目已在【项企PEP】或【映射关系】中被删除,请重选项目!'}>
<div style={{ marginRight: 5 }}> <div style={{ marginRight: 5 }}>
<img src="/assets/images/install/risk.png" alt="" style={{ height: 24, width: 24, }} /> <img src="/assets/images/install/risk.png" alt="" style={{ height: 24, width: 24, }} />
</div> </div>
@ -228,17 +273,17 @@ const EmPush = (props) => {
} }
{ {
<div className='myseparator' style={{ display: 'flex', alignItems: 'center' }}> <div className='myseparator' style={{ display: 'flex', alignItems: 'center' }}>
<Tooltip content={row.pomsProject.pepProject?.projectName || row.pomsProject.name}> <Tooltip content={(u.projectName || u.name)}>
<div style={{ width: row.pomsProject?.pepProject?.projectName?.length > 7 || row.pomsProject?.name?.length > 7 ? '112px' : '', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', color: row.pomsProject.del ? '#F93920' : '' }}> <div style={{ width: u.projectName?.length > 7 || u.name?.length > 7 ? '112px' : '', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', color: row.pomsProject.del ? '#F93920' : '' }}>
{row.pomsProject.pepProject?.projectName || row.pomsProject.name} {u.projectName || u.name}
</div> </div>
</Tooltip> </Tooltip>
</div> </div>
} }
{ {
row.pomsProject?.pepProject?.projectName ? ( u.projectName ? (
<div style={{ <div style={{
height: 18, marginLeft: 4, height: 18, marginLeft: 4, width: 76,
background: 'linear-gradient(180deg, #EBF5FF 0%, #EBF5FF 0%, #D3E8FF 100%)', background: 'linear-gradient(180deg, #EBF5FF 0%, #EBF5FF 0%, #D3E8FF 100%)',
borderRadius: 2, display: 'flex', alignItems: 'center' borderRadius: 2, display: 'flex', alignItems: 'center'
}}> }}>
@ -246,15 +291,7 @@ const EmPush = (props) => {
<img src="/assets/images/install/icon_zhengque.png" alt="" style={{ height: 10, width: 10, marginLeft: 4, marginRight: 9 }} /> <img src="/assets/images/install/icon_zhengque.png" alt="" style={{ height: 10, width: 10, marginLeft: 4, marginRight: 9 }} />
</div> </div>
<div style={{ color: '#0F7EFB', fontSize: 11, marginRight: 12 }}> <div style={{ color: '#0F7EFB', fontSize: 11, marginRight: 12 }}>
{ {u.constructionStatus}
val.map((ite, idx) => {
return (
<div key={idx}>
{ite.id == row.pomsProject?.pepProject.constructionStatusId ? ite.construction_status : ''}
</div>
)
})
}
</div> </div>
</div> </div>
) : ( ) : (
@ -272,7 +309,7 @@ const EmPush = (props) => {
</div> </div>
) )
} }
</div> </div>)
) )
} }
}, },
@ -485,21 +522,22 @@ const EmPush = (props) => {
let enableType = '' let enableType = ''
if (row.disable) { if (row.disable) {
enableType = '禁用' enableType = '禁用'
} } else {
else { let construcId = row.pomsProject?.map(v => (v.pepProject?.constructionStatusId || 'POMS')) || []
if (row.timeType.length > 0) { if (construcId?.includes('POMS')) {
for (let i = 0; i < row.timeType.length; i++) { enableType = '已生效'
if (row.timeType[i] == row.pomsProject?.pepProject?.constructionStatusId) { } else {
let timeType = row.timeType?.map(Number) || []
for (let i = 0; i < timeType.length; i++) {
if (construcId?.includes(timeType[i])) {
enableType = '已生效' enableType = '已生效'
break; break
} else { } else {
enableType = '未生效' enableType = '未生效'
} }
} }
} }
else {
enableType = '已生效'
}
} }
return ( return (
<div style={{ textAlign: 'center', padding: '1px 17px', color: enableType == '禁用' ? '#FB0F0F' : enableType == '已生效' ? '#0F7EFB' : '#646566', background: enableType == '禁用' ? 'rgba(255,221,221,0.38)' : enableType == '已生效' ? 'rgba(221,237,255,0.38)' : 'rgba(192,192,192,0.38)', }}> <div style={{ textAlign: 'center', padding: '1px 17px', color: enableType == '禁用' ? '#FB0F0F' : enableType == '已生效' ? '#0F7EFB' : '#646566', background: enableType == '禁用' ? 'rgba(255,221,221,0.38)' : enableType == '已生效' ? 'rgba(221,237,255,0.38)' : 'rgba(192,192,192,0.38)', }}>
@ -618,9 +656,9 @@ const EmPush = (props) => {
marginLeft: 32 marginLeft: 32
}} }}
onClick={() => { onClick={() => {
setEditObj({})
setPushModal(true); setPushModal(true);
setPushEdit(false); setPushEdit(false);
setEditObj({})
}} }}
> >
添加推送策略 添加推送策略
@ -684,6 +722,7 @@ const EmPush = (props) => {
visible={true} visible={true}
pushEdit={pushEdit} pushEdit={pushEdit}
editObj={editObj} editObj={editObj}
subTypeData={subTypeData}
cancel={() => { cancel={() => {
setPushModal(false); setPushModal(false);
}} }}

8
web/client/src/sections/service/containers/reportManagement.jsx

@ -4,7 +4,7 @@ import { connect } from 'react-redux';
const Rest = (props) => { const Rest = (props) => {
const { dispatch, actions, user, loading, socket } = props const { dispatch, actions, user, loading, socket, dcWeb } = props
useEffect(() => { useEffect(() => {
@ -13,8 +13,9 @@ const Rest = (props) => {
return ( return (
<> <>
{/* style={{height: '100%', width: '100%',margin: '8px 12px', padding: '20px 20px 0px 20px'}} */}
<div > <div >
<img src="/assets/images/install/watting.png" alt="" style={{ width: 'calc(100% + 16px)', position: "relative", top: -12, left: -8, }} /> <iframe frameBorder="0" src={`${dcWeb}/dataService/download?pcode=`} style={{ height: 'calc(100vh - 80px)', width: 'calc(100%)' }} />
</div> </div>
</> </>
) )
@ -27,7 +28,8 @@ function mapStateToProps (state) {
// user: auth.user, // user: auth.user,
// actions: global.actions, // actions: global.actions,
// members: members.data, // members: members.data,
// socket: webSocket.socket // socket: webSocket.socket,
dcWeb: global.dcWeb,
}; };
} }

8
web/config.js

@ -16,6 +16,9 @@ args.option('apiPomsUrl', 'webapi的URL 外网可访问');
args.option('apiAnxinyunUrl', '安心云 api'); args.option('apiAnxinyunUrl', '安心云 api');
args.option('apiEmisUrl', '企业管理 api'); args.option('apiEmisUrl', '企业管理 api');
args.option('iotVcmpWeb', 'IOT 视频服务'); args.option('iotVcmpWeb', 'IOT 视频服务');
args.option('pomsMonitor', '运维监控 web');
args.option('dcWeb', '报表中心web');
// 七牛 // 七牛
args.option('qnak', 'qiniuAccessKey'); args.option('qnak', 'qiniuAccessKey');
@ -30,6 +33,8 @@ const API_POMS_URL = process.env.API_POMS_URL || flags.apiPomsUrl;
const API_EMIS_URL = process.env.API_EMIS_URL || flags.apiEmisUrl; const API_EMIS_URL = process.env.API_EMIS_URL || flags.apiEmisUrl;
const API_ANXINYUN_URL = process.env.API_ANXINYUN_URL || flags.apiAnxinyunUrl; const API_ANXINYUN_URL = process.env.API_ANXINYUN_URL || flags.apiAnxinyunUrl;
const IOT_VIDEO_WEB = process.env.IOT_VIDEO_WEB || flags.iotVcmpWeb; const IOT_VIDEO_WEB = process.env.IOT_VIDEO_WEB || flags.iotVcmpWeb;
const POMS_MONITOR = process.env.POMS_MONITOR || flags.pomsMonitor;
const DC_WEB = process.env.DC_WEB || flags.dcWeb;
// 七牛 // 七牛
const ANXINCLOUD_QINIU_AK = process.env.ANXINCLOUD_QINIU_ACCESSKEY || flags.qnak; const ANXINCLOUD_QINIU_AK = process.env.ANXINCLOUD_QINIU_ACCESSKEY || flags.qnak;
@ -41,6 +46,7 @@ const ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE = process.env.ANXINCLOUD_QINIU_DOMA
if ( if (
!API_URL !API_URL
|| !API_ANXINYUN_URL || !API_ANXINYUN_URL
|| !POMS_MONITOR || !DC_WEB
|| !ANXINCLOUD_QINIU_AK || !ANXINCLOUD_QINIU_SK || !ANXINCLOUD_QINIU_BUCKET_RESOURCE || !ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE || !IOT_VIDEO_WEB) { || !ANXINCLOUD_QINIU_AK || !ANXINCLOUD_QINIU_SK || !ANXINCLOUD_QINIU_BUCKET_RESOURCE || !ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE || !IOT_VIDEO_WEB) {
console.log('缺少启动参数,异常退出'); console.log('缺少启动参数,异常退出');
args.showHelp(); args.showHelp();
@ -85,6 +91,8 @@ const product = {
opts: { opts: {
apiUrl: API_POMS_URL, apiUrl: API_POMS_URL,
iotVcmpWeb: IOT_VIDEO_WEB, iotVcmpWeb: IOT_VIDEO_WEB,
pomsMonitor: POMS_MONITOR,
dcWeb: DC_WEB,
staticRoot: './client', staticRoot: './client',
qiniu: { qiniu: {
fetchUrl: '/_file-server', fetchUrl: '/_file-server',

2
web/package.json

@ -7,7 +7,7 @@
"test": "mocha", "test": "mocha",
"start-vite": "cross-env NODE_ENV=developmentVite npm run start-params", "start-vite": "cross-env NODE_ENV=developmentVite npm run start-params",
"start": "cross-env NODE_ENV=development npm run start-params", "start": "cross-env NODE_ENV=development npm run start-params",
"start-params": "node server -p 5600 -u http://localhost:4600 --apiPomsUrl http://localhost:4600 --apiAnxinyunUrl http://10.8.30.112:4100 --apiEmisUrl http://10.8.30.112:14000 --qnak XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5 --qnsk yewcieZLzKZuDfig0wLZ9if9jKp2P_1jd3CMJPSa --qnbkt dev-highways4good --qndmn http://rhvqdivo5.hn-bkt.clouddn.com --iotVcmpWeb https://mediaconsole.ngaiot.com", "start-params": "node server -p 5600 -u http://localhost:4600 --apiPomsUrl http://localhost:4600 --apiAnxinyunUrl http://10.8.30.112:4100 --apiEmisUrl http://10.8.30.112:14000 --qnak XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5 --qnsk yewcieZLzKZuDfig0wLZ9if9jKp2P_1jd3CMJPSa --qnbkt dev-highways4good --qndmn http://rhvqdivo5.hn-bkt.clouddn.com --iotVcmpWeb https://mediaconsole.ngaiot.com --pomsMonitor https://monitor.anxinyun.cn --dcWeb https://fsiot-oamss.anxinyun.cn",
"deploy": "export NODE_ENV=production&& npm run build && node server", "deploy": "export NODE_ENV=production&& npm run build && node server",
"build-dev": "cross-env NODE_ENV=development&&webpack --config webpack.config.js", "build-dev": "cross-env NODE_ENV=development&&webpack --config webpack.config.js",
"build": "cross-env NODE_ENV=production&&webpack --config webpack.config.prod.js" "build": "cross-env NODE_ENV=production&&webpack --config webpack.config.prod.js"

4
web/routes/attachment/index.js

@ -19,12 +19,14 @@ module.exports = {
entry: function (app, router, opts) { entry: function (app, router, opts) {
const getApiRoot = async function (ctx) { const getApiRoot = async function (ctx) {
const { apiUrl, iotVcmpWeb } = opts; const { apiUrl, iotVcmpWeb, pomsMonitor, dcWeb } = opts;
ctx.status = 200; ctx.status = 200;
ctx.body = { ctx.body = {
root: apiUrl, root: apiUrl,
iotVcmpWeb: iotVcmpWeb, iotVcmpWeb: iotVcmpWeb,
pomsMonitor: pomsMonitor,
dcWeb: dcWeb,
}; };
}; };

Loading…
Cancel
Save