diff --git a/api/app/lib/controllers/project/group.js b/api/app/lib/controllers/project/group.js index bead78f..c9f0fbb 100644 --- a/api/app/lib/controllers/project/group.js +++ b/api/app/lib/controllers/project/group.js @@ -116,7 +116,7 @@ async function groupStatistic (ctx) { } }) - // 获取全部的 poms 项目id 并构建关系 + // 获取全部的 poms 项目id let pomsProjectIds = new Set() for (let group of progectGroupList) { for (let projectId of group.pomsProjectIds) { @@ -318,10 +318,102 @@ async function groupStatisticOnline (ctx) { } } +async function groupStatisticAlarm (ctx) { + try { + const { models } = ctx.fs.dc; + + const { groupId } = ctx.query + const sequelize = ctx.fs.dc.orm + const { clickHouse } = ctx.app.fs + + const pomsProjectRes = await sequelize.query(` + SELECT project_correlation.anxin_project_id + FROM project_group + JOIN project_correlation + ON project_correlation.id = ANY(project_group.poms_project_ids) + WHERE project_group.id = ${groupId}; + `) + + const anxinProjectIds = new Set() + for (let pomsProject of (pomsProjectRes[0] || [])) { + for (let pid of pomsProject.anxin_project_id) + anxinProjectIds.add(pid) + } + + const strucIdRes = anxinProjectIds.size ? await clickHouse.anxinyun.query( + ` + SELECT * + FROM t_project_structure + WHERE project IN (${[...anxinProjectIds].join(',')}, -1) + ` + ).toPromise() : [] + let strucIds = new Set() + for (let struc of strucIdRes) { + strucIds.add(struc.structure) + } + let strucIdArr = Array.from(strucIds) + + const strucRes = strucIdArr.length ? await clickHouse.anxinyun.query( + ` + SELECT name, id FROM t_structure WHERE id IN (${[...strucIdArr].join(',')}); + ` + ).toPromise() : [] + + // 查一周内超阈值告警的个数 + strucIdArr = [1] + const alarmRes = strucIdArr.length ? await clickHouse.dataAlarm.query( + ` + SELECT StructureId,count(StructureId) AS alarmCount + FROM alarms + WHERE StructureId IN (${[...strucIdArr].join(',')}) + AND AlarmGroupUnit = 8 + AND StartTime >= '${moment().subtract(7, 'days').format('YYYY-MM-DD HH:mm:ss')}' + group by StructureId + ` + ).toPromise() : [] + + const alarmDealRes = strucIdArr.length ? await clickHouse.dataAlarm.query( + ` + SELECT StructureId,count(StructureId) AS alarmCount + FROM alarms + WHERE StructureId IN (${[...strucIdArr].join(',')}) + AND AlarmGroupUnit = 8 + AND State = 4 + AND StartTime >= '${moment().subtract(30, 'days').format('YYYY-MM-DD HH:mm:ss')}' + group by StructureId + ` + ).toPromise() : [] + + for (let struc of strucRes) { + let corAlarm = alarmRes.find((o) => o.StructureId == struc.id) + let corDealAlarm = alarmDealRes.find((o) => o.StructureId == struc.id) + struc.alarmCount = corAlarm ? corAlarm.alarmCount : 0 + struc.dealAlarmCount = corDealAlarm ? corDealAlarm.alarmCount : 0 + } + strucRes.sort((a, b) => b.alarmCount - a.alarmCount) + + ctx.status = 200; + ctx.body = strucRes; + // ctx.body = [{ + // id: 1, + // name: '测试结构物1', + // alarmCount: 128, + // dealAlarmCount: 23 + // }]; + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { + message: typeof error == 'string' ? error : undefined + } + } +} + module.exports = { groupList, editGroup, delGroup, groupStatistic, groupStatisticOnline, + groupStatisticAlarm, }; \ No newline at end of file diff --git a/api/app/lib/models/alarm_service_type.js b/api/app/lib/models/alarm_service_type.js index 2ec27b8..fbcb030 100644 --- a/api/app/lib/models/alarm_service_type.js +++ b/api/app/lib/models/alarm_service_type.js @@ -2,42 +2,42 @@ 'use strict'; module.exports = dc => { - const DataTypes = dc.ORM; - const sequelize = dc.orm; - const AlarmServiceType = sequelize.define("alarmServiceType", { - id: { - type: DataTypes.INTEGER, - allowNull: false, - defaultValue: null, - comment: null, - primaryKey: true, - field: "id", - autoIncrement: true, - unique: "alarm_service_type_id_uindex" - }, - name: { - type: DataTypes.STRING, - allowNull: false, - defaultValue: null, - comment: null, - primaryKey: false, - field: "name", - autoIncrement: false - }, - typeNumber: { - type: DataTypes.INTEGER, - allowNull: false, - defaultValue: null, - comment: null, - primaryKey: false, - field: "type_number", - autoIncrement: false - } - }, { - tableName: "alarm_service_type", - comment: "", - indexes: [] - }); - dc.models.AlarmServiceType = AlarmServiceType; - return AlarmServiceType; + const DataTypes = dc.ORM; + const sequelize = dc.orm; + const AlarmServiceType = sequelize.define("alarmServiceType", { + id: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: null, + comment: null, + primaryKey: true, + field: "id", + autoIncrement: true, + unique: "alarm_service_type_id_uindex" + }, + name: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: null, + comment: null, + primaryKey: false, + field: "name", + autoIncrement: false + }, + typeNumber: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: null, + comment: null, + primaryKey: false, + field: "type_number", + autoIncrement: false + } + }, { + tableName: "alarm_service_type", + comment: "", + indexes: [] + }); + dc.models.AlarmServiceType = AlarmServiceType; + return AlarmServiceType; }; \ No newline at end of file diff --git a/api/app/lib/models/equipment_maintenance_record.js b/api/app/lib/models/equipment_maintenance_record.js index 61185d9..9ec07ee 100644 --- a/api/app/lib/models/equipment_maintenance_record.js +++ b/api/app/lib/models/equipment_maintenance_record.js @@ -3,86 +3,86 @@ 'use strict'; module.exports = dc => { - const DataTypes = dc.ORM; - const sequelize = dc.orm; - const EquipmentMaintenanceRecord = sequelize.define("equipmentMaintenanceRecord", { - id: { - type: DataTypes.INTEGER, - allowNull: false, - defaultValue: null, - comment: null, - primaryKey: true, - field: "id", - autoIncrement: true - }, - equipmentType: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: null, - primaryKey: false, - field: "equipment_type", - autoIncrement: false - }, - equipmentCategory: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: null, - primaryKey: false, - field: "equipment_category", - autoIncrement: false - }, - maintenanceReason: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: null, - primaryKey: false, - field: "maintenance_reason", - autoIncrement: false - }, - solution: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: null, - primaryKey: false, - field: "solution", - autoIncrement: false - }, - reportTime: { - type: DataTypes.DATE, - allowNull: true, - defaultValue: null, - comment: null, - primaryKey: false, - field: "report_time", - autoIncrement: false - }, - completedTime: { - type: DataTypes.DATE, - allowNull: true, - defaultValue: null, - comment: null, - primaryKey: false, - field: "completed_time", - autoIncrement: false - }, - status: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: null, - primaryKey: false, - field: "status", - autoIncrement: false - } - }, { - tableName: "equipment_maintenance_record", - comment: "", - indexes: [] - }); - dc.models.EquipmentMaintenanceRecord = EquipmentMaintenanceRecord; - return EquipmentMaintenanceRecord; + const DataTypes = dc.ORM; + const sequelize = dc.orm; + const EquipmentMaintenanceRecord = sequelize.define("equipmentMaintenanceRecord", { + id: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: null, + comment: null, + primaryKey: true, + field: "id", + autoIncrement: true + }, + equipmentType: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: null, + primaryKey: false, + field: "equipment_type", + autoIncrement: false + }, + equipmentCategory: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: null, + primaryKey: false, + field: "equipment_category", + autoIncrement: false + }, + maintenanceReason: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: null, + primaryKey: false, + field: "maintenance_reason", + autoIncrement: false + }, + solution: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: null, + primaryKey: false, + field: "solution", + autoIncrement: false + }, + reportTime: { + type: DataTypes.DATE, + allowNull: true, + defaultValue: null, + comment: null, + primaryKey: false, + field: "report_time", + autoIncrement: false + }, + completedTime: { + type: DataTypes.DATE, + allowNull: true, + defaultValue: null, + comment: null, + primaryKey: false, + field: "completed_time", + autoIncrement: false + }, + status: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: null, + primaryKey: false, + field: "status", + autoIncrement: false + } + }, { + tableName: "equipment_maintenance_record", + comment: "", + indexes: [] + }); + dc.models.EquipmentMaintenanceRecord = EquipmentMaintenanceRecord; + return EquipmentMaintenanceRecord; }; \ No newline at end of file diff --git a/api/app/lib/models/project_correlation.js b/api/app/lib/models/project_correlation.js index b1b5990..66526cb 100644 --- a/api/app/lib/models/project_correlation.js +++ b/api/app/lib/models/project_correlation.js @@ -2,96 +2,96 @@ 'use strict'; module.exports = dc => { - const DataTypes = dc.ORM; - const sequelize = dc.orm; - const ProjectCorrelation = sequelize.define("projectCorrelation", { - id: { - type: DataTypes.INTEGER, - allowNull: false, - defaultValue: null, - comment: null, - primaryKey: true, - field: "id", - autoIncrement: true, - unique: "project_correlation_id_uindex" - }, - anxinProjectId: { - type: DataTypes.ARRAY(DataTypes.INTEGER), - allowNull: false, - defaultValue: null, - comment: null, - primaryKey: false, - field: "anxin_project_id", - autoIncrement: false - }, - createTime: { - type: DataTypes.DATE, - allowNull: false, - defaultValue: null, - comment: null, - primaryKey: false, - field: "create_time", - autoIncrement: false - }, - createUser: { - type: DataTypes.INTEGER, - allowNull: false, - defaultValue: null, - comment: null, - primaryKey: false, - field: "create_user", - autoIncrement: false - }, - name: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: null, - primaryKey: false, - field: "name", - autoIncrement: false - }, - pepProjectId: { - type: DataTypes.INTEGER, - allowNull: true, - defaultValue: null, - comment: null, - primaryKey: false, - field: "pep_project_id", - autoIncrement: false - }, - del: { - type: DataTypes.BOOLEAN, - allowNull: true, - defaultValue: null, - comment: null, - primaryKey: false, - field: "del", - autoIncrement: false - }, - updateTime: { - type: DataTypes.DATE, - allowNull: false, - defaultValue: null, - comment: null, - primaryKey: false, - field: "update_time", - autoIncrement: false - }, - mappingClass: { - type: DataTypes.STRING, - allowNull: true, - defaultValue: null, - comment: null, - primaryKey: false, - field: "mapping_class", - autoIncrement: false - }, - }, { - tableName: "project_correlation", - comment: "", - indexes: [] - }); - dc.models.ProjectCorrelation = ProjectCorrelation; - return ProjectCorrelation; + const DataTypes = dc.ORM; + const sequelize = dc.orm; + const ProjectCorrelation = sequelize.define("projectCorrelation", { + id: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: null, + comment: null, + primaryKey: true, + field: "id", + autoIncrement: true, + unique: "project_correlation_id_uindex" + }, + anxinProjectId: { + type: DataTypes.ARRAY(DataTypes.INTEGER), + allowNull: false, + defaultValue: null, + comment: null, + primaryKey: false, + field: "anxin_project_id", + autoIncrement: false + }, + createTime: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: null, + comment: null, + primaryKey: false, + field: "create_time", + autoIncrement: false + }, + createUser: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: null, + comment: null, + primaryKey: false, + field: "create_user", + autoIncrement: false + }, + name: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: null, + primaryKey: false, + field: "name", + autoIncrement: false + }, + pepProjectId: { + type: DataTypes.INTEGER, + allowNull: true, + defaultValue: null, + comment: null, + primaryKey: false, + field: "pep_project_id", + autoIncrement: false + }, + del: { + type: DataTypes.BOOLEAN, + allowNull: true, + defaultValue: null, + comment: null, + primaryKey: false, + field: "del", + autoIncrement: false + }, + updateTime: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: null, + comment: null, + primaryKey: false, + field: "update_time", + autoIncrement: false + }, + mappingClass: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: null, + primaryKey: false, + field: "mapping_class", + autoIncrement: false + }, + }, { + tableName: "project_correlation", + comment: "", + indexes: [] + }); + dc.models.ProjectCorrelation = ProjectCorrelation; + return ProjectCorrelation; }; \ No newline at end of file diff --git a/api/app/lib/routes/project/index.js b/api/app/lib/routes/project/index.js index 395f6c2..545d829 100644 --- a/api/app/lib/routes/project/index.js +++ b/api/app/lib/routes/project/index.js @@ -45,4 +45,7 @@ module.exports = function (app, router, opts) { app.fs.api.logAttr['GET/project/group/statistic/online'] = { content: '获取项目分组在线率统计信息', visible: true }; router.get('/project/group/statistic/online', projectGroup.groupStatisticOnline); + + app.fs.api.logAttr['GET/project/group/statistic/alarm'] = { content: '获取项目分组告警统计信息', visible: true }; + router.get('/project/group/statistic/alarm', projectGroup.groupStatisticAlarm); }; \ No newline at end of file diff --git a/web/client/assets/images/projectGroup/first.png b/web/client/assets/images/projectGroup/first.png new file mode 100644 index 0000000..9b8a315 Binary files /dev/null and b/web/client/assets/images/projectGroup/first.png differ diff --git a/web/client/assets/images/projectGroup/second.png b/web/client/assets/images/projectGroup/second.png new file mode 100644 index 0000000..6f8af3b Binary files /dev/null and b/web/client/assets/images/projectGroup/second.png differ diff --git a/web/client/assets/images/projectGroup/third.png b/web/client/assets/images/projectGroup/third.png new file mode 100644 index 0000000..996d8fd Binary files /dev/null and b/web/client/assets/images/projectGroup/third.png differ diff --git a/web/client/src/sections/projectGroup/actions/group.js b/web/client/src/sections/projectGroup/actions/group.js index f60a956..aa351e8 100644 --- a/web/client/src/sections/projectGroup/actions/group.js +++ b/web/client/src/sections/projectGroup/actions/group.js @@ -55,4 +55,18 @@ export function groupStatisticOnline (query = {}) { msg: { error: "获取项目分组在线率统计信息失败" }, reducer: { name: "groupStatisticOnline", params: { noClear: true } }, }); +} + + +export function groupStatisticAlarm (query = {}) { + return (dispatch) => basicAction({ + type: "get", + dispatch: dispatch, + query, + actionType: "GET_STATISTICALARM", + url: `${ApiTable.groupStatisticAlarm}`, + msg: { error: "获获取项目分组告警统计信息失败" }, + reducer: { name: "groupStatisticAlarm", + params: { noClear: true } }, + }); } \ No newline at end of file diff --git a/web/client/src/sections/projectGroup/containers/bigscreen.jsx b/web/client/src/sections/projectGroup/containers/bigscreen.jsx index 50f304d..8cb4e29 100644 --- a/web/client/src/sections/projectGroup/containers/bigscreen.jsx +++ b/web/client/src/sections/projectGroup/containers/bigscreen.jsx @@ -11,6 +11,7 @@ import PerfectScrollbar from "perfect-scrollbar"; let interrupt +let overviewScrollbar; const Bigscreen = ({ dispatch, actions, user, match, history, clientHeight, groupStatisticOnline }) => { const [InterruptRank, setInterruptRank] = useState([]) @@ -18,14 +19,104 @@ const Bigscreen = ({ dispatch, actions, user, match, history, clientHeight, grou const [value, setValue] = useState([]) const [time, setTime] = useState([]) + const [alarmData, setAlarmData] = useState()//第三项之后的数据 + const [biggest, setBiggest] = useState()//最大的刻度值 + const [mockData, setMockData] = useState()//所有的告警数据 + const [xData, setXData] = useState([])//横坐标 + + useEffect(() => { let groupId = JSON.parse(localStorage.getItem('project_group'))?.find(v => user?.id == v.userId)?.projectGroupId - console.log(); statisticOnline(groupId) + dispatch(actions.projectGroup.groupStatisticAlarm({ groupId })).then(res => { + if (res.success) { + setMockData(res.data) + } + }) + + + const interruptDom = document.getElementById("interrupt"); + if (interruptDom) { + interrupt = new PerfectScrollbar("#interrupt", { + suppressScrollX: true, + }); + } + + }, []) + + useEffect(() => { + const overview = document.getElementById("alarmRank"); + if (overview) { + overviewScrollbar = new PerfectScrollbar("#alarmRank", { + suppressScrollX: true, + }); + } + if (overviewScrollbar && overview) { + overviewScrollbar.update(); + + } + + const interruptDom = document.getElementById("interrupt"); + if (interrupt && interruptDom) { + interrupt.update(); + + } + }) + useEffect(() => { + const maxCombinedValue = mockData?.reduce((max, item) => { + const combinedMax = Math.max(item.alarmCount, item.dealAlarmCount); + if (combinedMax > max) { + return combinedMax; + } + return max; + }, -Infinity) + const bigD = Math.ceil(maxCombinedValue / 50) * 50 + 50, 40, 30, 20, 10, 0 + setXData([bigD, (bigD - bigD / 5), (bigD - bigD * 2 / 5), (bigD - bigD * 3 / 5), (bigD - bigD * 4 / 5), 0, (bigD - bigD * 4 / 5), (bigD - bigD * 3 / 5), (bigD - bigD * 2 / 5), (bigD - bigD / 5), bigD]) + setBiggest(bigD) + }, []) + // const mockData=[ + // {id: 1,name: '测试结构物测试结构物',alarmCount: 200,dealAlarmCount: 23}, + // {id: 2,name: '测试结构物2',alarmCount: 300,dealAlarmCount: 22}, + // {id: 3,name: '测试结构物3',alarmCount: 140,dealAlarmCount: 21}, + // {id: 4,name: '测试结构物4',alarmCount: 120,dealAlarmCount: 23}, + // {id: 5,name: '测试结构物5',alarmCount: 110,dealAlarmCount: 22}, + // {id: 6,name: '测试结构物6',alarmCount: 109,dealAlarmCount: 21}, + // {id: 7,name: '测试结构物7',alarmCount: 100,dealAlarmCount: 23}, + // {id: 8,name: '测试结构物8',alarmCount: 99,dealAlarmCount: 22}, + // {id: 9,name: '测试结构物9',alarmCount: 98,dealAlarmCount: 21}, + // {id: 10,name: '测试结构物10',alarmCount: 97,dealAlarmCount: 23}, + // {id: 11,name: '测试结构物11',alarmCount: 96,dealAlarmCount: 22}, + // {id: 12,name: '测试结构物12',alarmCount: 95,dealAlarmCount: 21}, + // {id: 13,name: '测试结构物13',alarmCount: 100,dealAlarmCount: 23}, + // {id: 14,name: '测试结构物14',alarmCount: 49,dealAlarmCount: 22}, + // {id: 15,name: '测试结构物15',alarmCount: 48,dealAlarmCount: 21}, + // {id: 16,name: '测试结构物16',alarmCount: 47,dealAlarmCount: 23}, + // {id: 17,name: '测试结构物17',alarmCount: 46,dealAlarmCount: 22}, + // {id: 18,name: '测试结构物18',alarmCount: 45,dealAlarmCount: 21}, + // {id: 19,name: '测试结构物19',alarmCount: 30,dealAlarmCount: 22}, + // {id: 20,name: '测试结构物20',alarmCount: 29,dealAlarmCount: 21}, + // {id: 21,name: '测试结构物21',alarmCount: 28,dealAlarmCount: 23}, + // {id: 22,name: '测试结构物22',alarmCount: 27,dealAlarmCount: 22}, + // {id: 23,name: '测试结构物23',alarmCount: 26,dealAlarmCount: 21}, + // ] + useEffect(() => { + if (mockData && mockData.length > 3 && mockData.length < 21) { + const newArray = mockData.slice(3) + setAlarmData(newArray) + } + if (mockData && mockData.length > 21) { + //数据大于20的话,取前20 + const newArray = mockData.slice(3, 20) + setAlarmData(newArray) + } + }, []) + + let statisticOnline = (groupId) => { dispatch(actions.projectGroup.groupStatisticOnline({ groupId })).then(res => { console.log(res); @@ -92,20 +183,6 @@ const Bigscreen = ({ dispatch, actions, user, match, history, clientHeight, grou - - function handleRow (record, index) {//斑马条纹 - // 给偶数行设置斑马纹 - if (index % 2 === 0) { - return { - style: { - background: '#F6F9FF', - } - }; - } else { - return {}; - } - } - return (