From 8dc209efec2ff81073f4b238d33c5bc2051eb483 Mon Sep 17 00:00:00 2001 From: "gao.zhiyuan" Date: Fri, 28 Oct 2022 11:44:47 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=8E=A8=E9=80=81=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=90=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/app/lib/controllers/push/config.js | 2 +- api/app/lib/schedule/alarms_push.js | 207 ++++++++++++++++++++++--- api/app/lib/utils/push.js | 62 ++++++++ 3 files changed, 246 insertions(+), 25 deletions(-) create mode 100644 api/app/lib/utils/push.js diff --git a/api/app/lib/controllers/push/config.js b/api/app/lib/controllers/push/config.js index 4564481..f915686 100644 --- a/api/app/lib/controllers/push/config.js +++ b/api/app/lib/controllers/push/config.js @@ -7,7 +7,7 @@ async function list (ctx) { const sequelize = ctx.fs.dc.ORM; const { clickHouse } = ctx.app.fs const { utils: { anxinStrucIdRange, pomsProjectRange } } = ctx.app.fs - const { keyword, keywordTarget, alarmType, state, tactics, pomsProjectId } = ctx.request.body + const { keyword, keywordTarget, alarmType, state, tactics, pomsProjectId } = ctx.query let findOption = { where: { diff --git a/api/app/lib/schedule/alarms_push.js b/api/app/lib/schedule/alarms_push.js index a0d8918..eec2f63 100644 --- a/api/app/lib/schedule/alarms_push.js +++ b/api/app/lib/schedule/alarms_push.js @@ -53,11 +53,11 @@ module.exports = function (app, opts) { for (let { dataValues: c } of configListRes) { if (c.tacticsParams && c.tactics) { - const { projectCorrelation, strucId, pomsProjectId } = c + const { projectCorrelation, strucId, pomsProjectId, } = c const { interval, deviceProportion } = c.tacticsParams if ( - curMinOfYear % interval == 0 + curMinOfYear % parseInt(interval) == 0 ) { const corPepProject = projectCorrelation.pepProjectId ? pepProjectRes.find(p => p.id == projectCorrelation.pepProjectId) @@ -69,18 +69,63 @@ module.exports = function (app, opts) { && c.timeType.some(ct => ct == corPepProject.construction_status_id) ) ) { - // TODO 查当前 poms 下的结构物 并把不包含的去掉 + const { anxinProjectId, pepProjectId } = projectCorrelation - const strucListRes = strucId.length ? await clickHouse.anxinyun.query(` - SELECT id, iota_thing_id, name - FROM t_structure - WHERE id IN (${strucId.join(',')}) - `).toPromise() : [] + // 查当前 poms 下的结构物 并把不包含的去掉 + // 可能有结构物已解绑 + const strucListRes = strucId.length && anxinProjectId.length ? + await clickHouse.anxinyun.query( + ` + SELECT + DISTINCT id, + t_structure.id AS id, + t_structure.name AS name, + t_structure.iota_thing_id AS iotaThingId + FROM + t_project + LEFT JOIN + t_project_structure + ON t_project_structure.project = t_project.id + LEFT JOIN + t_project_structuregroup + ON t_project_structuregroup.project = t_project.id + LEFT JOIN + t_structuregroup_structure + ON t_structuregroup_structure.structuregroup = t_project_structuregroup.structuregroup + LEFT JOIN + t_project_construction + ON t_project_construction.project = t_project.id + LEFT JOIN + t_structure_site + ON t_structure_site.siteid = t_project_construction.construction + RIGHT JOIN + t_structure + ON t_structure.id = t_project_structure.structure + OR t_structure.id = t_structuregroup_structure.structure + OR t_structure.id = t_structure_site.structid + WHERE + project_state != -1 + AND t_project.id IN (${anxinProjectId.join(',')}) + AND t_structure.id IN (${strucId.join(',')}) + + ` + ).toPromise() : + [] + let searchStrucIds = strucListRes.map(s => s.id) + if (searchStrucIds.length) { + searchStrucIds.unshift(-1) + } + let pepProjectName = pepProjectId ? + pepProjectRes.find(p => p.id == pepProjectId).project_name + : projectCorrelation.name + let emailTitle = `${pepProjectName}-${c.name}-` + let emailSubTitle = '' let dataAlarmOption = [] let dataAlarmGroupOption = [] let dataAlarms = [] + let videoAlarmWhereOption = [] let videoAlarms = [] let appAlarmWhereOption = { @@ -89,17 +134,26 @@ module.exports = function (app, opts) { let appAlarms = [] let deviceCount = 0 + let alarmDeviceCount = 0 let cameraCount = 0 + let alarmCameraCount = 0 // 判断推送策略 - let pointTime = moment().subtract(interval, 'minute').format('YYYY-MM-DD HH:mm:ss') + let nowTime = moment().startOf('minute') + let pointTime = moment().subtract(parseInt(interval), 'minute').startOf('minute').format('YYYY-MM-DD HH:mm:ss') if (c.tactics == 'immediately') { - dataAlarmOption.push(`StartTime >= '${pointTime}'`); - appAlarmWhereOption.createTime = { $gte: pointTime } + // dataAlarmOption.push(`StartTime >= '${pointTime}'`); + // appAlarmWhereOption.createTime = { $gte: pointTime } + // videoAlarmWhereOption.push(`camera_status_alarm.create_time >= '${pointTime}'`) + emailTitle += `即时推送服务` + emailSubTitle += `截止${moment(pointTime).format('YYYY年MM月DD日 HH时mm分')}-${moment(nowTime).format('HH时mm分')}:` } else if (c.tactics == 'continue') { - dataAlarmOption.push(`StartTime <= '${pointTime}'`); - appAlarmWhereOption.createTime = { $lte: pointTime } + // dataAlarmOption.push(`StartTime <= '${pointTime}'`); + // appAlarmWhereOption.createTime = { $lte: pointTime } + // videoAlarmWhereOption.push(`camera_status_alarm.create_time <= '${pointTime}'`) + emailTitle += `持续时长推送服务` + emailSubTitle += `告警持续时长超${interval}分钟的告警源,详情如下:` } else if (c.tactics == 'abnormal_rate') { - dataAlarmOption.push(`StartTime <= '${pointTime}'`); + // dataAlarmOption.push(`StartTime <= '${pointTime}'`); if (c.alarmType.includes('data_outages') || c.alarmType.includes('data_exception')) { // 查了设备异常率 去安心云查当前项目下的设备数量 // TODO 等同步以太数据再查 @@ -110,15 +164,19 @@ module.exports = function (app, opts) { } if (c.alarmType.includes('video_exception')) { // 查了视频异常 去安心云查 接入的 萤石 设备数量 - cameraCount = strucId.length ? + cameraCount = searchStrucIds.length ? (await clickHouse.anxinyun.query(` SELECT count(*) AS count FROM t_video_ipc - WHERE structure IN (${strucId.join(',')}) + WHERE structure IN (${searchStrucIds.join(',')}) `).toPromise())[0].count : 0 } - appAlarmWhereOption.createTime = { $lte: pointTime } + // appAlarmWhereOption.createTime = { $lte: pointTime } + // videoAlarmWhereOption.push(`camera_status_alarm.create_time <= '${pointTime}'`) + emailTitle += `异常率推送服务` + emailSubTitle += `持续产生时间超过${interval}分钟的异常设备数量${interval}个,异常率达到项目或结构物内设备总数量${deviceCount + cameraCount}个的${interval}%,详情如下` } + emailTitle += '——POMS飞尚运维中台' // 判断告警数据范围 if (c.alarmType.includes('data_outages')) { @@ -131,7 +189,7 @@ module.exports = function (app, opts) { dataAlarmGroupOption.push(3) } if (c.alarmType.includes('video_exception')) { - videoAlarms = strucId.length ? await clickHouse.vcmp.query( + videoAlarms = searchStrucIds.length ? await clickHouse.vcmp.query( ` SELECT cameraAlarm.cameraId AS cameraId, @@ -167,13 +225,15 @@ module.exports = function (app, opts) { 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 - AND ${anxinyun}.t_video_ipc.structure IN (${strucId.join(',')}) + AND ${anxinyun}.t_video_ipc.structure IN (${searchStrucIds.join(',')}) INNER JOIN camera ON camera.serial_no = camera_status_alarm.serial_no AND camera.channel_no = camera_status_alarm.channel_no AND camera.delete = false AND camera.recycle_time is null - WHERE camera_status_alarm.confirm_time IS null + WHERE + camera_status_alarm.confirm_time IS null + ${videoAlarmWhereOption.length ? ` AND ${videoAlarmWhereOption.join(' AND ')}` : ''} ) AS cameraAlarm LEFT JOIN camera_status ON cameraAlarm.platform = camera_status.platform @@ -186,7 +246,7 @@ module.exports = function (app, opts) { AND anxinIpc.serial_no = cameraAlarm.cameraSerialNo LEFT JOIN ${anxinyun}.t_structure AS anxinStruc ON anxinStruc.id = anxinIpc.structure - AND anxinStruc.id IN (${strucId.join(',')}) + AND anxinStruc.id IN (${searchStrucIds.join(',')}) LEFT JOIN ${anxinyun}.t_video_ipc_station AS anxinIpcStation ON anxinIpcStation.ipc = anxinIpc.id LEFT JOIN ${anxinyun}.t_sensor AS anxinStation @@ -275,20 +335,119 @@ module.exports = function (app, opts) { dataAlarmGroupOption.push(4) dataAlarmGroupOption.push(5) } - // - if (dataAlarmGroupOption.length) { + + // 查数据告警 三警合一 + if (dataAlarmGroupOption.length && searchStrucIds.length) { dataAlarmGroupOption.push(-1) dataAlarmOption.push(`AlarmGroup IN (${dataAlarmGroupOption.join(',')})`) dataAlarms = await clickHouse.dataAlarm.query(` - SELECT * FROM alarms + SELECT * FROM alarms WHERE State NOT IN (3, 4) + AND StructureId IN (${searchStrucIds.join(',')}) ${dataAlarmOption.length ? ' AND ' + dataAlarmOption.join(' AND ') : ''} `).toPromise() console.log(dataAlarms); } + let dataAlarmTitle = [{ + n: '项目', + k: '', + v: pepProjectName + }, { + n: '结构物', + k: '', + f: (d) => { + return (strucListRes.find(s => s.id == d.StructureId) || {}).name + } + }, { + n: '告警源名称', + k: 'SourceName' + }, { + n: '告警源类型', + k: '', + f: (d) => { + switch (d.SourceTypeId) { + case 0: + return 'DTU' + case 1: + return '传感器' + case 2: + return '测点' + default: + return '' + } + } + }, { + n: '告警信息', + k: 'AlarmContent' + }, { + n: '告警等级(当前)', + k: '', + f: (d) => { + switch (d.CurrentLevel) { + case 1: + return '一级' + case 2: + return '二级' + case 3: + return '三级' + default: + return '' + } + } + }, { + n: '持续时间', + k: '', + f: (d) => { + return d.StartTime ? + '超过' + moment().diff(moment(d.StartTime), 'minutes') + '分钟' : '' + } + },] + + let html = '' + let tableTitlePostfix = ',详情如下:' + function packageTableTitle (tArr) { + + } + if (c.alarmType.includes('data_outages')) { + let tableTitlePrefix = '数据中断告警源' + let newAddCount = 0 + let alarmHtml = '' + + if (c.tactics == 'immediately') { + for (let a of dataAlarms.filter(d => d.AlarmGroup == 1)) { + alarmHtml += 1 + } + tableTitlePrefix += 1 + } else if (c.tactics == 'continue') { + + } else if (c.tactics == 'abnormal_rate') { + + } + } + if (c.alarmType.includes('data_exception')) { + + } + if (c.alarmType.includes('strategy_hit')) { + + } + if (c.alarmType.includes('video_exception')) { + + } + if (c.alarmType.includes('app_exception')) { + + } + if (c.alarmType.includes('device_exception')) { + + } + await pushByEmail({ + email: ['1650192445@qq.com'], + title: emailTitle, + text: '', + html: '' + }) } } } diff --git a/api/app/lib/utils/push.js b/api/app/lib/utils/push.js new file mode 100644 index 0000000..a0cf5ed --- /dev/null +++ b/api/app/lib/utils/push.js @@ -0,0 +1,62 @@ +'use strict'; + +const moment = require('moment') +const Core = require('@alicloud/pop-core'); +const nodemailer = require('nodemailer') + +module.exports = function (app, opts) { + const pushBySms = async ({ phone = [], templateCode, templateParam } = {}) => { + try { + if (phone.length) { + const client = new Core({ + accessKeyId: opts.sms.accessKey, + accessKeySecret: opts.sms.accessSecret, + endpoint: 'http://dysmsapi.aliyuncs.com',//固定 + apiVersion: '2017-05-25'//固定 + }); + const SendSmsRes = await client.request('SendSms', { + "PhoneNumbers": phone.join(','),//接收短信的手机号码。 + "SignName": "飞尚尚视",//短信签名名称。必须是已添加、并通过审核的短信签名。 + "TemplateCode": templateCode,//短信模板ID。必须是已添加、并通过审核的短信签名;且发送国际/港澳台消息时,请使用国际/港澳台短信模版。 + "TemplateParam": JSON.stringify(templateParam)//短信模板变量对应的实际值,JSON格式。 + }, { + method: 'POST' + }); + return SendSmsRes + } + } catch (error) { + throw error + } + } + + const pushByEmail = async ({ email = [], title, text = '', html = '', attachments = undefined, } = {}) => { + try { + let transporter = nodemailer.createTransport({ + host: opts.email.host, + port: opts.email.port, + secure: true, + auth: { + user: opts.email.sender.address, + pass: opts.email.sender.password, + } + }); + + // send mail with defined transport object + await transporter.sendMail({ + from: `${opts.email.sender.name}<${opts.email.sender.address}>`, // sender address + to: email.join(','), // list of receivers 逗号分隔字符串 + subject: title, // Subject line + text: text, // plain text body + html: html, // html body + attachments: attachments + }); + } catch (error) { + throw error + } + } + + return { + pushByEmail, + pushBySms, + } +} \ No newline at end of file From 978d12936d8bf72216d6fe373550d525c204031a Mon Sep 17 00:00:00 2001 From: "gao.zhiyuan" Date: Fri, 28 Oct 2022 15:15:53 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix=20=E7=8A=B6=E6=80=81=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/app/lib/controllers/push/config.js | 2 +- api/app/lib/utils/dataRange.js | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/api/app/lib/controllers/push/config.js b/api/app/lib/controllers/push/config.js index f915686..d4b299e 100644 --- a/api/app/lib/controllers/push/config.js +++ b/api/app/lib/controllers/push/config.js @@ -42,7 +42,7 @@ async function list (ctx) { findOption.where.alarmType = { $contains: [alarmType] } } if (state) { - if (state == 'enable') { + if (state == 'enable' || state == 'notYet' || state == 'takeEffect') { findOption.where.disable = false } else if (state == 'disable') { findOption.where.disable = true diff --git a/api/app/lib/utils/dataRange.js b/api/app/lib/utils/dataRange.js index 14fcc6b..407c80e 100644 --- a/api/app/lib/utils/dataRange.js +++ b/api/app/lib/utils/dataRange.js @@ -207,6 +207,16 @@ module.exports = function (app, opts) { let pomsProject = [] for (let b of bindRes) { + if ( + keywordTarget == 'pepProject' && keyword + && ( + !b.name && !( + b.pepProjectId && pepProjectRes.some(pp => pp.id == b.pepProjectId) + ) + ) + ) { + continue + } if (b.pepProjectId) { let corPepProject = pepProjectRes.find(pp => pp.id == b.pepProjectId) || {} pomsProject.push({ From c96f714e6b203d45540e587c99eed7f1a6d73c66 Mon Sep 17 00:00:00 2001 From: deartibers <947466799@qq.com> Date: Fri, 28 Oct 2022 15:41:45 +0800 Subject: [PATCH 3/3] =?UTF-8?q?em=E6=8E=A8=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/sections/service/actions/emPush.js | 21 +- .../sections/service/components/pushModal.jsx | 213 ++++++--- .../sections/service/containers/emPush.jsx | 405 +++++++++++++----- web/client/src/sections/service/style.less | 10 +- web/client/src/utils/webapi.js | 1 + 5 files changed, 482 insertions(+), 168 deletions(-) diff --git a/web/client/src/sections/service/actions/emPush.js b/web/client/src/sections/service/actions/emPush.js index 52db5a4..cadbb00 100644 --- a/web/client/src/sections/service/actions/emPush.js +++ b/web/client/src/sections/service/actions/emPush.js @@ -2,10 +2,11 @@ import { ApiTable, basicAction } from '$utils' -export function getPush () { //获取推送配置列表 +export function getPush (query) { //获取推送配置列表 return dispatch => basicAction({ type: 'get', dispatch: dispatch, + query: query, actionType: 'GET_PUSH', url: `${ApiTable.getPush}`, msg: { error: '获取推送配置列表失败' }, @@ -71,4 +72,22 @@ export function getProjectStatus (query) {//获取项目状态列表 msg: { option: "获取项目状态列表" }, reducer: { name: "ProjectStatus", params: { noClear: true } }, }); +} +export function putPushPushId (data) {//更改推送配置状态(禁用或删除) + let pushId = '' + let msg = '' + if (data) { + pushId = data.pushId + msg = data.msg + } + return (dispatch) => + basicAction({ + type: "put", + dispatch: dispatch, + data, + actionType: "PUT_PUSH_PUSHID", + url: `${ApiTable.putPushPushId.replace("{pushId}", pushId)}`, + msg: { option: msg }, //更改推送配置状态(禁用或删除) + reducer: {}, + }); } \ No newline at end of file diff --git a/web/client/src/sections/service/components/pushModal.jsx b/web/client/src/sections/service/components/pushModal.jsx index 6cf391c..de9199b 100644 --- a/web/client/src/sections/service/components/pushModal.jsx +++ b/web/client/src/sections/service/components/pushModal.jsx @@ -19,10 +19,6 @@ function pushModal (props) { } = props; const { service } = actions; const form = useRef();//表单 - const [disablePeople, setDisablePeople] = useState(true); //页码信息 - const [peopleList, setPeopleList] = useState([]); //人员List - const [departmentId, setDepartmentId] = useState(); //部门id - const [peopleId, setPeopleId] = useState(); //人员id const [abnormal, setAbnormal] = useState(false); //异常率推送机制disable const [usersList, setUsersList] = useState([]); //获取全部未删除用户 const [structure, setStructure] = useState(true); //结构物disable @@ -30,27 +26,38 @@ function pushModal (props) { const [projectStructure, setProjectStructure] = useState([]); //获取绑定项目下结构物 const [timeTypeDis, setTimeTypeDis] = useState(true); //通知时效disable const [projectStatus, setProjectStatus] = useState([]); //获取项目状态列表 + const timeTypePOMS = useRef([]);//表单 + const [interval1, setInterval1] = useState(undefined); // + const [interval2, setInterval2] = useState(undefined); // + const [interval3, setInterval3] = useState(undefined); // + const [deviceProportion, setDeviceProportion] = useState(undefined); // //初始化 useEffect(() => { - // if (editObj.id) { - // let departmentList = [] - // for (let i = 0; i < pepList.length; i++) { - // if (pepList[i].id == editObj.departments[0].id) { - // departmentList = pepList[i].users - // } - // } - // setPeopleList(departmentList) - // setDepartmentId(editObj.departments[0].id) - // setPeopleId(editObj.pepUserId) - // setDisablePeople(false) - // } getOrganizationUsersList()//获取全部未删除用户 getProjectPomsList()//获取已绑定项目 + if (editObj.id) { + getProjectStructureList(editObj.pomsProjectId) + if (editObj.pomsProject?.pepProjectId) { + getProjectStatusList()//获取项目状态列表 + } + else { + setProjectStatus([{ construction_status: 'POMS', id: 'POMS' }]) + timeTypePOMS.current = ['POMS'] + } + if (editObj.tactics == 'immediately') { + setInterval1(editObj.tacticsParams?.interval) + } else if (editObj.tactics == 'continue') { + setInterval2(editObj.tacticsParams?.interval) + } else if (editObj.tactics == 'abnormal_rate') { + setInterval3(editObj.tacticsParams?.interval) + setDeviceProportion(editObj.tacticsParams?.deviceProportion) + } + } }, []); function getOrganizationUsersList () {//获取全部未删除用户 dispatch(service.getOrganizationUsers()).then((res) => { @@ -75,7 +82,7 @@ function pushModal (props) { } setProjectStructure(res.payload?.data) form.current.setValue('strucId', mylist) - form.current.validate(['strucId','timeType']) + form.current.validate(['strucId', 'timeType']) setStructure(false) setTimeTypeDis(false) } @@ -90,7 +97,7 @@ function pushModal (props) { mylist.push(res.payload?.data[i].id) } form.current.setValue('timeType', mylist) - form.current.validate(['strucId','timeType']) + form.current.validate(['strucId', 'timeType']) } }) } @@ -100,7 +107,124 @@ function pushModal (props) { .validate() .then((values) => { if (pushEdit) { - dispatch(service.postPush({ pushId: pushId, pepUserId: values.pepUserId, msg: '编辑推送配置' })).then((res) => {//获取项企(PEP)全部部门及其下用户 + 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 + } 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 + } 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 + } 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, + }) + } + } + dispatch(service.postPush({ pushId: pushId, ...obj, msg: '编辑推送配置' })).then((res) => {//获取项企(PEP)全部部门及其下用户 if (res.success) { close(); } @@ -108,7 +232,7 @@ function pushModal (props) { } else { let obj = JSON.parse(JSON.stringify(values)) - if (obj.timeType[0] == null) { + if (obj.timeType[0] == 'POMS') { obj.timeType = [] } let regu = /^[0-9]*[1-9][0-9]*$/; @@ -224,7 +348,6 @@ function pushModal (props) { }) } } - console.log('obj', obj); dispatch(service.postPush({ ...obj, msg: '新增推送配置' })).then((res) => {//获取项企(PEP)全部部门及其下用户 if (res.success) { close(); @@ -274,35 +397,14 @@ function pushModal (props) { getProjectStatusList()//获取项目状态列表 } else { - setProjectStatus([{ construction_status: 'POMS', id: null }]) - form.current.setValue('timeType', [null]) + setProjectStatus([{ construction_status: 'POMS', id: 'POMS' }]) + form.current.setValue('timeType', ['POMS']) form.current.validate() } } } } } - - // for (var key in field) { - // if (key == 'department') { - // if (values.department >= 0) { - // let departmentList = [] - // for (let i = 0; i < pepList.length; i++) { - // if (pepList[i].id == values.department) { - // departmentList = pepList[i].users - // } - // } - // setPeopleList(departmentList) - // setDisablePeople(false) - // form.current.setValue('pepUserId', undefined); - // } - // else { - // setPeopleList([]) - // setDisablePeople(true) - // form.current.setValue('pepUserId', undefined); - // } - // } - // } }} getFormApi={(formApi) => (form.current = formApi)} > @@ -314,7 +416,7 @@ function pushModal (props) { field="name" label='策略名称:' style={{ width: 695 }} - // initValue={editObj?.name || ""} + initValue={editObj?.name || ""} placeholder="请输入策略名称" showClear rules={[{ required: true, message: "请输入策略名称" }]} /> @@ -326,7 +428,7 @@ function pushModal (props) { placeholder="请选择项目" style={{ width: 695 }} rules={[{ required: true, message: "请选择项目" }]} - // initValue={departmentId || ""} + initValue={editObj?.pomsProjectId || ""} filter > { @@ -347,7 +449,7 @@ function pushModal (props) { placeholder="请选择结构物" style={{ width: 695 }} rules={[{ required: true, message: "请选择结构物" }]} - // initValue={departmentId || ""} + initValue={editObj?.strucId || []} disabled={structure} filter multiple @@ -371,6 +473,7 @@ function pushModal (props) { label='推送策略配置:' type='card' direction='horizontal' + initValue={editObj?.tactics || ''} rules={[{ required: true, message: '请选择推送策略' }]}> 分钟内,有告警源新增,则通过【信鸽服务】发送一条通知信息。 @@ -399,7 +502,7 @@ function pushModal (props) { field="interval2" pure style={{ width: 60, height: 20, color: '#1859C1' }} - initValue={editObj?.interval || "10"} + initValue={interval2 || "10"} // rules={[{ pattern: "^[0-9]*[1-9][0-9]*$", message: "请输入正整数" }]} /> 分钟,则通过【信鸽服务】发送一条通知信息。 @@ -417,7 +520,7 @@ function pushModal (props) { field="deviceProportion" pure style={{ width: 60, height: 20, color: '#1859C1' }} - initValue={editObj?.deviceProportion || "40"} + initValue={deviceProportion || "40"} // rules={[{ pattern: "^[0-9]*[1-9][0-9]*$", message: "请输入正整数" }]} /> %,且持续时长超过 @@ -425,7 +528,7 @@ function pushModal (props) { field="interval3" pure style={{ width: 60, height: 20, color: '#1859C1' }} - initValue={editObj?.interval || "2"} + initValue={interval3 || "2"} // rules={[{ pattern: "^[0-9]*[1-9][0-9]*$", message: "请输入正整数" }]} /> 小时,则通过【信鸽服务】发送一条通知信息。 @@ -442,7 +545,7 @@ function pushModal (props) { field="alarmType" style={{ width: 695 }} rules={[{ required: true, message: "监听问题模块" }]} - // initValue={departmentId || ""} + initValue={editObj?.alarmType || []} direction='horizontal' showClear > @@ -464,7 +567,7 @@ function pushModal (props) { placeholder="请选择通知时效" style={{ width: 285 }} rules={[{ required: true, message: "请选择通知时效" }]} - // initValue={departmentId || ""} + initValue={editObj?.timeType.length > 0 ? editObj?.timeType : timeTypePOMS.current} disabled={timeTypeDis} multiple maxTagCount={3} @@ -485,7 +588,7 @@ function pushModal (props) { placeholder="请选择接收人" style={{ width: 285 }} rules={[{ required: true, message: "请选择接收人" }]} - initValue={[user.id]} + initValue={editObj?.receiverPepUserId || [user.id]} filter multiple maxTagCount={3} @@ -511,7 +614,7 @@ function pushModal (props) { pure direction='horizontal' style={{ display: 'flex', justifyContent: 'space-evenly' }} - initValue={false || false} + initValue={editObj?.disable || false} rules={[{ required: true, }]}> 启用 diff --git a/web/client/src/sections/service/containers/emPush.jsx b/web/client/src/sections/service/containers/emPush.jsx index b988ae8..3772b80 100644 --- a/web/client/src/sections/service/containers/emPush.jsx +++ b/web/client/src/sections/service/containers/emPush.jsx @@ -1,6 +1,7 @@ import React, { useEffect, useRef, useState } from 'react'; import { connect } from 'react-redux'; import { Skeleton, Button, Pagination, Form, Popconfirm, Table, Tooltip } from '@douyinfe/semi-ui'; +import { IconSearch } from '@douyinfe/semi-icons'; import { SkeletonScreen, } from "$components"; import moment from "moment"; import PushModal from '../components/pushModal' @@ -30,6 +31,7 @@ const EmPush = (props) => { const [appArr, setAppArr] = useState([]) //修改时添加应用 const [bindId, setBindId] = useState() //修改时绑定的id const [tableKey, setTableKey] = useState([]) //修改时绑定的id + const [editObj, setEditObj] = useState({});//管理员弹框修改内容 const [projectStatus, setProjectStatus] = useState([]); //获取项目状态列表 const page = useRef(query.page);//哪一页 const EMPUSH = "empush"; @@ -37,9 +39,9 @@ const EmPush = (props) => { { title: '推送信息', list: [ + { name: "关联项目", value: "projectName" }, { name: "策略名称", value: "name" }, { name: "创建时间", value: "createTime" }, - { name: "关联项目", value: "projectName" }, { name: "接收人", value: "receiverPepUser" }, { name: "推送方式", value: "pushType" }, { name: "监听问题模块", value: "alarmType" }, @@ -77,7 +79,6 @@ const EmPush = (props) => { return {}; } } - const [tableData, setTableData] = useState([]) //表格数据 useEffect(() => { @@ -91,31 +92,28 @@ const EmPush = (props) => { // dispatch(install.getProjectAppList(query)).then((res) => {//获取应用列表 // setAppList(res.payload.data) // }) - getProjectStatusList() localStorage.getItem(EMPUSH) == null ? localStorage.setItem( EMPUSH, - JSON.stringify(['name', 'createTime', 'projectName', 'receiverPepUser', 'alarmType', 'timeType', 'tactics', 'disable']) + JSON.stringify(['projectName', 'name', 'createTime', 'receiverPepUser', 'alarmType', 'timeType', 'tactics', 'disable']) ) : ""; - attribute(); + getProjectStatusList() }, []) useEffect(() => { getPushList(); }, [query]); function getPushList () { - dispatch(service.getPush(query)).then((res) => {//获取已绑定项目 + let val = form.current.getValues() + // , ...query + dispatch(service.getPush({ ...val })).then((res) => {//获取已绑定项目 if (res.success) { - // let mytableData = JSON.parse(JSON.stringify(res.payload.data.rows)); - // let mytableKey = [] - // for (let index = 0; index < mytableData.length; index++) { - // mytableData[index].key = mytableData[index].id - // mytableKey.push(mytableData[index].id) - // } - // setTableKey(mytableKey) - // setTableData(mytableData) - setTableData(res.payload.data) + let mytableData = JSON.parse(JSON.stringify(res.payload.data)); + for (let index = 0; index < mytableData.length; index++) { + mytableData[index].key = String(mytableData[index].id) + } + setTableData(mytableData) setLimits(res.payload.data.length) mylimits.current = res.payload.data.length } @@ -125,13 +123,14 @@ const EmPush = (props) => { dispatch(service.getProjectStatus()).then((res) => { if (res.success) { setProjectStatus(res.payload?.data) + attribute(res.payload?.data); } }) } - const [columns, setColumns] = useState([//表格属性 + const columns = [//表格属性 { title: "操作", - width: "20%", + width: "12%", dataIndex: "text", key: 'text', render: (_, row) => { @@ -139,55 +138,82 @@ const EmPush = (props) => {
- + {row?.disable ? ( + + ) : ( + { + dispatch(service.putPushPushId({ pushId: row?.id, del: false, disable: true, msg: '更改推送配置状态' })).then(() => { + // setQuery({ limit: 10, page: page.current }) + }) + }} + > + + + )} { - // dispatch(install.deleteProjectBind({ bindId: row?.id, msg: '删除安心云、项目管理项目绑定关系' })).then(() => { - // if (page.current > 0 && mylimits.current < 2) { - // setQuery({ limit: 10, page: page.current - 1 }) - // } else { - // setQuery({ limit: 10, page: page.current }) - // } - // }) + dispatch(service.putPushPushId({ pushId: row?.id, del: true, disable: false, msg: '删除推送配置' })).then(() => { + // if (page.current > 0 && mylimits.current < 2) { + // setQuery({ limit: 10, page: page.current - 1 }) + // } else { + // setQuery({ limit: 10, page: page.current }) + // } + }) }} > @@ -196,30 +222,29 @@ const EmPush = (props) => { ); }, }, - ]) + ] + function expandRowRender (record, index) { + return ( +
+ 结构物: + { + record.structure?.map((item, index) => { + return ( +
+ {item.name} +
+ ) + }) + } +
+ ) + } //获取表格属性设置 - function attribute () { + function attribute (val) { const arr = localStorage.getItem(EMPUSH) ? JSON.parse(localStorage.getItem(EMPUSH)) : []; - const column = [ - { - title: '策略名称', - dataIndex: "name", - key: 'name', - render: (_, row) => { - return row.name - } - }, - { - title: "创建时间", - dataIndex: "createTime", - key: "createTime", - render: (_, r, index) => { - return moment(r.createTime).format('YYYY-MM-DD HH:mm:ss'); - }, - }, { title: '关联项目', dataIndex: "projectName", @@ -250,10 +275,63 @@ const EmPush = (props) => {
} + { + row.pomsProject?.pepProject?.projectName ? ( +
+
+ +
+
+ { + val.map((ite, idx) => { + return ( +
+ {ite.id == row.pomsProject?.pepProject.constructionStatusId ? ite.construction_status : ''} +
+ ) + }) + } +
+
+ ) : ( +
+
+ +
+
+ POMS +
+
+ ) + } ) } }, + { + title: '策略名称', + dataIndex: "name", + key: 'name', + render: (_, row) => { + return row.name + } + }, + { + title: "创建时间", + dataIndex: "createTime", + key: "createTime", + render: (_, r, index) => { + return moment(r.createTime).format('YYYY-MM-DD HH:mm:ss'); + }, + }, { title: '接收人', dataIndex: "receiverPepUser", @@ -280,7 +358,7 @@ const EmPush = (props) => { { row.receiverPepUser.map((item, index) => { return ( -
+
{item.name},
) @@ -314,7 +392,6 @@ const EmPush = (props) => { return (
{ - // alarmTypeObj row.alarmType.map((item, index) => { return (
@@ -355,9 +432,81 @@ const EmPush = (props) => { title: "生效项目节点", dataIndex: "timeType", key: "timeType", - render: (_, r, index) => { - // projectStatus - return r.timeType[0] + render: (_, row, index) => { + return ( +
+ { + row.timeType.length > 0 ? ( + row.timeType.map((item, index) => { + return ( +
1 ? 'none' : 'flex', alignItems: 'center' + }}> +
+ +
+
+ { + val.map((ite, idx) => { + return ( +
+ {ite.id == item ? ite.construction_status : ''} +
+ ) + }) + } +
+
+ ) + }) + ) : ( +
+
+ +
+
+ POMS +
+
+ ) + } + { + row.timeType.length > 2 ? ( + + { + row.timeType.map((item, index) => { + return ( +
+ { + val.map((ite, idx) => { + return ( + + {ite.id == item ? ite.construction_status : ''} + + ) + }) + }, +
+ ) + }) + } +
+ } trigger="click" style={{ lineHeight: 2 }}> +
+ +{row.timeType.length - 2} +
+ + ) : ('') + } +
+ ) }, }, { @@ -372,9 +521,31 @@ const EmPush = (props) => { title: "启用状态", dataIndex: "disable", key: "disable", - render: (_, r, index) => { - // projectStatus - return r.disable + render: (_, row, index) => { + let enableType = '' + if (row.disable) { + enableType = '禁用' + } + else { + if (row.timeType.length > 0) { + for (let i = 0; i < row.timeType.length; i++) { + if (row.timeType[i] == row.pomsProject?.pepProject?.constructionStatusId) { + enableType = '已生效' + break; + } else { + enableType = '未生效' + } + } + } + else { + enableType = '已生效' + } + } + return ( +
+ {enableType} +
+ ) }, }, { @@ -382,7 +553,7 @@ const EmPush = (props) => { dataIndex: "pushCount", key: "pushCount", render: (_, r, index) => { - return r.pushCount + return r.pushCount + '次' }, }, ]; @@ -403,7 +574,7 @@ const EmPush = (props) => {
EM推送
Em push
-
+
console.log(values)} // onValueChange={values=>console.log(values)} @@ -411,47 +582,53 @@ const EmPush = (props) => { layout="horizontal" style={{ position: "relative", width: "100%", flex: 1 }} > + + 项目 + 结构物 + 策略名 + } + field="keyword" + pure + showClear + style={{ width: 260, marginLeft: 12, marginRight: 12 }} + placeholder="请输入或选择关键词" /> - {/* {.map((item) => { - return ( - - {item.name} - - ); - })} */} + 数据中断 + 数据异常 + 策略命中 + 视频异常 + 应用异常 + 设备异常 - {/* {.map((item) => { - return ( - - {item.name} - - ); - })} */} + 已生效 + 未生效 + 禁用 @@ -502,10 +681,13 @@ const EmPush = (props) => { placeholder={SkeletonScreen()} > s)} dataSource={tableData} bordered={false} + hideExpandedColumn={false} empty="暂无数据" + expandedRowRender={expandRowRender} pagination={false} onRow={handleRow} /> @@ -543,6 +725,7 @@ const EmPush = (props) => { { setPushModal(false); }} @@ -558,7 +741,7 @@ const EmPush = (props) => { tableList={tableList} close={() => { setSetup(false); - attribute(); + attribute(projectStatus); }} /> ) : ( diff --git a/web/client/src/sections/service/style.less b/web/client/src/sections/service/style.less index b98d242..7f2491d 100644 --- a/web/client/src/sections/service/style.less +++ b/web/client/src/sections/service/style.less @@ -1,5 +1,13 @@ -.empush{ +.myempush{ .semi-input-wrapper{ margin-bottom: 0px !important; } +} +.emPushTable{ + // .semi-table-row-cell:first-child{ + // display: flex !important; + // } + // .semi-table-row-cell{ + // display: flex !important; + // } } \ No newline at end of file diff --git a/web/client/src/utils/webapi.js b/web/client/src/utils/webapi.js index 36b3e65..e420840 100644 --- a/web/client/src/utils/webapi.js +++ b/web/client/src/utils/webapi.js @@ -54,6 +54,7 @@ export const ApiTable = { getOrganizationUsers: "organization/users", //获取全部未删除用户 getProjectStructure: "project/structure", //获取绑定项目下结构物 getProjectStatus: "project/status", //获取项目状态列表 + putPushPushId: "push/{pushId}", //更改推送配置状态(禁用或删除) //控制台 consoleToollink: 'console/toollink', //常用工具