wenlele 1 year ago
parent
commit
417e339d78
  1. 94
      api/app/lib/controllers/project/group.js
  2. 76
      api/app/lib/models/alarm_service_type.js
  3. 164
      api/app/lib/models/equipment_maintenance_record.js
  4. 184
      api/app/lib/models/project_correlation.js
  5. 3
      api/app/lib/routes/project/index.js
  6. BIN
      web/client/assets/images/projectGroup/first.png
  7. BIN
      web/client/assets/images/projectGroup/second.png
  8. BIN
      web/client/assets/images/projectGroup/third.png
  9. 14
      web/client/src/sections/projectGroup/actions/group.js
  10. 238
      web/client/src/sections/projectGroup/containers/bigscreen.jsx
  11. 108
      web/client/src/sections/projectGroup/style.less
  12. 1
      web/client/src/utils/webapi.js

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

76
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;
};

164
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;
};

184
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;
};

3
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);
};

BIN
web/client/assets/images/projectGroup/first.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 976 B

BIN
web/client/assets/images/projectGroup/second.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
web/client/assets/images/projectGroup/third.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

14
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 } },
});
}

238
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) {
//2020
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 (
<div className='project-group'>
<Header match={match} history={history} />
@ -120,9 +197,37 @@ const Bigscreen = ({ dispatch, actions, user, match, history, clientHeight, grou
</div>
</Card>
<Card title='修复排名' style={{ width: "calc(50% - 8px)", height: "100%" }}>
<div style={{ height: '100%' }}>
<div style={{ height: '100%', fontFamily: 'SourceHanSansCN-Regular', fontWeight: 400, fontSize: 14, }}>
<div style={{ display: "flex", background: '#F6F9FF', height: 40, alignItems: 'center' }}>
<div style={{ textAlign: 'center', width: '33%' }}>序号</div>
<div style={{ textAlign: 'center', width: '33%' }}>工单名称</div>
<div style={{ textAlign: 'center', width: '33%' }}>修复时长</div>
</div>
<div id="interrupt" style={{ position: 'relative', height: clientHeight * 0.55 - 170 }}>
{[{ index: 1, name: 'wweq', time: 20 },
{ index: 2, name: 'wweq', time: 20 },
{ index: 3, name: 'wweq', time: 20 },
{ index: 4, name: 'wweq', time: 20 },
{ index: 5, name: 'wweq', time: 20 },
{ index: 6, name: 'wweq', time: 20 },
{ index: 7, name: 'wweq', time: 20 },
{ index: 1, name: 'wweq', time: 20 },
{ index: 1, name: 'wweq', time: 20 },
{ index: 1, name: 'wweq', time: 20 }].map((c, index) => {
let title
if (c.offline) {
if (c.offline >= 1440) title = Math.floor(c.offline / 1440) + "天"
if ((c.offline % 1440) >= 60) title = title + Math.floor(c.offline % 1440 / 60) + "时"
if (c.offline % 1440 % 60) title = title + c.offline % 1440 % 60 + "分"
}
return <div style={{ display: "flex", background: index % 2 == 1 ? "#F6F9FF" : '', height: 40, alignItems: 'center' }}>
<div style={{ textAlign: 'center', width: '33%', fontFamily: 'SourceHanSansCN-Regular', color: '#2C66F3', fontWeight: 400 }}>{c.name}</div>
<div style={{ textAlign: 'center', width: '33%' }}>{title}</div>
<div style={{ textAlign: 'center', width: '33%', fontFamily: 'SourceHanSansCN-Regular', color: '#F33B3B', fontWeight: 400 }}>{c.offnum + '/' + c.totnum}</div>
</div>
})}
</div>
</div>
</Card>
</div>
@ -199,11 +304,92 @@ const Bigscreen = ({ dispatch, actions, user, match, history, clientHeight, grou
</div>
<div style={{ width: '100%', height: "calc(55% - 24px)", display: 'flex', marginTop: 24 }}>
<Card title='告警排名TOP20' style={{ width: "calc(50% - 8px)", height: "100%", marginRight: 16, }}>
<div style={{ height: '100%' }}>
</div>
<Card title='告警排名TOP20' style={{
width: "calc(50% - 8px)", height: "100%", marginRight: 16
}} >
{mockData && mockData.length > 0 ? (<div style={{ height: '100%' }}>
<div style={{ display: "flex", justifyContent: 'flex-end' }}>
<div style={{ display: "flex", alignItems: 'center' }}>
<div class='alarmDiv'></div><div class='alarm'>超阈值个数</div>
</div>
<div style={{ display: "flex", alignItems: 'center' }}>
<div class='dealAlarmCountDiv'></div><div class='alarmCount'>手动恢复个数</div>
</div>
</div>
<div id='alarmRank' style={{ height: clientHeight * 0.55 - 150, position: 'relative' }}>
{mockData && mockData[0] ? (<div style={{ display: 'flex', marginTop: 15, alignItems: 'center' }}>
<div class='rankDiv'>
<img src='/assets/images/projectGroup/first.png'></img>
</div>
<div class='structDiv'>{mockData[0]?.name?.length > 5 ? <Tooltip content={mockData[0]?.name}>{mockData[0]?.name.substring(0, 5) + '...'}</Tooltip> : mockData[0]?.name}</div>
<div class='barChartDiv'>
<div style={{ width: '50%', display: 'flex', justifyContent: 'flex-end' }}>
<div class='alarms' style={{ width: (mockData[0].alarmCount / biggest) * 100 || '%', height: '100%' }}></div>
</div>
<div style={{ width: '50%', display: 'flex', }}>
<div class='dealAlarms' style={{ width: (mockData[0].dealAlarmCount / biggest) * 100 || '%', height: '100%' }}></div>
</div>
</div>
</div>) : ''
}
{mockData && mockData[1] ? (<div style={{ display: 'flex', marginTop: 5, alignItems: 'center' }}>
<div class='rankDiv'>
<img src='/assets/images/projectGroup/second.png'></img>
</div>
<div class='structDiv'>{mockData[1]?.name?.length > 5 ? <Tooltip content={mockData[1]?.name}>{mockData[1]?.name.substring(0, 5) + '...'}</Tooltip> : mockData[0]?.name}</div>
<div class='barChartDiv'>
<div style={{ width: '50%', display: 'flex', justifyContent: 'flex-end' }}>
<div class='alarms' style={{ width: (mockData[1].alarmCount / biggest) * 100 || '%', height: '100%' }}></div>
</div>
<div style={{ width: '50%', display: 'flex', }}>
<div class='dealAlarms' style={{ width: (mockData[1].dealAlarmCount / biggest) * 100 || '%', height: '100%' }}></div>
</div>
</div>
</div>) : ''
}
{mockData && mockData[2] ? (<div style={{ display: 'flex', marginTop: 5, alignItems: 'center' }}>
<div class='rankDiv'>
<img src='/assets/images/projectGroup/third.png'></img>
</div>
<div class='structDiv'>{mockData[2]?.name?.length > 5 ? <Tooltip content={mockData[2]?.name}>{mockData[2]?.name.substring(0, 5) + '...'}</Tooltip> : mockData[0]?.name}</div>
<div class='barChartDiv'>
<div style={{ width: '50%', display: 'flex', justifyContent: 'flex-end' }}>
<div class='alarms' style={{ width: (mockData[2].alarmCount / biggest) * 100 || '%', height: '100%' }}></div>
</div>
<div style={{ width: '50%', display: 'flex', }}>
<div class='dealAlarms' style={{ width: (mockData[2].dealAlarmCount / biggest) * 100 || '%', height: '100%' }}></div>
</div>
</div>
</div>) : ''
}
{alarmData && alarmData.length ?
alarmData.map((item, index) => {
return (<div style={{ display: 'flex', marginTop: 5, alignItems: 'center' }}>
<div class='rankDiv'>
<span>{index + 4}</span>
</div>
<div class='structDiv'>{item.name?.length > 5 ? <Tooltip content={item.name}>{item.name.substring(0, 5) + '...'}</Tooltip> : item.name}</div>
<div class='barChartDiv'>
<div style={{ width: '50%', display: 'flex', justifyContent: 'flex-end' }}>
<div class='alarms' style={{ width: (item.alarmCount / biggest) * 100 || '%', height: '100%' }}></div>
</div>
<div style={{ width: '50%', display: 'flex', }}>
<div class='dealAlarms' style={{ width: (item.dealAlarmCount / biggest) * 100 || '%', height: '100%' }}></div>
</div>
</div>
</div>)
}
)
: ''
}
</div>
<div class="scale">
{xData?.map(item => {
return <div >{item}</div>
})}
</div>
</div>) : ''}
</Card>
<Card title='中断排名' style={{ width: "calc(50% - 8px)", height: "100%", }}>
<div style={{ height: '100%', fontFamily: 'SourceHanSansCN-Regular', fontWeight: 400, fontSize: 14, }}>
@ -212,7 +398,7 @@ const Bigscreen = ({ dispatch, actions, user, match, history, clientHeight, grou
<div style={{ textAlign: 'center', width: '33%' }}>中断时长</div>
<div style={{ textAlign: 'center', width: '33%' }}>中断个数</div>
</div>
<div id="interrupt" style={{ position: 'relative', height: clientHeight * 0.55 - 100 }}>
<div id="interrupt" style={{ position: 'relative', height: clientHeight * 0.55 - 170 }}>
{InterruptRank?.map((c, index) => {
let title
if (c.offline) {
@ -221,10 +407,10 @@ const Bigscreen = ({ dispatch, actions, user, match, history, clientHeight, grou
if (c.offline % 1440 % 60) title = title + c.offline % 1440 % 60 + "分"
}
return <div style={{ display: "flex", background: index % 2 == 0 ? "#F6F9FF;" : '', height: 40, alignItems: 'center' }}>
<div style={{ textAlign: 'center', width: '33%' }}>{c.name}</div>
return <div style={{ display: "flex", background: index % 2 == 1 ? "#F6F9FF" : '', height: 40, alignItems: 'center' }}>
<div style={{ textAlign: 'center', width: '33%', fontFamily: 'SourceHanSansCN-Regular', color: '#2C66F3', fontWeight: 400 }}>{c.name}</div>
<div style={{ textAlign: 'center', width: '33%' }}>{title}</div>
<div style={{ textAlign: 'center', width: '33%' }}>{c.offnum + '/' + c.totnum}</div>
<div style={{ textAlign: 'center', width: '33%', fontFamily: 'SourceHanSansCN-Regular', color: '#F33B3B', fontWeight: 400 }}>{c.offnum + '/' + c.totnum}</div>
</div>
})}
</div>

108
web/client/src/sections/projectGroup/style.less

@ -1,3 +1,109 @@
.project-group {
font-family: PangMenZhengDaoBiaoTiTi;
}
}
.alarmDiv{
width: 8px;
height: 8px;
background-image: linear-gradient(180deg, #fbac3200 1%, #FBAC32 100%);
box-shadow: inset 0 2px 0 0 #FBAC32;
}
.alarm{
width: 73px;
height: 12px;
font-family: SourceHanSansCN-Regular;
font-weight: 400;
font-size: 12px;
color: #A0A0A0;
letter-spacing: 0;
line-height: 12px;
// margin-left: 2!important;
}
.dealAlarmCountDiv{
width: 8px;
height: 8px;
background-image: linear-gradient(180deg, #c2d2ff00 1%, #2A62FC 100%);
box-shadow: inset 0 2px 0 0 #2C66F3;
}
.alarmCount{
width: 73px;
height: 12px;
font-family: SourceHanSansCN-Regular;
font-weight: 400;
font-size: 12px;
color: #A0A0A0;
letter-spacing: 0;
text-align: right;
line-height: 12px;
// margin-left: 2 !important;
}
//柱状图外层的div
.barChartDiv{
width: 740px;
height: 12px;
background: #F0F5FF;
border-radius: 2px;
display: flex;
}
.structDiv{
width: 100px;
height: 14px;
font-family: SourceHanSansCN-Regular;
font-weight: 400;
font-size: 14px;
color: #3E434E;
letter-spacing: 0;
line-height: 14px;
text-align: center;
}
.rankDiv{
width: 34.48px;
height: 17.67px;
text-align: center;
span{
width: 13px;
height: 16px;
font-family: D-DIN-Italic;
font-weight: Italic;
font-size: 16px;
color: #7C8DB6;
letter-spacing: 0;
}
}
.rankBackDiv{
// width: 34.48px;
// height: 9px;
// background-image: linear-gradient(270deg, #f957571f 0%, #f32c2c57 93%);
// margin-bottom: 0;
}
.alarms{
width: 282px;
height: 10px;
background-image: linear-gradient(116deg, #2c66f329 8%, #2C66F3 100%);
box-shadow: inset 2px 0 0 0 #2C66F3;
}
.dealAlarms{
width: 108px;
height: 10px;
background-image: linear-gradient(270deg, #fbac3229 1%, #FBAC32 100%);
box-shadow: inset -2px 0 0 0 #FBAC32;
}
.scale{
display: flex;
width: 740px;
height: 18px;
font-family: DIN-Regular;
font-weight: 400;
font-size: 12px;
color: #5A6685;
letter-spacing: 0;
text-align: center;
justify-content: space-between;
margin-left: 134.48px;
}

1
web/client/src/utils/webapi.js

@ -40,6 +40,7 @@ export const ApiTable = {
projectGroup: 'project/group',
groupStatistic: 'project/group/statistic',
groupStatisticOnline: 'project/group/statistic/online',
groupStatisticAlarm:'project/group/statistic/alarm',
//告警
getProjectPoms: 'project/poms', //获取已绑定项目

Loading…
Cancel
Save