Browse Source

(*)应用告警,视频告警,数据告警确认; 控制台最新动态接口暂交

dev
wuqun 2 years ago
parent
commit
0f9b1ac3e1
  1. 4
      api/.vscode/launch.json
  2. 38
      api/app/lib/controllers/alarm/app.js
  3. 153
      api/app/lib/controllers/console/index.js
  4. 25
      api/app/lib/index.js
  5. 53
      api/app/lib/models/alarm_appear_record.js
  6. 2
      api/app/lib/models/alarm_confirm_log.js
  7. 62
      api/app/lib/models/email_send_log.js
  8. 71
      api/app/lib/models/latest_dynamic_list.js
  9. 23
      api/app/lib/routes/console/index.js
  10. 12
      web/client/src/sections/problem/components/tableData.jsx
  11. 27
      web/client/src/sections/problem/containers/dataAlarm.jsx

4
api/.vscode/launch.json

@ -16,9 +16,9 @@
"-p 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 node35:6667,node36:6667,node37:6667",
"--iotaProxy http://10.8.30.157:17007",
"--redisHost 10.8.30.112",

38
api/app/lib/controllers/alarm/app.js

@ -2,7 +2,7 @@
const moment = require('moment')
async function inspection (ctx) {
async function inspection(ctx) {
// 巡查
try {
const models = ctx.fs.dc.models;
@ -31,7 +31,7 @@ async function inspection (ctx) {
}
}
async function inspectionList (ctx) {
async function inspectionList(ctx) {
try {
const models = ctx.fs.dc.models;
const { clickHouse } = ctx.app.fs
@ -116,7 +116,7 @@ async function inspectionList (ctx) {
}
}
async function notedInspection (ctx) {
async function notedInspection(ctx) {
try {
const models = ctx.fs.dc.models;
const { inspectionId } = ctx.request.body
@ -141,7 +141,7 @@ async function notedInspection (ctx) {
}
}
async function apiError (ctx) {
async function apiError(ctx) {
try {
const models = ctx.fs.dc.models;
const { projectAppId, alarmContent, router, statusCode, screenshot = '', type } = ctx.request.body
@ -212,7 +212,7 @@ async function apiError (ctx) {
}
}
async function apiErrorList (ctx) {
async function apiErrorList(ctx) {
try {
const models = ctx.fs.dc.models;
const { clickHouse } = ctx.app.fs
@ -324,11 +324,11 @@ async function apiErrorList (ctx) {
}
}
async function confirmApiError (ctx) {
async function confirmApiError(ctx) {
try {
const models = ctx.fs.dc.models;
const { confirm, appAlarmId = [] } = ctx.request.body
const { confirm, appAlarmId = [], confirmPost } = ctx.request.body
const { pepUserId, projectCorrelationIds, alarmInfo } = confirmPost
await models.AppAlarm.update({
confirm,
confirmTime: moment().format()
@ -338,6 +338,28 @@ async function confirmApiError (ctx) {
}
})
//存日志
let logDatas = projectCorrelationIds.map(id => {
return {
pepUserId,
projectCorrelationId: id,
alarmInfo,//包含告警id,type,source
confirmTime: moment().format(),
confirmContent: confirm
}
})
let rslt = await models.AlarmConfirmLog.bulkCreate(logDatas, { returning: true });
//存最新动态
let dynamics = rslt.map(r => {
return {
time: moment().format(),
alarmConfirmId: r.id
}
})
await models.AlarmConfirmLog.bulkCreate(dynamics);
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);

153
api/app/lib/controllers/console/index.js

@ -0,0 +1,153 @@
'use strict';
const moment = require('moment');
//工作台
async function getWorkbench(ctx) {
try {
const { models } = ctx.fs.dc;
const { clickHouse } = ctx.app.fs
const { alarmId, limit, page } = ctx.query
ctx.status = 200;
ctx.body = []
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
//项目概览
async function getProjectsInfo(ctx) {
try {
const { models } = ctx.fs.dc;
const { clickHouse } = ctx.app.fs
const { alarmId, limit, page } = ctx.query
ctx.status = 200;
ctx.body = []
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
//BI分析
async function getBiAnalysis(ctx) {
try {
const { models } = ctx.fs.dc;
const { clickHouse } = ctx.app.fs
const { alarmId, limit, page } = ctx.query
ctx.status = 200;
ctx.body = []
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
//最新动态
async function getLatestDynamic(ctx) {
try {
const { models } = ctx.fs.dc;
const { limit, page, projectCorrelationId } = ctx.query;
const { userInfo } = ctx.fs.api;
const { clickHouse } = ctx.app.fs;
let where = {}
if (!userInfo.role.includes('SuperAdmin') && !userInfo.role.includes('admin')) {
where.projectCorrelationId = { $in: userInfo.correlationProject }
}
if (projectCorrelationId) {//查指定项目,控制台全局切换
where.projectCorrelationId = projectCorrelationId
}
let news = await models.LatestDynamicList.findAll({//最新动态
include: [{
model: models.ProjectCorrelation,
where: { del: false },
attributes: ['id', 'name', 'pepProjectId'],
}, {
model: models.AlarmAppearRecord
}, {
model: models.EmailSendLog
}, {
model: models.AlarmConfirmLog
}],
where: where,
offset: Number(page) * Number(limit),
limit: Number(limit),
order: [['time', 'desc']],
});
//查项目名称 查用户名
let pepPojectIds = new Set(), notedUserIds = new Set();
for (let p of news) {
pepPojectIds.add(p.projectCorrelation.pepProjectId);
if (p.emailSendLog) {
notedUserIds.add(p.emailSendLog.toPepUserId);//通知 接收人
}
if (p.alarmConfirmLog && p.alarmConfirmLog.pepUserId) {
notedUserIds.add(p.alarmConfirmLog.pepUserId);//确认 操作者
}
}
let pepProjects = pepPojectIds.size ? await clickHouse.projectManage.query(`
SELECT id, project_name FROM t_pim_project WHERE id IN (${[...pepPojectIds]})
`).toPromise() : [];
let userPepRes = notedUserIds.size ? await clickHouse.pepEmis.query(
`SELECT DISTINCT user.id AS id, "user"."name" AS name FROM user WHERE user.id IN (${[...notedUserIds].join(',')})
`).toPromise() : []
let appear = [], notice = [], confirm = [];
news.map(d => {
let projectName = d.projectCorrelation.name || pepProjects.find(pp => pp.id == d.projectCorrelation.pepProjectId).project_name;
if (d.alarmAppearId) {
appear.push({
projectName,
...d.alarmAppearRecord
});
}
if (d.emailSendId) {
notice.push({
userName: userPepRes.find(u => u.id == d.emailSendLog.toPepUserId).name,
projectName,
...d.emailSendLog
});
}
if (d.alarmConfirmId) {
confirm.push({
userName: d.alarmConfirmLog.pepUserId ? userPepRes.find(u => u.id == d.alarmConfirmLog.pepUserId).name : '自动恢复',
projectName,
...d.alarmConfirmLog.dataValues
});
}
})
ctx.status = 200;
ctx.body = {
appear,//发现
notice,//通知
confirm//确认
};
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
module.exports = {
getWorkbench,
getProjectsInfo,
getBiAnalysis,
getLatestDynamic
};

25
api/app/lib/index.js

@ -58,7 +58,7 @@ module.exports.models = function (dc) { // dc = { orm: Sequelize对象, ORM: Seq
});
const {
AppInspection, ProjectApp, ProjectCorrelation, AppAlarm, App
AppInspection, ProjectApp, ProjectCorrelation, AppAlarm, App, AlarmAppearRecord, AlarmConfirmLog, EmailSendLog, LatestDynamicList
} = dc.models;
AppInspection.belongsTo(App, { foreignKey: 'projectAppId', targetKey: 'id' });
@ -76,4 +76,27 @@ module.exports.models = function (dc) { // dc = { orm: Sequelize对象, ORM: Seq
AppAlarm.belongsTo(App, { foreignKey: 'projectAppId', targetKey: 'id' });
App.hasMany(AppAlarm, { foreignKey: 'projectAppId', sourceKey: 'id' });
AlarmAppearRecord.belongsTo(ProjectCorrelation, { foreignKey: 'projectCorrelationId', targetKey: 'id' });
ProjectCorrelation.hasMany(AlarmAppearRecord, { foreignKey: 'projectCorrelationId', sourceKey: 'id' });
AlarmConfirmLog.belongsTo(ProjectCorrelation, { foreignKey: 'projectCorrelationId', targetKey: 'id' });
ProjectCorrelation.hasMany(AlarmConfirmLog, { foreignKey: 'projectCorrelationId', sourceKey: 'id' });
EmailSendLog.belongsTo(ProjectCorrelation, { foreignKey: 'projectCorrelationId', targetKey: 'id' });
ProjectCorrelation.hasMany(EmailSendLog, { foreignKey: 'projectCorrelationId', sourceKey: 'id' });
LatestDynamicList.belongsTo(AlarmAppearRecord, { foreignKey: 'alarmAppearId', targetKey: 'id' });
AlarmAppearRecord.hasMany(LatestDynamicList, { foreignKey: 'alarmAppearId', sourceKey: 'id' });
LatestDynamicList.belongsTo(EmailSendLog, { foreignKey: 'emailSendId', targetKey: 'id' });
EmailSendLog.hasMany(LatestDynamicList, { foreignKey: 'emailSendId', sourceKey: 'id' });
LatestDynamicList.belongsTo(AlarmConfirmLog, { foreignKey: 'alarmConfirmId', targetKey: 'id' });
AlarmConfirmLog.hasMany(LatestDynamicList, { foreignKey: 'alarmConfirmId', sourceKey: 'id' });
LatestDynamicList.belongsTo(ProjectCorrelation, { foreignKey: 'projectCorrelationId', targetKey: 'id' });
ProjectCorrelation.hasMany(LatestDynamicList, { foreignKey: 'projectCorrelationId', sourceKey: 'id' });
};

53
api/app/lib/models/alarm_appear_record.js

@ -0,0 +1,53 @@
/* eslint-disable*/
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const AlarmAppearRecord = sequelize.define("alarmAppearRecord", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "alarm_appear_record_id_uindex"
},
projectCorrelationId: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "project_correlation_id",
autoIncrement: false
},
alarmInfo: {
type: DataTypes.JSON,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "alarm_info",
autoIncrement: false
},
time: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "time",
autoIncrement: false
}
}, {
tableName: "alarm_appear_record",
comment: "",
indexes: []
});
dc.models.AlarmAppearRecord = AlarmAppearRecord;
return AlarmAppearRecord;
};

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

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

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

@ -0,0 +1,62 @@
/* eslint-disable*/
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const EmailSendLog = sequelize.define("emailSendLog", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "email_send_log_id_uindex"
},
projectCorrelationId: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "project_correlation_id",
autoIncrement: false
},
toPepUserId: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "to_pep_user_id",
autoIncrement: false
},
by: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "by",
autoIncrement: false
},
time: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "time",
autoIncrement: false
}
}, {
tableName: "email_send_log",
comment: "",
indexes: []
});
dc.models.EmailSendLog = EmailSendLog;
return EmailSendLog;
};

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

@ -0,0 +1,71 @@
/* eslint-disable*/
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const LatestDynamicList = sequelize.define("latestDynamicList", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "latest_dynamic_list_id_uindex"
},
time: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "time",
autoIncrement: false
},
alarmAppearId: {
type: DataTypes.INTEGER,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "alarm_appear_id",
autoIncrement: false
},
emailSendId: {
type: DataTypes.INTEGER,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "email_send_id",
autoIncrement: false
},
alarmConfirmId: {
type: DataTypes.INTEGER,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "alarm_confirm_id",
autoIncrement: false
},
projectCorrelationId: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "project_correlation_id",
autoIncrement: false
}
}, {
tableName: "latest_dynamic_list",
comment: "",
indexes: []
});
dc.models.LatestDynamicList = LatestDynamicList;
return LatestDynamicList;
};

23
api/app/lib/routes/console/index.js

@ -0,0 +1,23 @@
'use strict';
const console = require('../../controllers/console/index');
module.exports = function (app, router, opts) {
//我的工作台
app.fs.api.logAttr['GET/user/:userId/workbench'] = { content: '查询工作台问题', visible: false };
router.get('/user/:userId/workbench', console.getWorkbench);
//项目概览
app.fs.api.logAttr['GET/user/:userId/projects/info'] = { content: '查询项目概览', visible: false };
router.get('/user/:userId/projects/info', console.getProjectsInfo);
//BI分析模块
app.fs.api.logAttr['GET/user/:userId/bi/analysis'] = { content: '查询BI分析数据', visible: false };
router.get('/user/:userId/bi/analysis', console.getBiAnalysis);
//最新动态
app.fs.api.logAttr['GET/user/:userId/latest/dynamic'] = { content: '查询最新动态', visible: false };
router.get('/user/:userId/latest/dynamic', console.getLatestDynamic);
};

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

@ -26,8 +26,8 @@ const TableData = ({ route, dispatch, actions, collectData, setSetup, exhibition
let typeData = { element: "元素异常", apiError: "接口报错 ", timeout: "加载超时" }
let tableDatas = res.payload.data?.rows.map(v => ({
key: v.id,
projectName: v.app?.projectCorrelations?.map(r => (r.name ? { name: r.name, state: 'PMOS' } : {
name: r.pepProject?.projectName, state: r.pepProject?.constructionStatus
projectName: v.app?.projectCorrelations?.map(r => (r.name ? { id: r.id, name: r.name, state: 'PMOS' } : {
id: r.id, name: r.pepProject?.projectName, state: r.pepProject?.constructionStatus
}))?.filter(c => c),
appName: v.app?.name,
url: v.app?.url,
@ -59,8 +59,8 @@ const TableData = ({ route, dispatch, actions, collectData, setSetup, exhibition
let tableDatas = res.payload.data?.map(v => ({
key: v.alarmId,
StructureName: v.struc,
projectName: v.pomsProject?.map(r => (r.name ? { name: r.name, state: 'PMOS' } : {
name: r.pepProject?.projectName, state: r.pepProject?.constructionStatus
projectName: v.pomsProject?.map(r => (r.name ? { id: r.id, name: r.name, state: 'PMOS' } : {
id: r.id, name: r.pepProject?.projectName, state: r.pepProject?.constructionStatus
}))?.filter(c => c),
createTime: v.createTime ? moment(v.createTime).format("YYYY-MM-DD HH:mm:ss") : "",
updateTime: v.updateTime ? moment(v.updateTime).format("YYYY-MM-DD HH:mm:ss") : "",
@ -107,8 +107,8 @@ const TableData = ({ route, dispatch, actions, collectData, setSetup, exhibition
let tableDatas = res.payload.data?.rows?.map(v => ({
key: v.AlarmId,
StructureName: v.StructureName,
projectName: v.pomsProject?.map(r => (r.name ? { name: r.name, state: 'PMOS' } : {
name: r.pepProject?.projectName, state: r.pepProject?.constructionStatus
projectName: v.pomsProject?.map(r => (r.name ? { id: r.id, name: r.name, state: 'PMOS' } : {
id: r.id, name: r.pepProject?.projectName, state: r.pepProject?.constructionStatus
}))?.filter(c => c),
createTime: v.StartTime ? moment(v.StartTime).format("YYYY-MM-DD HH:mm:ss") : "",
updateTime: v.EndTime ? moment(v.EndTime).format("YYYY-MM-DD HH:mm:ss") : "",

27
web/client/src/sections/problem/containers/dataAlarm.jsx

@ -37,7 +37,7 @@ const DataAlarm = ({ match, dispatch, actions, user, loading, socket, iotVcmpWeb
const [videoModal, setVideoModal] = useState(false) //
const [videoData, setVideoData] = useState({}) //
const [videoToken, setVideoToken] = useState() //token
const [alarmToConfirm, setAlarmToConfirm] = useState(null) //
const TextAreaApi = useRef('')
@ -309,6 +309,7 @@ const DataAlarm = ({ match, dispatch, actions, user, loading, socket, iotVcmpWeb
<Button theme='borderless' style={{ width: 65 }} onClick={() => {
setConfirm(true)
setSelected([r.key])
setAlarmToConfirm(r)
}}>确认</Button>
: r.State == 3 || r.autoRestore || r.confirmAuto ?
<Button theme='borderless' style={{ width: 65 }} disabled>自动恢复</Button> :
@ -383,7 +384,19 @@ const DataAlarm = ({ match, dispatch, actions, user, loading, socket, iotVcmpWeb
// console.log(selected);
const getAlarmConfirmItem = () => {
let source = route == 'useAbnormal' ? alarmToConfirm.appName : alarmToConfirm.SourceName;
let type = route == 'useAbnormal' ? alarmToConfirm.type : route == 'videoAbnormal' ? alarmToConfirm.AlarmContent : alarmToConfirm.AlarmGroupUnit;
return {
pepUserId: user.pomsUserInfo.pepUserId,
projectCorrelationIds: alarmToConfirm?.projectName?.map(p => p.id),
alarmInfo: {
id: alarmToConfirm.key,
source: source,//
type: type,//
}
};
}
return (
// route=='dataLnterrupt'|| route=='dataAbnormal'|| route=='strategyHit'?
@ -444,10 +457,10 @@ const DataAlarm = ({ match, dispatch, actions, user, loading, socket, iotVcmpWeb
width={600}
onCancel={() => setConfirm(false)}
onOk={() => {
let confirmPost = getAlarmConfirmItem();
if (route == 'useAbnormal') {
TextAreaApi.current.validate().then((v) => {
dispatch(problem.postApiConfirm({ appAlarmId: selected, confirm: content })).then(res => {
dispatch(problem.postApiConfirm({ appAlarmId: selected, confirm: content, confirmPost })).then(res => {
if (res.success) {
setConfirm(false)
setSelected([])
@ -457,7 +470,7 @@ const DataAlarm = ({ match, dispatch, actions, user, loading, socket, iotVcmpWeb
})
} else if (route == 'videoAbnormal') {
TextAreaApi.current.validate().then((v) => {
dispatch(problem.putAlarmVideoConfirm({ alarmId: selected, content: content })).then(res => {
dispatch(problem.putAlarmVideoConfirm({ alarmId: selected, content: content, confirmPost })).then(res => {
if (res.success) {
setConfirm(false)
setSelected([])
@ -476,7 +489,7 @@ const DataAlarm = ({ match, dispatch, actions, user, loading, socket, iotVcmpWeb
})
} else {
TextAreaApi.current.validate().then((v) => {
dispatch(problem.putAlarmdataConfirm({ alarmId: selected, content: content })).then(res => {
dispatch(problem.putAlarmdataConfirm({ alarmId: selected, content: content, confirmPost })).then(res => {
if (res.success) {
setConfirm(false)
let data = tableData?.map(v => {
@ -580,7 +593,7 @@ const DataAlarm = ({ match, dispatch, actions, user, loading, socket, iotVcmpWeb
)
}
function mapStateToProps (state) {
function mapStateToProps(state) {
const { auth, global, members, webSocket } = state
return {
// loading: members.isRequesting,

Loading…
Cancel
Save