'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, };