|
|
|
'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 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 { clickHouse } = ctx.app.fs
|
|
|
|
const sequelize = ctx.fs.dc.orm
|
|
|
|
|
|
|
|
const progectGroupList = await models.ProjectGroup.findAll({
|
|
|
|
where: {
|
|
|
|
pomsUserId: userId
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// 获取全部的 poms 项目id 并构建关系
|
|
|
|
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()
|
|
|
|
for (let project of groupProjectRes) {
|
|
|
|
for (let projectId of project.anxinProjectId) {
|
|
|
|
anxinProjectIds.add(projectId)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let anxinProjectIdArr = Array.from(anxinProjectIds)
|
|
|
|
|
|
|
|
// 统计安心云项目下的结构物id
|
|
|
|
const strucIdRes = await clickHouse.anxinyun.query(
|
|
|
|
`
|
|
|
|
SELECT *
|
|
|
|
FROM t_project_structure
|
|
|
|
WHERE project IN (${[...anxinProjectIdArr].join(',')}, -1)
|
|
|
|
`
|
|
|
|
).toPromise()
|
|
|
|
|
|
|
|
let strucIds = new Set()
|
|
|
|
for (let struc of strucIdRes) {
|
|
|
|
strucIds.add(struc.structure)
|
|
|
|
}
|
|
|
|
|
|
|
|
let strucIdArr = Array.from(strucIds)
|
|
|
|
const deviceOffTimeRes = strucIdArr.length ? await models.StructureOff.findAll({
|
|
|
|
where: {
|
|
|
|
structure: { $in: strucIdArr }
|
|
|
|
}
|
|
|
|
}) : []
|
|
|
|
|
|
|
|
let rslt = []
|
|
|
|
for (let pg of progectGroupList) {
|
|
|
|
let strucCount = 0
|
|
|
|
let maxOffLineTime = 0
|
|
|
|
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_ =
|
|
|
|
strucIdRes.filter(s => gp.anxinProjectId.includes(s.project))
|
|
|
|
strucCount += strucIdArr_.length
|
|
|
|
//
|
|
|
|
for (let { dataValues: off } of deviceOffTimeRes) {
|
|
|
|
if (strucIdArr_.some((s) => s.structure == off.structure)) {
|
|
|
|
if (off.offline > maxOffLineTime) {
|
|
|
|
maxOffLineTime = off.offline
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count
|
|
|
|
}, 0)
|
|
|
|
rslt.unshift({
|
|
|
|
...pg.dataValues,
|
|
|
|
strucCount,
|
|
|
|
maxOffLineTime,
|
|
|
|
anxinProjectCount,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
|
|
|
const strucIdRes = 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() : []
|
|
|
|
|
|
|
|
// 查中断时间
|
|
|
|
const maxOfflineTimeRes = strucIdArr.length ? await models.StructureOff.findAll({
|
|
|
|
where: {
|
|
|
|
structure: { $in: strucIdArr },
|
|
|
|
state: 0
|
|
|
|
}
|
|
|
|
}) : []
|
|
|
|
|
|
|
|
// 查在线率
|
|
|
|
const strucOnlineClient = ctx.app.fs.esclient.strucOnline
|
|
|
|
const onlineRes = await strucOnlineClient.search({
|
|
|
|
index: strucOnlineClient.config.index,
|
|
|
|
type: strucOnlineClient.config.type,
|
|
|
|
body: {
|
|
|
|
"query": {
|
|
|
|
"bool": {
|
|
|
|
"filter": [
|
|
|
|
{
|
|
|
|
"range": {
|
|
|
|
"collect_time": {
|
|
|
|
"gte": `${moment().subtract(24, '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"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
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;
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
groupList,
|
|
|
|
editGroup,
|
|
|
|
delGroup,
|
|
|
|
groupStatistic,
|
|
|
|
groupStatisticOnline,
|
|
|
|
};
|