巴林闲侠
2 years ago
14 changed files with 1277 additions and 54 deletions
@ -0,0 +1,154 @@ |
|||||
|
'use strict'; |
||||
|
|
||||
|
const moment = require('moment') |
||||
|
//const db = require('../')
|
||||
|
async function getFailureTime(ctx) { |
||||
|
const sequelize = ctx.fs.dc.orm |
||||
|
try { |
||||
|
const res = await sequelize.query( |
||||
|
`SELECT substring(to_char(w.wmonth,'yyyy-mm'),1,7) wmonth,COALESCE(e.counts,0) count
|
||||
|
from ( SELECT COUNT(1) counts,to_char(maintenance_record.occurrence_time, 'yyyy-mm') months |
||||
|
FROM maintenance_record |
||||
|
GROUP BY months |
||||
|
) e |
||||
|
RIGHT JOIN |
||||
|
( |
||||
|
SELECT to_date(EXTRACT(YEAR FROM (current_date - INTERVAL '1 month' * (t - 1))) ||'-' |
||||
|
|| EXTRACT(MONTH FROM (current_date - INTERVAL '1 month' * (t - 1))),'yyyy-mm')as wmonth |
||||
|
from generate_series(1, 12) as t |
||||
|
) w on e.months = substring(to_char(w.wmonth,'yyyy-mm'),1,7) |
||||
|
GROUP BY w.wmonth,e.counts |
||||
|
ORDER BY w.wmonth desc` |
||||
|
) |
||||
|
console.log('111112232', res) |
||||
|
let resList = [] |
||||
|
if (res.length > 0) { |
||||
|
res[0].forEach((item) => { |
||||
|
resList.push(item) |
||||
|
}) |
||||
|
|
||||
|
} |
||||
|
ctx.status = 200 |
||||
|
ctx.body = resList |
||||
|
} catch (error) { |
||||
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { |
||||
|
message: '查询故障发生时间失败' |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
async function getSystemAvailability(ctx) { |
||||
|
const sequelize = ctx.fs.dc.orm |
||||
|
try { |
||||
|
const res = await sequelize.query( |
||||
|
`SELECT substring(to_char(w.wmonth,'yyyy-mm'),1,7) wmonth,
|
||||
|
COALESCE((w.seconds-e.counts)/w.seconds,0) ability |
||||
|
from ( |
||||
|
SELECT to_char(maintenance_record.occurrence_time, 'yyyy-MM') months, |
||||
|
SUM(maintenance_record.interrupt_duration) counts |
||||
|
FROM maintenance_record |
||||
|
where maintenance_record.occurrence_time is not null |
||||
|
GROUP BY months |
||||
|
) e |
||||
|
RIGHT JOIN |
||||
|
( |
||||
|
SELECT to_date(EXTRACT(YEAR FROM (current_date - INTERVAL '1 month' * (n - 1))) ||'-'|| EXTRACT(MONTH FROM (current_date - INTERVAL '1 month' * (n - 1))),'yyyy-mm') as wmonth, |
||||
|
(EXTRACT(DAY FROM (DATE_TRUNC('MONTH', current_date - INTERVAL '1 month' * (n - 1) + INTERVAL '1 MONTH') - DATE_TRUNC('MONTH', current_date - INTERVAL '1 month' * (n - 1)) - INTERVAL '1 DAY'))+1)* 24 * 60 * 60 AS seconds |
||||
|
from generate_series(1, 12) AS n |
||||
|
) w |
||||
|
on e.months = substring(to_char(w.wmonth,'yyyy-mm'),1,7) |
||||
|
GROUP BY w.wmonth,w.seconds,e.counts |
||||
|
ORDER BY w.wmonth DESC;` |
||||
|
) |
||||
|
let resList = [] |
||||
|
if (res.length > 0) { |
||||
|
res[0].forEach((item) => { |
||||
|
resList.push(item) |
||||
|
}) |
||||
|
} |
||||
|
ctx.status = 200 |
||||
|
ctx.body = resList |
||||
|
|
||||
|
} catch (error) { |
||||
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { |
||||
|
message: '查询系统可用性失败' |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
async function getProblemType(ctx) { |
||||
|
const sequelize = ctx.fs.dc.orm |
||||
|
try { |
||||
|
const res = await sequelize.query(` |
||||
|
SELECT n.type,COALESCE(m.count,0) count FROM (SELECT t.type,count(1) FROM maintenance_record t GROUP BY t.type) m |
||||
|
RIGHT JOIN (SELECT p.type FROM system_problem p) n |
||||
|
ON m.type=n.type |
||||
|
GROUP BY n.type,m.count |
||||
|
`)
|
||||
|
let resList = [] |
||||
|
if (res.length > 0) { |
||||
|
res[0].forEach((item) => { |
||||
|
resList.push(item) |
||||
|
}) |
||||
|
|
||||
|
} |
||||
|
ctx.status = 200 |
||||
|
ctx.body = resList |
||||
|
} catch (error) { |
||||
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { |
||||
|
message: '查询故障类型失败' |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
async function getOperationsPersonnel(ctx) { |
||||
|
const sequelize = ctx.fs.dc.orm |
||||
|
const { clickHouse } = ctx.app.fs |
||||
|
try { |
||||
|
//查询用户id
|
||||
|
const res = await sequelize.query(`SELECT t.pep_user_id userId,count(1) FROM maintenance_plan_execute_user t GROUP BY pep_user_id`) |
||||
|
let useList = new Set() |
||||
|
console.log('rss', res) |
||||
|
if (res.length > 0) { |
||||
|
res[0].forEach((item) => { |
||||
|
useList.add(item.userid) |
||||
|
}) |
||||
|
} |
||||
|
let users = useList ? await clickHouse.pepEmis.query(`SELECT DISTINCT user.id AS id, "user"."name" AS name FROM user WHERE user.id IN
|
||||
|
(${[...useList].join(',')}, -1)`).toPromise() : []
|
||||
|
let resRecord = [] |
||||
|
if (res.length > 0) { |
||||
|
res[0].forEach((item) => { |
||||
|
resRecord.push(item) |
||||
|
}) |
||||
|
} |
||||
|
let mergedArray = [] |
||||
|
if (users.length > 0 && resRecord.length > 0) { |
||||
|
mergedArray = users.map(item1 => { |
||||
|
const item2 = resRecord.find(item2 => item2.userid === item1.id); |
||||
|
return { |
||||
|
userid: item1.id, |
||||
|
name: item1.name, |
||||
|
count: parseInt(item2.count) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
ctx.status = 200 |
||||
|
ctx.body = mergedArray |
||||
|
} catch (error) { |
||||
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { |
||||
|
message: '查询运维人员失败' |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
module.exports = { |
||||
|
getFailureTime, getSystemAvailability, getProblemType, getOperationsPersonnel |
||||
|
} |
@ -0,0 +1,297 @@ |
|||||
|
'use strict'; |
||||
|
const moment = require('moment') |
||||
|
|
||||
|
async function getMaintenceRecordRank(ctx) { |
||||
|
const sequelize = ctx.fs.dc.orm |
||||
|
const Sequelize = ctx.fs.dc.ORM; |
||||
|
const { clickHouse } = ctx.app.fs |
||||
|
const models = ctx.fs.dc.models |
||||
|
const { startTime, endTime } = ctx.query |
||||
|
|
||||
|
console.log(startTime, endTime, ctx.query, '1212312') |
||||
|
try { |
||||
|
const res = await sequelize.query(` |
||||
|
SELECT emrp.project_id,count(1) |
||||
|
FROM equipment_maintenance_record |
||||
|
RIGHT JOIN equipment_maintenance_record_project emrp |
||||
|
on equipment_maintenance_record.id = emrp.equipment_maintenance_record_id |
||||
|
where report_time BETWEEN :startTime AND :endTime |
||||
|
GROUP BY emrp.project_id |
||||
|
` |
||||
|
, { |
||||
|
replacements: { |
||||
|
startTime: moment(startTime).format('YYYY-MM-DD HH:mm:ss'), |
||||
|
endTime: moment(endTime).format('YYYY-MM-DD HH:mm:ss ') |
||||
|
} |
||||
|
//, type: sequelize.QueryTypes.SELECT
|
||||
|
} |
||||
|
) |
||||
|
//查询equipment_maintenance_record返回的结果[{project_id: 22, count: 1}]
|
||||
|
let projectList = [] |
||||
|
//存project的id
|
||||
|
let projectIdList = [] |
||||
|
// console.log('resssss', res)
|
||||
|
if (res.length > 0) { |
||||
|
res[0].forEach((item) => { |
||||
|
projectList.push({ project_id: item.project_id, count: Number(item.count) }) |
||||
|
projectIdList.push(item.project_id) |
||||
|
}) |
||||
|
} |
||||
|
const projectNameList = await models.ProjectCorrelation.findAll({ |
||||
|
attributes: |
||||
|
['id', 'name'], |
||||
|
where: { |
||||
|
id: { $in: projectIdList }, |
||||
|
name: { |
||||
|
[Sequelize.Op.not]: null//有name的结果
|
||||
|
} |
||||
|
// del: false
|
||||
|
} |
||||
|
}) || [] |
||||
|
//在ProjectCorrelation中查不到名字,去clickHouse中去查
|
||||
|
const projectNameList1 = await models.ProjectCorrelation.findAll({ |
||||
|
attributes: |
||||
|
['id', 'name', 'pepProjectId'], |
||||
|
where: { |
||||
|
id: { $in: projectIdList }, |
||||
|
name: { |
||||
|
[Sequelize.Op.eq]: null//无name的结果
|
||||
|
} |
||||
|
// del: false
|
||||
|
} |
||||
|
}) |
||||
|
//存放需要去查询clickHouse的id
|
||||
|
let idList = new Set() |
||||
|
if (projectNameList1.length) { |
||||
|
projectNameList1.forEach((item) => { |
||||
|
idList.add(item.pepProjectId) |
||||
|
}) |
||||
|
} |
||||
|
//pepProject名称
|
||||
|
const projectManageName = idList.size ? await clickHouse.projectManage.query(` |
||||
|
SELECT id,project_name FROM t_pim_project |
||||
|
WHERE id IN (${[...idList].join(',')}, -1) |
||||
|
`).toPromise() : []
|
||||
|
// if (projectList.length) {
|
||||
|
// projectList.forEach((item) => {
|
||||
|
// projectManageName
|
||||
|
// })
|
||||
|
// }
|
||||
|
//存的是{id,projectName}
|
||||
|
let project = [] |
||||
|
if (projectNameList1.length && projectManageName.length) { |
||||
|
projectManageName.forEach((item) => { |
||||
|
const pepObj = projectNameList1.find((item1) => { return item1.pepProjectId === item.id }) |
||||
|
project.push({ id: pepObj.id, projectName: item.project_name }) |
||||
|
}) |
||||
|
} |
||||
|
const resAll = project.concat(projectNameList) |
||||
|
let mergedArray = [] |
||||
|
if (resAll.length && projectList) { |
||||
|
mergedArray = projectList.map(obj1 => { |
||||
|
const matchingObj = resAll.find(obj2 => obj2.id === obj1.project_id); |
||||
|
return { id: obj1.project_id, pepProjectId: matchingObj.id, projectName: matchingObj.projectName || matchingObj.dataValues.name, count: obj1.count }; |
||||
|
}); |
||||
|
} |
||||
|
// console.log('ididididid', resAll)
|
||||
|
// console.log('ididididid', project)
|
||||
|
// console.log('ididididid', projectManageName)
|
||||
|
// console.log('ididididid', projectNameList)
|
||||
|
// console.log('ididididid', projectList)
|
||||
|
|
||||
|
ctx.status = 200 |
||||
|
ctx.body = mergedArray |
||||
|
} catch (error) { |
||||
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { |
||||
|
message: '查询维修记录排名失败' |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
async function getMaintenceTotal(ctx) { |
||||
|
const sequelize = ctx.fs.dc.orm |
||||
|
const Sequelize = ctx.fs.dc.ORM; |
||||
|
const { clickHouse } = ctx.app.fs |
||||
|
const models = ctx.fs.dc.models |
||||
|
const { startTime, endTime } = ctx.query |
||||
|
try { |
||||
|
//所有维修记录
|
||||
|
const res = await sequelize.query(` |
||||
|
SELECT emrp.project_id, |
||||
|
count(case when record.status in ('维修中','待维修') then record.id end) incomplete, |
||||
|
count(case when record.status in ('维修完成') then record.id end) completed |
||||
|
FROM equipment_maintenance_record record |
||||
|
RIGHT JOIN equipment_maintenance_record_project emrp |
||||
|
on record.id = emrp.equipment_maintenance_record_id |
||||
|
where report_time BETWEEN :startTime AND :endTime |
||||
|
GROUP BY emrp.project_id |
||||
|
` |
||||
|
, { |
||||
|
replacements: { |
||||
|
startTime: moment(startTime).format('YYYY-MM-DD HH:mm:ss '), |
||||
|
endTime: moment(endTime).format('YYYY-MM-DD HH:mm:ss ') |
||||
|
} |
||||
|
//, type: sequelize.QueryTypes.SELECT
|
||||
|
} |
||||
|
) |
||||
|
//查询equipment_maintenance_record返回的结果[{project_id: 22,status:'' count: 1}]
|
||||
|
let projectList = [] |
||||
|
//存project的id
|
||||
|
let projectIdList = new Set() |
||||
|
// console.log('resssss', res)
|
||||
|
if (res.length > 0) { |
||||
|
res[0].forEach((item) => { |
||||
|
projectList.push({ project_id: item.project_id, 'incomplete': Number(item.incomplete), completed: Number(item.completed) }) |
||||
|
projectIdList.add(item.project_id) |
||||
|
}) |
||||
|
} |
||||
|
// const result = projectList.reduce((acc, curr) => {
|
||||
|
// if (curr.status === '待维修' || curr.status === '维修中') {
|
||||
|
// const existingItem = acc.find(item => item.project_id === curr.project_id && item.status === '异常数');
|
||||
|
// if (existingItem) {
|
||||
|
// existingItem.count += curr.count;
|
||||
|
// } else {
|
||||
|
// acc.push({ project_id: curr.project_id, status: '异常数', count: curr.count });
|
||||
|
// }
|
||||
|
// } else if (curr.status === '维修完成') {
|
||||
|
// const existingItem = acc.find(item => item.project_id === curr.project_id && item.status === '维修数');
|
||||
|
// if (existingItem) {
|
||||
|
// existingItem.count += curr.count;
|
||||
|
// } else {
|
||||
|
// acc.push({ project_id: curr.project_id, status: '维修数', count: curr.count });
|
||||
|
// }
|
||||
|
// }
|
||||
|
// return acc;
|
||||
|
// }, [])
|
||||
|
//console.log('resssssresult', result)
|
||||
|
const projectNameList = await models.ProjectCorrelation.findAll({ |
||||
|
attributes: |
||||
|
['id', 'name'], |
||||
|
where: { |
||||
|
id: { $in: [...projectIdList] }, |
||||
|
name: { |
||||
|
[Sequelize.Op.not]: null//有name的结果
|
||||
|
} |
||||
|
// del: false
|
||||
|
} |
||||
|
}) || [] |
||||
|
//在ProjectCorrelation中查不到名字,去clickHouse中去查
|
||||
|
const projectNameList1 = await models.ProjectCorrelation.findAll({ |
||||
|
attributes: |
||||
|
['id', 'name', 'pepProjectId'], |
||||
|
where: { |
||||
|
id: { $in: [...projectIdList] }, |
||||
|
name: { |
||||
|
[Sequelize.Op.eq]: null//无name的结果
|
||||
|
} |
||||
|
// del: false
|
||||
|
} |
||||
|
}) |
||||
|
//存放需要去查询clickHouse的id
|
||||
|
let idList = new Set() |
||||
|
if (projectNameList1.length) { |
||||
|
projectNameList1.forEach((item) => { |
||||
|
idList.add(item.pepProjectId) |
||||
|
}) |
||||
|
} |
||||
|
//pepProject名称
|
||||
|
const projectManageName = idList.size ? await clickHouse.projectManage.query(` |
||||
|
SELECT id,project_name FROM t_pim_project |
||||
|
WHERE id IN (${[...idList].join(',')}, -1) |
||||
|
`).toPromise() : []
|
||||
|
let project = [] |
||||
|
if (projectNameList1.length && projectManageName.length) { |
||||
|
projectManageName.forEach((item) => { |
||||
|
const pepObj = projectNameList1.find((item1) => { return item1.pepProjectId === item.id }) |
||||
|
project.push({ id: pepObj.id, projectName: item.project_name }) |
||||
|
}) |
||||
|
} |
||||
|
//pg的数据和clcikHouse的数据(名字)合并
|
||||
|
const resAll = project.concat(projectNameList) |
||||
|
let mergedArray = [] |
||||
|
if (resAll.length && projectList) { |
||||
|
mergedArray = projectList.map(obj1 => { |
||||
|
const matchingObj = resAll.find(obj2 => obj2.id === obj1.project_id) |
||||
|
return { |
||||
|
id: obj1.project_id, incomplete: obj1.incomplete, completed: obj1.completed, pepProjectId: matchingObj.id, |
||||
|
projectName: matchingObj.projectName || matchingObj.dataValues.name |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// console.log('ididididid', resAll)
|
||||
|
// console.log('ididididid', project)
|
||||
|
// console.log('ididididid', projectManageName)
|
||||
|
// console.log('ididididid', projectNameList)
|
||||
|
// console.log('ididididid', projectList)
|
||||
|
ctx.status = 200 |
||||
|
ctx.body = mergedArray |
||||
|
} catch (error) { |
||||
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { |
||||
|
message: '查询维修记录统计失败' |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
async function getEquipmentCategory(ctx) { |
||||
|
const { startTime, endTime } = ctx.query |
||||
|
const Sequelize = ctx.fs.dc.ORM |
||||
|
const models = ctx.fs.dc.models |
||||
|
try { |
||||
|
const res = await models.EquipmentMaintenanceRecord.findAll({ |
||||
|
attributes: [ |
||||
|
'equipment_category', |
||||
|
[Sequelize.fn('COUNT', Sequelize.col('equipment_category')), 'count'] |
||||
|
], |
||||
|
where: { reportTime: { $between: [moment(startTime).format('YYYY-MM-DD HH:mm:ss '), moment(endTime).format('YYYY-MM-DD HH:mm:ss ')] } }, |
||||
|
group: ['equipment_category'] |
||||
|
}) |
||||
|
ctx.status = 200 |
||||
|
ctx.body = res |
||||
|
|
||||
|
} catch (error) { |
||||
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { |
||||
|
message: '查询设备类型失败' |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
async function getStatus(ctx) { |
||||
|
const { startTime, endTime } = ctx.query |
||||
|
const Sequelize = ctx.fs.dc.ORM |
||||
|
const models = ctx.fs.dc.models |
||||
|
try { |
||||
|
const res = await models.EquipmentMaintenanceRecord.findAll({ |
||||
|
attributes: [ |
||||
|
'status', |
||||
|
[Sequelize.fn('COUNT', Sequelize.col('status')), 'count'] |
||||
|
], |
||||
|
where: { reportTime: { $between: [moment(startTime).format('YYYY-MM-DD HH:mm:ss '), moment(endTime).format('YYYY-MM-DD HH:mm:ss ')] } }, |
||||
|
group: ['status'] |
||||
|
}) |
||||
|
ctx.status = 200 |
||||
|
ctx.body = res |
||||
|
|
||||
|
} catch (error) { |
||||
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { |
||||
|
message: '查询设备类型失败' |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
module.exports = { |
||||
|
getMaintenceRecordRank, getMaintenceTotal, getEquipmentCategory, getStatus |
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
/* eslint-disable*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
module.exports = dc => { |
||||
|
const DataTypes = dc.ORM; |
||||
|
const sequelize = dc.orm; |
||||
|
const SystemProblem = sequelize.define("systemProblem", { |
||||
|
id: { |
||||
|
type: DataTypes.INTEGER, |
||||
|
allowNull: false, |
||||
|
defaultValue: null, |
||||
|
comment: null, |
||||
|
primaryKey: true, |
||||
|
field: "id", |
||||
|
autoIncrement: true |
||||
|
}, |
||||
|
type: { |
||||
|
type: DataTypes.STRING, |
||||
|
allowNull: true, |
||||
|
defaultValue: null, |
||||
|
comment: "问题类型:数据库异常、es异常、kafka异常、服务器异常、应用异常、其他", |
||||
|
primaryKey: false, |
||||
|
field: "type", |
||||
|
autoIncrement: false |
||||
|
} |
||||
|
}, { |
||||
|
tableName: "system_problem", |
||||
|
comment: "", |
||||
|
indexes: [] |
||||
|
}); |
||||
|
dc.models.SystemProblem = SystemProblem; |
||||
|
return SystemProblem; |
||||
|
}; |
@ -0,0 +1,16 @@ |
|||||
|
'use strict'; |
||||
|
const operationData = require('../../controllers/operationData'); |
||||
|
|
||||
|
module.exports = function (app, router, opts) { |
||||
|
app.fs.api.logAttr['GET/failureTime'] = { content: '获取故障发生时间', visible: true }; |
||||
|
router.get('/failureTime', operationData.getFailureTime) |
||||
|
|
||||
|
app.fs.api.logAttr['GET/systemAvailability'] = { content: '获取系统可用性', visible: true }; |
||||
|
router.get('/systemAvailability', operationData.getSystemAvailability) |
||||
|
|
||||
|
app.fs.api.logAttr['GET/problemType'] = { content: '获取故障类型', visible: true }; |
||||
|
router.get('/problemType', operationData.getProblemType) |
||||
|
|
||||
|
app.fs.api.logAttr['GET/operationsPersonnel'] = { content: '获取运维人员', visible: true }; |
||||
|
router.get('/operationsPersonnel', operationData.getOperationsPersonnel) |
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
'use strict'; |
||||
|
const problemData = require('../../controllers/problemData'); |
||||
|
|
||||
|
module.exports = function (app, router, opts) { |
||||
|
app.fs.api.logAttr['GET/maintenceRecordRank'] = { content: '获取维修记录排名', visible: true }; |
||||
|
router.get('/maintenceRecordRank', problemData.getMaintenceRecordRank) |
||||
|
|
||||
|
app.fs.api.logAttr['GET/maintenceTotal'] = { content: '获取维修次数统计', visible: true }; |
||||
|
router.get('/maintenceTotal', problemData.getMaintenceTotal) |
||||
|
|
||||
|
app.fs.api.logAttr['GET/equipmentCategory'] = { content: '获取设备类型', visible: true }; |
||||
|
router.get('/equipmentCategory', problemData.getEquipmentCategory) |
||||
|
|
||||
|
app.fs.api.logAttr['GET/maintenanceStatus'] = { content: '获取状态', visible: true }; |
||||
|
router.get('/maintenanceStatus', problemData.getStatus) |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
create table public.system_problem( |
||||
|
id serial primary key, |
||||
|
type varchar(20) |
||||
|
); |
||||
|
comment on column public.system_problem.type is '问题类型:数据库异常、es异常、kafka异常、服务器异常、应用异常、其他'; |
||||
|
|
||||
|
insert into system_problem (id, type)values ('es异常'); |
||||
|
insert into system_problem (id, type)values ('数据库异常'); |
||||
|
insert into system_problem (id, type)values ('应用异常'); |
||||
|
insert into system_problem (id, type)values ('kafka异常'); |
||||
|
insert into system_problem (id, type)values ('服务器异常'); |
||||
|
insert into system_problem (id, type)values ('DAC进程异常'); |
||||
|
insert into system_problem (id, type)values ('K8S集群异常'); |
||||
|
insert into system_problem (id, type)values ('redis服务异常'); |
||||
|
insert into system_problem (id, type)values ('其他'); |
@ -1,7 +1,8 @@ |
|||||
'use strict'; |
'use strict'; |
||||
|
|
||||
import * as console from './console' |
import * as console from './console' |
||||
|
import * as operation from './operationData' |
||||
|
import * as maintenceRecord from './maintenceRecordTotal' |
||||
export default { |
export default { |
||||
...console |
...console, ...operation, ...maintenceRecord |
||||
} |
} |
@ -0,0 +1,53 @@ |
|||||
|
'use strict'; |
||||
|
|
||||
|
import { ApiTable, basicAction } from '$utils' |
||||
|
|
||||
|
|
||||
|
export function getMaintenceRecordRank(query) { |
||||
|
return dispatch => basicAction({ |
||||
|
type: 'get', |
||||
|
dispatch: dispatch, |
||||
|
query: query, |
||||
|
actionType: 'GET_MAINTENCE_RECORD_RANK', |
||||
|
url: ApiTable.getMaintenceRecordRank, |
||||
|
msg: { option: '获取维修记录排名' }, |
||||
|
reducer: { name: 'maintenceRecordRank' } |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
|
||||
|
export function getMaintenceTotal(query) { |
||||
|
return dispatch => basicAction({ |
||||
|
type: 'get', |
||||
|
dispatch: dispatch, |
||||
|
query: query, |
||||
|
actionType: 'GET_MAINTENCE_TOTAL', |
||||
|
url: ApiTable.getMaintenceTotal, |
||||
|
msg: { option: '获取维修次数统计' }, |
||||
|
reducer: { name: 'maintenceTotal' } |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function getEquipmentCategory(query) { |
||||
|
return dispatch => basicAction({ |
||||
|
type: 'get', |
||||
|
dispatch: dispatch, |
||||
|
query: query, |
||||
|
actionType: 'GET_EQUIPMENT_CATEGORY', |
||||
|
url: ApiTable.getEquipmentCategory, |
||||
|
msg: { option: '获取设备类型' }, |
||||
|
reducer: { name: 'equipmentCategory' } |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function getStatus(query) { |
||||
|
return dispatch => basicAction({ |
||||
|
type: 'get', |
||||
|
dispatch: dispatch, |
||||
|
query: query, |
||||
|
actionType: 'GET_STATUS', |
||||
|
url: ApiTable.getMaintenanceStatus, |
||||
|
msg: { option: '获取维修状态数据' }, |
||||
|
reducer: { name: 'maintenanceStatus' } |
||||
|
}) |
||||
|
} |
@ -0,0 +1,50 @@ |
|||||
|
'use strict'; |
||||
|
|
||||
|
import { ApiTable, basicAction } from '$utils' |
||||
|
|
||||
|
|
||||
|
export function getFailureTime() { |
||||
|
return dispatch => basicAction({ |
||||
|
type: 'get', |
||||
|
dispatch: dispatch, |
||||
|
actionType: 'GET_FAILURE_TIME', |
||||
|
url: ApiTable.getFailureTime, |
||||
|
msg: { error: '获取故障发生时间分析' }, |
||||
|
reducer: { name: 'failureTime' } |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function getSystemAvailability() { |
||||
|
return dispatch => basicAction({ |
||||
|
type: 'get', |
||||
|
dispatch: dispatch, |
||||
|
actionType: 'GET_SYSTEM_AVAILABILITY', |
||||
|
url: ApiTable.getSystemAvailability, |
||||
|
msg: { error: '获取可用性分析' }, |
||||
|
reducer: { name: 'systemAvailability' } |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
|
||||
|
export function getProblemType() { |
||||
|
return dispatch => basicAction({ |
||||
|
type: 'get', |
||||
|
dispatch: dispatch, |
||||
|
actionType: 'GET_PROBLEM_TYPE', |
||||
|
url: ApiTable.getProblemType, |
||||
|
msg: { error: '获取故障类型' }, |
||||
|
reducer: { name: 'probleType' } |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
|
||||
|
export function getOperationsPersonnel() { |
||||
|
return dispatch => basicAction({ |
||||
|
type: 'get', |
||||
|
dispatch: dispatch, |
||||
|
actionType: 'GET_OPERATIONS_PERSONNEL', |
||||
|
url: ApiTable.getOperationsPersonnel, |
||||
|
msg: { error: '获取故障类型' }, |
||||
|
reducer: { name: 'operationsPersonnel' } |
||||
|
}) |
||||
|
} |
@ -1,48 +1,267 @@ |
|||||
import React, { useEffect } from 'react'; |
import React, { useEffect, useState } from 'react'; |
||||
import { connect } from 'react-redux'; |
import { connect } from 'react-redux'; |
||||
import { Spin, Card } from '@douyinfe/semi-ui'; |
import { Spin, Card, Divider, CardGroup } from '@douyinfe/semi-ui'; |
||||
import '../style.less' |
import '../style.less' |
||||
|
import ReactECharts from 'echarts-for-react'; |
||||
const { Meta } = Card; |
const { Meta } = Card; |
||||
|
|
||||
const Console = (props) => { |
const Console = (props) => { |
||||
const { dispatch, actions, user, loading, socket } = props |
const { dispatch, actions, user, loading, socket, clientHeight } = props |
||||
|
const [left1List, setLeft1List] = useState([])//故障发生时间分析的数据 |
||||
useEffect(() => { |
const [right1List, setRight1List] = useState([])//系统可用性分析的数据 |
||||
// ACTION 示例 |
const [left2List, setLeft2List] = useState([])//故障类型分析的数据 |
||||
// dispatch(actions.example.getMembers(user.orgId)) |
const [right2List, setRight2List] = useState([])//运维人员分析的数据 |
||||
}, []) |
const { analysis } = actions |
||||
|
console.log('actions', actions) |
||||
// websocket 使用测试 |
useEffect(() => { |
||||
// useEffect(() => { |
// ACTION 示例 |
||||
// if (socket) { |
// dispatch(actions.example.getMembers(user.orgId)) |
||||
// socket.on('TEST', function (msg) { |
}, []) |
||||
// console.info(msg); |
useEffect(() => { |
||||
// }); |
//故障发生时间分析接口 |
||||
// return () => { |
dispatch(analysis.getFailureTime()).then((res) => { |
||||
// socket.off("TEST"); |
if (res.success) setLeft1List(res.payload.data) |
||||
// } |
}) |
||||
// } |
//系统可用性分析接口 |
||||
|
dispatch(analysis.getSystemAvailability()).then((res) => { |
||||
// }, [socket]) |
if (res.success) setRight1List(res.payload.data) |
||||
|
}) |
||||
return ( |
//故障类型接口 |
||||
<> |
dispatch(analysis.getProblemType()).then((res) => { |
||||
<div> |
if (res.success) setLeft2List(res.payload.data) |
||||
<img src="/assets/images/install/watting.png" alt="" style={{ width: 'calc(100% + 16px)', position: "relative",top: -12, left: -8, }} /> |
}) |
||||
|
//运维人员 |
||||
|
dispatch(analysis.getOperationsPersonnel()).then((res) => { |
||||
|
if (res.success) setRight2List(res.payload.data) |
||||
|
}) |
||||
|
|
||||
|
}, []) |
||||
|
|
||||
|
|
||||
|
// websocket 使用测试 |
||||
|
// useEffect(() => { |
||||
|
// if (socket) { |
||||
|
// socket.on('TEST', function (msg) { |
||||
|
// console.info(msg); |
||||
|
// }); |
||||
|
// return () => { |
||||
|
// socket.off("TEST"); |
||||
|
// } |
||||
|
// } |
||||
|
|
||||
|
// }, [socket]) |
||||
|
|
||||
|
return ( |
||||
|
<> |
||||
|
{/* <img src="/assets/images/install/watting.png" alt="" style={{ width: 'calc(100% + 16px)', position: "relative",top: -12, left: -8, }} /> */} |
||||
|
<div style={{ background: '#FFFFFF', margin: '8px 12px', padding: '20px 20px 0px 20px', minHeight: clientHeight - 32, display: 'flex', flexDirection: 'column' }}> |
||||
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}> |
||||
|
<div style={{ display: 'flex', alignItems: 'center' }}> |
||||
|
<div style={{ width: 0, height: 20, borderLeft: '3px solid #005ABD', borderTop: '3px solid transparent', borderBottom: '3px solid transparent' }}></div> |
||||
|
<div style={{ fontFamily: "YouSheBiaoTiHei", fontSize: 24, color: '#101531', marginLeft: 8 }}>维修记录统计</div> |
||||
|
<div style={{ marginLeft: 6, fontSize: 12, color: '#969799', fontFamily: "DINExp", }}>MAINTAIN RECORDS STATISTICAL</div> |
||||
|
</div> |
||||
</div> |
</div> |
||||
</> |
<div style={{ margin: '20px 0', flex: 1, display: 'flex', }}> |
||||
) |
<CardGroup type='grid' style={{ width: '100%' }}> |
||||
|
{ |
||||
|
[{ |
||||
|
t: '故障发生时间分析', |
||||
|
echartOption: { |
||||
|
xAxis: { |
||||
|
type: 'category', |
||||
|
data: left1List.map((item) => { |
||||
|
return item.wmonth |
||||
|
}), |
||||
|
axisLabel: { |
||||
|
interval: 0,//x轴强制显示每个 |
||||
|
rotate: 40 |
||||
|
}, |
||||
|
}, |
||||
|
yAxis: { |
||||
|
type: 'value', |
||||
|
name: "单位:次数", |
||||
|
// nameLocation: "end", |
||||
|
// nameGap: 20 |
||||
|
}, |
||||
|
legend: { |
||||
|
orient: 'vertical', |
||||
|
right: '5%', |
||||
|
top: '0%', |
||||
|
data: ['异常数'] |
||||
|
}, |
||||
|
tooltip: {}, |
||||
|
grid: { |
||||
|
top: '10%', |
||||
|
right: '5%', |
||||
|
left: '5%', |
||||
|
bottom: '10%', |
||||
|
containLabel: true |
||||
|
}, |
||||
|
|
||||
|
series: [ |
||||
|
{ |
||||
|
data: left1List.map((item) => { |
||||
|
return Number(item.count) |
||||
|
}), |
||||
|
type: 'bar', |
||||
|
name: '异常数', |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
}, { |
||||
|
t: '系统可用性分析', |
||||
|
echartOption: { |
||||
|
xAxis: { |
||||
|
type: 'category', |
||||
|
data: right1List.map((item) => { |
||||
|
return item.wmonth |
||||
|
}), |
||||
|
axisLabel: { |
||||
|
interval: 0,//x轴强制显示每个 |
||||
|
rotate: 40 |
||||
|
}, |
||||
|
}, |
||||
|
yAxis: { |
||||
|
type: 'value', |
||||
|
name: "单位:%", |
||||
|
// nameLocation: "end", |
||||
|
// nameGap: 20 |
||||
|
}, |
||||
|
legend: {}, |
||||
|
tooltip: {}, |
||||
|
grid: { |
||||
|
//left: '3%', |
||||
|
//right: '3%', |
||||
|
bottom: '1%', |
||||
|
// top: '24%', |
||||
|
containLabel: true |
||||
|
}, |
||||
|
|
||||
|
series: [ |
||||
|
{ |
||||
|
data: right1List.map((item) => { |
||||
|
return Math.round(item.ability * 10000) / 100 |
||||
|
|
||||
|
}), |
||||
|
type: 'line', |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
}, { |
||||
|
t: '故障类型分析', |
||||
|
echartOption: { |
||||
|
xAxis: { |
||||
|
type: 'category', |
||||
|
data: left2List.map((item) => { |
||||
|
return item.type |
||||
|
}), |
||||
|
axisLabel: { |
||||
|
interval: 0,//x轴强制显示每个 |
||||
|
rotate: 40 |
||||
|
}, |
||||
|
}, |
||||
|
yAxis: { |
||||
|
type: 'value', |
||||
|
name: "单位:个", |
||||
|
nameLocation: "end", |
||||
|
nameGap: 20 |
||||
|
}, |
||||
|
legend: {}, |
||||
|
tooltip: {}, |
||||
|
grid: { |
||||
|
left: '3%', |
||||
|
right: '4%', |
||||
|
bottom: '1%', |
||||
|
// top: '24%', |
||||
|
containLabel: true |
||||
|
}, |
||||
|
series: [ |
||||
|
{ |
||||
|
data: left2List.map((item) => { |
||||
|
return Number(item.count) |
||||
|
}), |
||||
|
type: 'bar', |
||||
|
//name: '发起数' |
||||
|
} |
||||
|
|
||||
|
] |
||||
|
}, |
||||
|
}, { |
||||
|
t: '运维人员分析', |
||||
|
echartOption: { |
||||
|
tooltip: {}, |
||||
|
series: [ |
||||
|
{ |
||||
|
// name: right2List?.map((item)=>{ |
||||
|
// return item.name |
||||
|
// }), |
||||
|
type: 'pie', |
||||
|
radius: '80%',//饼图大小 |
||||
|
data: right2List?.map((item) => { |
||||
|
return { value: item.count, name: item.name } |
||||
|
}), |
||||
|
label: { |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
media: [ |
||||
|
{ |
||||
|
query: { minAspectRatio: 1 }, |
||||
|
option: { |
||||
|
series: [ |
||||
|
{ center: ['50%', '50%'] }, |
||||
|
{ center: ['50%', '50%'] } |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
] |
||||
|
}, |
||||
|
},].map((c, idx) => ( |
||||
|
<Card |
||||
|
key={idx} |
||||
|
shadows='hover' |
||||
|
title={c.t} |
||||
|
bordered={false} |
||||
|
headerLine={false} |
||||
|
headerStyle={{ |
||||
|
padding: '12px', |
||||
|
}} |
||||
|
bodyStyle={{ |
||||
|
padding: '12px', |
||||
|
}} |
||||
|
style={{ width: '50%', height: '50%' }} |
||||
|
> |
||||
|
|
||||
|
<ReactECharts |
||||
|
notMerge={true} |
||||
|
lazyUpdate={true} |
||||
|
option={c.echartOption} |
||||
|
/> |
||||
|
</Card> |
||||
|
)) |
||||
|
} |
||||
|
</CardGroup> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
|
||||
|
</> |
||||
|
) |
||||
} |
} |
||||
|
|
||||
function mapStateToProps (state) { |
function mapStateToProps(state) { |
||||
const { auth, global, members, webSocket } = state; |
const { auth, global, members, webSocket } = state; |
||||
return { |
return { |
||||
// loading: members.isRequesting, |
// loading: members.isRequesting, |
||||
// user: auth.user, |
// user: auth.user, |
||||
// actions: global.actions, |
actions: global.actions, |
||||
// members: members.data, |
// members: members.data, |
||||
// socket: webSocket.socket |
// socket: webSocket.socket |
||||
}; |
clientHeight: global.clientHeight |
||||
|
|
||||
|
}; |
||||
} |
} |
||||
|
|
||||
export default connect(mapStateToProps)(Console); |
export default connect(mapStateToProps)(Console); |
||||
|
Loading…
Reference in new issue