运维服务中台
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

720 lines
23 KiB

'use strict';
const moment = require('moment')
async function groupList (ctx) {
try {
const { models } = ctx.fs.dc;
const { userId } = ctx.fs.api
const res = await models.ProjectGroup.findAll({
where: {
pomsUserId: userId
},
order: [['id', 'DESC']]
})
ctx.status = 200;
ctx.body = res
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function groupDetail (ctx) {
try {
const { models } = ctx.fs.dc;
const { groupId } = ctx.params
const res = await models.ProjectGroup.findOne({
where: {
id: groupId
}
})
ctx.status = 200;
ctx.body = res
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function editGroup (ctx) {
try {
const { models } = ctx.fs.dc;
const { userId } = ctx.fs.api
const { id, name, pomsProjectIds = [] } = ctx.request.body
if (!name || !pomsProjectIds || !pomsProjectIds.length) {
throw '参数错误!'
}
let repeatNameRes = await models.ProjectGroup.findOne({
where: {
pomsUserId: userId,
name,
}
})
let repeatProjectRes = await models.ProjectGroup.findOne({
where: {
pomsUserId: userId,
pomsProjectIds
}
})
if (repeatNameRes && (!id || (id && repeatNameRes.id != id))) {
throw '已有相同名称的分组信息!'
}
if (repeatProjectRes && (!id || (id && repeatProjectRes.id != id))) {
throw '已有相同项目的分组信息!'
}
if (id) {
await models.ProjectGroup.update({
name,
pomsProjectIds,
}, {
where: {
id
}
})
} else {
await models.ProjectGroup.create({
name,
pomsProjectIds,
pomsUserId: userId,
}, {
where: {
id
}
})
}
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function delGroup (ctx) {
try {
const { models } = ctx.fs.dc;
await models.ProjectGroup.destroy({
where: {
id: ctx.query.groupId
}
})
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function groupStatistic (ctx) {
try {
const { models } = ctx.fs.dc;
const { userId } = ctx.fs.api
const { pomsU } = ctx.query
const { clickHouse } = ctx.app.fs
const { utils: { judgeSuper, anxinStrucIdRange } } = ctx.app.fs
const sequelize = ctx.fs.dc.orm
let userId_ = pomsU || userId
1 year ago
const progectGroupList = await models.ProjectGroup.findAll({
where: {
pomsUserId: userId_
1 year ago
}
})
1 year ago
// 获取全部的 poms 项目id 并构建关系
1 year ago
let pomsProjectIds = new Set()
for (let group of progectGroupList) {
for (let projectId of group.pomsProjectIds) {
pomsProjectIds.add(projectId)
}
}
let pomsProjectIdArr = Array.from(pomsProjectIds)
const groupProjectRes = await models.ProjectCorrelation.findAll({
where: {
id: { $in: pomsProjectIdArr }
}
})
// 获取所有的 安心云项目id
let anxinProjectIds = new Set()
let pepmProjectIds = new Set()
1 year ago
for (let project of groupProjectRes) {
for (let projectId of project.anxinProjectId) {
anxinProjectIds.add(projectId)
}
if (project.pepProjectId) {
pepmProjectIds.add(project.pepProjectId)
}
1 year ago
}
let anxinProjectIdArr = Array.from(anxinProjectIds)
let pepmProjectIdArr = Array.from(pepmProjectIds)
// 查询pepm项目的客户等级
console.log(`查询pepm项目`, pepmProjectIdArr.join(','));
let pepmCustomerLevelRes = pepmProjectIdArr.length ? await clickHouse.projectManage.query(
`
SELECT t_rpm_customer_level.id AS id, t_rpm_customer_level.name AS name, t_pim_project.id AS projectId
FROM t_pim_project
LEFT JOIN t_rpm_customer
ON t_rpm_customer.id = t_pim_project.related_customers_id
LEFT JOIN t_rpm_customer_level
ON t_rpm_customer_level.id = t_rpm_customer.level
WHERE t_pim_project.id IN (${pepmProjectIdArr.join(',')},-1)
`
).toPromise() : []
console.log(pepmCustomerLevelRes);
// pepmCustomerLevelRes = pepmCustomerLevelRes.filter(item => item && item.id > 0)
// 统计安心云项目下的结构物
const strucRes = anxinProjectIdArr.length ? await clickHouse.anxinyun.query(
`
SELECT
DISTINCT t_structure.id AS strucId,
t_project.id AS projectId,
t_structure.name AS strucName,
project_state
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 (${anxinProjectIdArr.join(',')},-1)
`
).toPromise() : []
let strucIds = new Set()
for (let struc of strucRes) {
strucIds.add(struc.strucId)
}
let strucIdArr = Array.from(strucIds)
const deviceOffTimeRes = strucIdArr.length ? await models.StructureOff.findAll({
where: {
structure: { $in: strucIdArr }
}
}) : []
const alarmRes = strucIdArr.length ? await clickHouse.dataAlarm.query(
`
SELECT StructureId,count(StructureId) AS alarmCount
FROM alarms
WHERE StructureId IN (${strucIdArr.join(',')}, -1)
AND AlarmGroupUnit = 8
AND StartTime >= '${moment().subtract(1, 'days').format('YYYY-MM-DD HH:mm:ss')}'
group by StructureId
`
).toPromise() : []
let rslt = []
// progectGroupList 是自定义分组信息
for (let pg of progectGroupList) {
let strucCount = 0
let maxOffLineTime = 0
let todayAlarms = 0
let pepmCustomerLevels = []
// groupProjectRes 是poms项目信息
let anxinProjectCount = groupProjectRes.reduce((count, gp) => {
if (pg.pomsProjectIds.some(id => gp.id == id)) {
// 如果 pg 分组信息 存储的 pomsProjectIds 运维项目id 和 真正的 groupProjectRes 运维项目id 相等
// gp.anxinProjectId 就是对应的 安心云的项目 id 集
count += gp.anxinProjectId.length
//
let strucIdArr_ =
strucRes.filter(s => gp.anxinProjectId.includes(s.projectId))
strucCount += strucIdArr_.length
//所有结构物的告警
const ss = alarmRes.filter(p => strucIdArr_.some(q => q.strucId == p.StructureId))
todayAlarms = ss.reduce((p, c) => {
return p + c.alarmCount
}, 0)
//
if (gp.pepProjectId) {
let corLevel = pepmCustomerLevelRes.find(p => p.projectId == gp.pepProjectId)
if (corLevel) {
pepmCustomerLevels.push(corLevel)
}
}
//
for (let { dataValues: off } of deviceOffTimeRes) {
if (strucIdArr_.some((s) => s.strucId == off.structure)) {
if (off.offline > maxOffLineTime) {
maxOffLineTime = off.offline
}
}
}
}
return count
}, 0)
console.log(pg.id, pepmCustomerLevels);
pepmCustomerLevels.sort((a, b) => a.id - b.id)
rslt.unshift({
...pg.dataValues,
strucCount,
todayAlarms,
maxOffLineTime,
anxinProjectCount,
level: pepmCustomerLevels.length ? pepmCustomerLevels[0] : null
})
}
ctx.status = 200;
ctx.body = rslt
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function groupStatisticOnline (ctx) {
try {
const { models } = ctx.fs.dc;
const { userId } = ctx.fs.api
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)
}
// 统计安心云项目下的结构物
1 year ago
const strucRes = anxinProjectIds.size ? await clickHouse.anxinyun.query(
`
SELECT
DISTINCT t_structure.id AS id,
t_project.id AS projectId,
t_structure.name AS name,
project_state
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
1 year ago
t_project.id IN (${[...anxinProjectIds].join(',')},-1)
`
).toPromise() : []
let strucIds = new Set()
for (let struc of strucRes) {
strucIds.add(struc.id)
}
let strucIdArr = Array.from(strucIds)
1 year ago
// 查中断时间
const maxOfflineTimeRes = strucIdArr.length ?
await models.StructureOff.findAll({
where: {
structure: { $in: strucIdArr },
state: 0,
offline: { $gt: 720 }
}
}) : []
1 year ago
// 查在线率
const strucOnlineClient = ctx.app.fs.esclient.strucOnline
const onlineRes = strucIdArr.length ?
await strucOnlineClient.search({
index: strucOnlineClient.config.index,
type: strucOnlineClient.config.type,
body: {
"query": {
"bool": {
"filter": [
{
"range": {
"collect_time": {
"gte": `${moment().subtract(32, 'hours').format('YYYY-MM-DDTHH:mm:ss.SSS')}Z`,
// "gte": "2023-08-24T08:00:00.000Z",
}
}
},
{
"terms": {
"structure": strucIdArr,
// "structure": [1, 2, 3]
}
}
]
}
},
"sort": [
{
"collect_time": {
"order": "asc"
}
}
],
"size": 10000
}
})
: {
hits: {
hits: []
}
}
1 year ago
for (let struc of strucRes) {
let curOnline =
onlineRes.hits.hits
.filter((h) => h._source.structure == struc.id)
// .sort((a, b) => {
// return a._source.collect_time - b._source.collect_time
// })
.map(s => {
return {
...s._source,
rate: s._source.online / s._source.total * 100
}
})
let curOffline = maxOfflineTimeRes.find((o) => o.structure == struc.id)
struc.online = curOnline
struc.offline = curOffline || {}
}
ctx.status = 200;
1 year ago
ctx.body = strucRes;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
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)
}
// 统计安心云项目下的结构物
1 year ago
const strucRes = anxinProjectIds.size ? await clickHouse.anxinyun.query(
`
SELECT
DISTINCT t_structure.id AS id,
t_project.id AS projectId,
t_structure.name AS name,
project_state
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
1 year ago
t_project.id IN (${[...anxinProjectIds].join(',')},-1)
`
).toPromise() : []
let strucIds = new Set()
for (let struc of strucRes) {
strucIds.add(struc.id)
}
let strucIdArr = Array.from(strucIds)
// 查一周内超阈值告警的个数
const alarmRes = strucIdArr.length ? await clickHouse.dataAlarm.query(
`
SELECT StructureId,count(StructureId) AS alarmCount
FROM alarms
WHERE StructureId IN (${strucIdArr.join(',')}, -1)
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(',')}, -1)
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
}
}
}
1 year ago
async function groupProject (ctx) {
try {
const { models } = ctx.fs.dc;
const { groupId } = ctx.query
const { clickHouse } = ctx.app.fs
const findOne = await models.ProjectGroup.findOne({ where: { id: groupId } })
const proRes = await models.ProjectCorrelation.findAll({ where: { id: { $in: findOne.pomsProjectIds } } })
let pepProjectIds = new Set()
for (let p of proRes) {
if (p.pepProjectId) {
pepProjectIds.add(p.pepProjectId)
}
}
const pepProjectRes = pepProjectIds.size ?
await clickHouse.projectManage.query(
`
SELECT
t_pim_project.id AS id,
t_pim_project.project_name AS project_name,
t_pim_project.isdelete AS isdelete,
t_pim_project_construction.construction_status_id AS construction_status_id,
t_pim_project_state.construction_status AS construction_status
FROM t_pim_project
LEFT JOIN t_pim_project_construction
ON t_pim_project.id = t_pim_project_construction.project_id
LEFT JOIN t_pim_project_state
ON t_pim_project_construction.construction_status_id = t_pim_project_state.id
WHERE id IN (${[...pepProjectIds].join(',')}, -1)
`
).toPromise() :
[]
for (let p of proRes) {
const corPro = pepProjectRes.find(pp => pp.id == p.pepProjectId) || {}
p.dataValues.pepProjectName = corPro.project_name
}
ctx.status = 200;
ctx.body = proRes;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function getProjectWorkOrders (ctx) {
try {
// 计算一个月前的日期
const oneMonthAgo = moment().subtract(1, 'months').toDate()
const { models } = ctx.fs.dc
1 year ago
const sequelize = ctx.fs.dc.ORM
const { projectIds } = ctx.query
if (projectIds && projectIds.length) {
const projectIdsArr = projectIds.split(',').map(Number)
const res = await models.FormDataTable.findAll({
attributes: [
'projectId',
[sequelize.fn('COUNT', sequelize.col('id')), 'count'],
],
where: {
projectId: {
$in: projectIdsArr,
},
startTime: {
$gte: oneMonthAgo,
},
},
group: ['projectId'],
order: [[sequelize.fn('COUNT', sequelize.col('id')), 'DESC']],
})
ctx.body = res
ctx.status = 200
} else {
ctx.body = '没有查询到数据'
ctx.status = 204
}
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function getWorkOrdersRepairRank (ctx) {
try {
const oneMonthAgo = moment().subtract(1, 'months').toDate()
const { models } = ctx.fs.dc
const sequelize = ctx.fs.dc.ORM
const { projectIds } = ctx.query
1 year ago
if (projectIds && projectIds.length) {
const res = await models.FormDataTable.findAll({
where: {
1 year ago
projectId: {
$in: projectIds.split(',').map(Number)
},
startTime: {
$gte: oneMonthAgo,
}
},
order: [
1 year ago
[sequelize.literal('(EXTRACT(EPOCH FROM "end_time" - "start_time"))'), 'DESC']
]
})
ctx.body = res
ctx.status = 200
} else {
ctx.body = '没有查询到信息'
ctx.status = 204
}
} 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,
groupDetail,
editGroup,
delGroup,
groupStatistic,
groupStatisticOnline,
groupStatisticAlarm,
groupProject,
getProjectWorkOrders,
getWorkOrdersRepairRank
};