Browse Source

feat:3.9版本代码

dev
zhaobing’ 1 year ago
parent
commit
8831933303
  1. 12
      api/app/lib/controllers/alarm/data.js
  2. 24
      api/app/lib/controllers/dataCacl/index.js
  3. 1
      api/app/lib/controllers/monitor/index.js
  4. 181
      api/app/lib/controllers/organization/index.js
  5. 193
      api/app/lib/controllers/project/group.js
  6. 15
      api/app/lib/controllers/project/index.js
  7. 11
      api/app/lib/models/report_automatic.js
  8. 2
      api/app/lib/routes/project/index.js
  9. 30
      api/app/lib/schedule/alarms_push.js
  10. 4
      api/app/lib/schedule/workOrder.js
  11. 5
      script/3.9/schema/1.update_report_automatic.sql
  12. 4
      web/client/src/layout/components/header/index.jsx
  13. 34
      web/client/src/sections/control/containers/control.jsx
  14. 9
      web/client/src/sections/install/containers/AbnRecognize.jsx
  15. 57
      web/client/src/sections/install/containers/burr.jsx
  16. 43
      web/client/src/sections/install/containers/cacl.jsx
  17. 57
      web/client/src/sections/install/containers/interrupt.jsx
  18. 38
      web/client/src/sections/install/containers/roles.jsx
  19. 11
      web/client/src/sections/install/containers/system.jsx
  20. 57
      web/client/src/sections/install/containers/trend.jsx
  21. 2
      web/client/src/sections/install/style.less
  22. 2
      web/client/src/sections/problem/actions/problem.jsx
  23. 29
      web/client/src/sections/problem/components/tableData.jsx
  24. 2
      web/client/src/sections/problem/containers/dataAlarm.jsx
  25. 16
      web/client/src/sections/projectGroup/actions/group.js
  26. 368
      web/client/src/sections/projectGroup/containers/bigscreen.jsx
  27. 40
      web/client/src/sections/projectGroup/style.less
  28. 16
      web/client/src/sections/service/components/automatic-Modal.jsx
  29. 4
      web/client/src/sections/workOrder/containers/initiated.jsx
  30. 2
      web/client/src/utils/webapi.js

12
api/app/lib/controllers/alarm/data.js

@ -46,7 +46,7 @@ async function list (ctx) {
const { utils: { judgeSuper, anxinStrucIdRange } } = ctx.app.fs
const { database: anxinyun } = clickHouse.anxinyun.opts.config
const { pepProjectId, keywordTarget, keyword, groupId, groupUnitId, sustainTimeStart, sustainTimeEnd, limit, page, state, onlineState, toExport } = ctx.query
const { timestamps,pepProjectId, keywordTarget, keyword, groupId, groupUnitId, sustainTimeStart, sustainTimeEnd, limit, page, state, onlineState, toExport } = ctx.query
let anxinStruc = await anxinStrucIdRange({
ctx, pepProjectId, keywordTarget, keyword
@ -100,10 +100,10 @@ async function list (ctx) {
let alarmQueryOptionStr = `
FROM
alarms
LEFT JOIN (
SELECT DeviceId, any(Status) AS Status,max(Time) FROM DeviceStatus GROUP BY DeviceId
) AS DeviceStatus
ON DeviceStatus.DeviceId = alarms.SourceId
${timestamps?`LEFT JOIN (
SELECT DeviceId, any(Status) AS Status,max(Time) FROM DeviceStatus GROUP BY DeviceId
) AS DeviceStatus
ON DeviceStatus.DeviceId = alarms.SourceId`:''}
LEFT JOIN ${anxinyun}.t_structure
ON ${anxinyun}.t_structure.id = alarms.StructureId
LEFT JOIN ${anxinyun}.t_alarm_code
@ -121,7 +121,7 @@ async function list (ctx) {
SourceTypeId,
AlarmAdviceProblem, AlarmGroup, AlarmGroupUnit, AlarmAdviceProblem,
alarms.StructureId AS StructureId,
${`DeviceStatus.Status AS DeviceStatus,`}
${timestamps?`DeviceStatus.Status AS DeviceStatus,`:''}
${anxinyun}.t_structure.name AS StructureName,
${anxinyun}.t_structure.longitude AS StructureLongitude,
${anxinyun}.t_structure.latitude AS StructureLatitude,

24
api/app/lib/controllers/dataCacl/index.js

@ -26,16 +26,28 @@ async function findAbnMethods(ctx, next) {
}
//获取异常参数配置
async function findAbnParamList(ctx) {
const { factorId } = ctx.query
const { factorId,limit,page,keywords,type } = ctx.query
const id=factorId.split(',')
let rslt = null;
let error = { name: 'FindError', message: '异常参数配置获取失败' };
let abnParamList
try {
let findOption= {where:{ factorId:{$in:id},abnTypeId:Number(type) }}
if (limit) {
findOption.limit = limit
}
if (page && limit) {
findOption.offset = page * limit
}
if(keywords){
findOption.where.$or = [
{ sensorLocationDescription: { $like: `%${keywords}%` } },
{ factor: { $like: `%${keywords}%` } }
]
}
const models = ctx.fs.dc.models;
let abnParamList = await models.AbnReportParams.findAll({
where: { factorId:{$in:id} }
})
rslt = abnParamList.map(s => ({
abnParamList= await models.AbnReportParams.findAndCountAll(findOption)
rslt = abnParamList.rows.map(s => ({
key: s.id,
id: s.id,
sensorId: s.sensorId,
@ -56,7 +68,7 @@ async function findAbnParamList(ctx) {
ctx.body = error;
} else {
ctx.status = 200;
ctx.body = rslt;
ctx.body ={count:abnParamList.count,rows:rslt}
}
}

1
api/app/lib/controllers/monitor/index.js

@ -284,7 +284,6 @@ async function exportMaterialEnterList(ctx, data, columns) {
// exportData.push(item)
// }
const fileName = `${siteName}` + '.xls'
console.log('x11111111',data,fileName,header)
const filePath = await simpleExcelDown({ data: data, header, fileName: fileName, needIndexCell: false })
const fileData = fs.readFileSync(filePath)
ctx.status = 200

181
api/app/lib/controllers/organization/index.js

@ -1,7 +1,7 @@
'use strict';
const moment = require('moment')
async function allDeps (ctx) {
async function allDeps(ctx) {
try {
const models = ctx.fs.dc.models;
const { redis } = ctx.app
@ -22,7 +22,7 @@ async function allDeps (ctx) {
}
}
async function allUsers (ctx) {
async function allUsers(ctx) {
try {
const { models } = ctx.fs.dc;
const { clickHouse } = ctx.app.fs
@ -43,7 +43,7 @@ async function allUsers (ctx) {
}
}
async function editUser (ctx) {
async function editUser(ctx) {
try {
const models = ctx.fs.dc.models;
const { pomsUserId, pepUserId, role = [], correlationProject = [] } = ctx.request.body
@ -113,7 +113,7 @@ async function editUser (ctx) {
}
}
async function putUser (ctx) {
async function putUser(ctx) {
try {
const models = ctx.fs.dc.models;
const { pomsUserId } = ctx.params
@ -153,7 +153,7 @@ async function putUser (ctx) {
}
}
async function delAdmin (ctx) {
async function delAdmin(ctx) {
try {
const models = ctx.fs.dc.models;
const { pomsUserId } = ctx.params
@ -189,13 +189,13 @@ async function delAdmin (ctx) {
}
}
async function user (ctx) {
async function user(ctx) {
try {
const models = ctx.fs.dc.models;
const { clickHouse } = ctx.app.fs
const sequelize = ctx.fs.dc.orm;
const { role, limit, page, } = ctx.query
const { role, limit, page, keywords } = ctx.query
const excludeField = ['lastInTime', 'inTimes', 'onlineDuration', 'lastInAddress', 'deleted', 'updateTime']
@ -222,14 +222,107 @@ async function user (ctx) {
findOption.where.role = { $contains: [role] }
}
if (limit) {
findOption.limit = limit
findOption.limit = limit
}
if (page && limit) {
findOption.offset = page * limit
findOption.offset = page * limit
}
if(keywords){
let userPepRes =await clickHouse.pepEmis.query(`
SELECT DISTINCT
user.id AS id, "user"."name" AS name, department.name AS depName, department.id AS depId
FROM department_user
LEFT JOIN user
ON department_user.user=user.id
LEFT JOIN department
ON department.id=department_user.department
WHERE
department.delete='0'
AND "user"."name" LIKE '%${keywords}%'`||[]
).toPromise() ||[]
let userId=new Set()
userPepRes.forEach(item=>{
userId.add(item.id)
})
findOption.where.pepUserId =Array.from(userId)
let userRes = await models.User.findAndCountAll(findOption)
const adminRes = await models.User.findAll({
where: {
role: { $contains: ['admin'] }
},
attributes: {
exclude: excludeField,
},
order: [['updateTime', 'DESC']]
})
let pomsProjectIds = new Set()
for (let u of userRes.rows.concat(adminRes)) {
for (let pid of u.correlationProject) {
pomsProjectIds.add(pid)
}
}
// 获取响应的绑定的 项企项目的 id
let pomsProjectRes = await models.ProjectCorrelation.findAll({
where: {
id: { $in: [...pomsProjectIds] },
// del: false
}
})
let pepPojectIds = new Set()
for (let p of pomsProjectRes) {
if (p.pepProjectId) {
pepPojectIds.add(p.pepProjectId)
}
}
// 查对应的项企项目信息
let pepProjectRes = pepPojectIds.size ?
await clickHouse.projectManage.query(`
SELECT id, project_name, isdelete FROM t_pim_project WHERE id IN (${[...pepPojectIds]},-1)
`).toPromise() :
[]
for (let u of userRes.rows.concat(adminRes)) {
// 用户信息
const corUsers = userPepRes
u.dataValues.name = corUsers.length ? corUsers[0].name : ''
u.dataValues.departments = corUsers.length ? corUsers.map(cu => {
return {
name: cu.depName,
id: cu.depId
}
}) : []
// pep项目信息
u.dataValues.correlationProject = u.dataValues.correlationProject.map(cpid => {
let returnData = {
id: cpid,
}
const corPomsProject = pomsProjectRes.find(ppr => ppr.id == cpid)
if (corPomsProject) {
returnData.name = corPomsProject.name
returnData.del = corPomsProject.del
if (corPomsProject.pepProjectId) {
returnData.pepProjectId = corPomsProject.pepProjectId
const corPepProject = pepProjectRes.find(ppr => ppr.id == corPomsProject.pepProjectId)
if (corPepProject) {
returnData.pepProjectName = corPepProject.project_name
returnData.pepIsdelete = corPepProject.isdelete
}
}
}
return returnData
})
}
ctx.status = 200
ctx.body = {
admin: adminRes,
users: userRes
}
const userRes = await models.User.findAndCountAll(findOption)
}
let userRes = await models.User.findAndCountAll(findOption)
const adminRes = await models.User.findAll({
where: {
role: { $contains: ['admin'] }
@ -260,7 +353,8 @@ async function user (ctx) {
ON department.id=department_user.department
WHERE
user.id IN (${[...userIds].join(',')},-1)
AND department.delete='0'`
AND department.delete='0'
`
).toPromise() :
[]
@ -285,38 +379,45 @@ async function user (ctx) {
`).toPromise() :
[]
const data = userRes.rows.filter(item => {
return userPepRes.some(f => f.id == item.dataValues.pepUserId)
})
userRes.rows = data
userRes.count = data.length
// 遍历用户并将查到的信息拼合
for (let u of userRes.rows.concat(adminRes)) {
// 用户信息
const corUsers = userPepRes.filter(up => up.id == u.pepUserId)
u.dataValues.name = corUsers.length ? corUsers[0].name : ''
u.dataValues.departments = corUsers.length ? corUsers.map(cu => {
return {
name: cu.depName,
id: cu.depId
}
}) : []
// pep项目信息
u.dataValues.correlationProject = u.dataValues.correlationProject.map(cpid => {
let returnData = {
id: cpid,
}
const corPomsProject = pomsProjectRes.find(ppr => ppr.id == cpid)
if (corPomsProject) {
returnData.name = corPomsProject.name
returnData.del = corPomsProject.del
if (corPomsProject.pepProjectId) {
returnData.pepProjectId = corPomsProject.pepProjectId
const corPepProject = pepProjectRes.find(ppr => ppr.id == corPomsProject.pepProjectId)
if (corPepProject) {
returnData.pepProjectName = corPepProject.project_name
returnData.pepIsdelete = corPepProject.isdelete
for (let u of userRes.rows.concat(adminRes)) {
// 用户信息
const corUsers = userPepRes.filter(up => up.id == u.pepUserId)
u.dataValues.name = corUsers.length ? corUsers[0].name : ''
u.dataValues.departments = corUsers.length ? corUsers.map(cu => {
return {
name: cu.depName,
id: cu.depId
}
}) : []
// pep项目信息
u.dataValues.correlationProject = u.dataValues.correlationProject.map(cpid => {
let returnData = {
id: cpid,
}
const corPomsProject = pomsProjectRes.find(ppr => ppr.id == cpid)
if (corPomsProject) {
returnData.name = corPomsProject.name
returnData.del = corPomsProject.del
if (corPomsProject.pepProjectId) {
returnData.pepProjectId = corPomsProject.pepProjectId
const corPepProject = pepProjectRes.find(ppr => ppr.id == corPomsProject.pepProjectId)
if (corPepProject) {
returnData.pepProjectName = corPepProject.project_name
returnData.pepIsdelete = corPepProject.isdelete
}
}
}
}
return returnData
})
}
return returnData
})
}
ctx.status = 200
ctx.body = {

193
api/app/lib/controllers/project/group.js

@ -435,114 +435,54 @@ async function groupStatisticOnline (ctx) {
// 查在线率
const strucOnlineClient = ctx.app.fs.esclient.strucOnline
// let arr = [1,2,3,4,5,6,7]
// let onlineRes={
// hits: {
// hits: []
// }
// }
// if(strucIdArr.length){
// for(let i = 0;i<arr.length;i++){
// const res=await strucOnlineClient.search({
// index: strucOnlineClient.config.index,
// type: strucOnlineClient.config.type,
// body: {
// "query": {
// "bool": {
// "filter": [
// {
// "range": {
// "collect_time": {
// "gte": `${moment().subtract(24*(i+1)+8, 'hours').format('YYYY-MM-DDTHH:mm:ss.SSS')}Z`,
// // "gte": "2023-08-24T08:00:00.000Z",
// "lt":`${moment().subtract(8+24*i, 'hours').format('YYYY-MM-DDTHH:mm:ss.SSS')}Z`
// }
// }
// },
// {
// "terms": {
// "structure": strucIdArr,
// // "structure": [1, 2, 3]
// }
// }
// ]
// }
// },
// "sort": [
// {
// "collect_time": {
// "order": "asc"
// }
// }
// ],
// "size": 10000
// }
// })
// onlineRes.hits.hits=[...onlineRes.hits.hits,...res.hits.hits]
// }
// }
// 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 || {}
// }
// 查在线率
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",
let arr = [1,2,3,4,5,6,7]
let onlineRes={
hits: {
hits: []
}
}
if(strucIdArr.length){
for(let i = 0;i<arr.length;i++){
const res=await strucOnlineClient.search({
index: strucOnlineClient.config.index,
type: strucOnlineClient.config.type,
body: {
"query": {
"bool": {
"filter": [
{
"range": {
"collect_time": {
"gte": `${moment().subtract(24*(i+1)+8, 'hours').format('YYYY-MM-DDTHH:mm:ss.SSS')}Z`,
// "gte": "2023-08-24T08:00:00.000Z",
"lt":`${moment().subtract(8+24*i, 'hours').format('YYYY-MM-DDTHH:mm:ss.SSS')}Z`
}
}
}
},
{
"terms": {
"structure": strucIdArr,
},
{
"terms": {
"structure": strucIdArr,
// "structure": [1, 2, 3]
}
}
]
}
},
"sort": [
{
"collect_time": {
"order": "asc"
}
]
}
},
"sort": [
{
"collect_time": {
"order": "asc"
}
}
],
"size": 10000
}
})
: {
hits: {
hits: []
}
}
],
"size": 10000
}
})
onlineRes.hits.hits=[...onlineRes.hits.hits,...res.hits.hits]
}
}
for (let struc of strucRes) {
let curOnline =
@ -821,6 +761,50 @@ async function getWorkOrdersRepairRank (ctx) {
}
}
async function getworkOrdersAvgTimes (ctx) {
try {
// 计算一个月前的日期
const oneMonthAgo = moment().subtract(1, 'months').toDate()
const { models } = ctx.fs.dc
const sequelize = ctx.fs.dc.ORM
const { projectIds } = ctx.query
if (projectIds && projectIds.length) {
const res= await models.FormDataTable.findAll({
where: {
projectId: {
$in: projectIds.split(',').map(Number)
},
startTime: {
$gte: oneMonthAgo,
}
},
attributes: [
'project_id',
[
sequelize.literal('AVG(EXTRACT(EPOCH FROM "end_time" + INTERVAL \'8 hours\' - "start_time"))'),
'avgTime',
],
],
group: ['project_id'],
order: [[sequelize.literal('AVG(EXTRACT(EPOCH FROM "end_time" + INTERVAL \'8 hours\' - "start_time"))'), 'DESC']],
limit: 5,
})
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,
@ -832,5 +816,6 @@ module.exports = {
groupStatisticAlarm,
groupProject,
getProjectWorkOrders,
getWorkOrdersRepairRank
getWorkOrdersRepairRank,
getworkOrdersAvgTimes
};

15
api/app/lib/controllers/project/index.js

@ -24,7 +24,6 @@ async function pomsProject (ctx) {
const { clickHouse } = ctx.app.fs
const { userId, pepUserId, userInfo, pepUserInfo } = ctx.fs.api
const { limit, page, global, pepId, keyword } = ctx.query
let findOption = {
where: {
del: false,
@ -87,7 +86,6 @@ async function pomsProject (ctx) {
}
const proRes = await models.ProjectCorrelation.findAndCountAll(findOption)
let pepProjectIds = new Set()
let anxinProjectIds = new Set()
let createUsers = new Set()
@ -104,6 +102,17 @@ async function pomsProject (ctx) {
}
}
}
let pepmCustomerLevelRes = pepProjectIds.size ? 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 (${[...pepProjectIds].join(',')},-1)
`
).toPromise() : []
const pomsUser = await models.User.findAll({
where: {
id: { $in: [...createUsers] }
@ -124,6 +133,7 @@ async function pomsProject (ctx) {
).toPromise() :
[]
const pepProjectRes = pepProjectIds.size ?
await clickHouse.projectManage.query(
`
@ -161,6 +171,7 @@ async function pomsProject (ctx) {
p.dataValues.anxinProject = nextAnxinProject
p.dataValues.pepUserName = pepUserName
delete p.dataValues.anxinProjectId
p.dataValues.customerLevel=(pepmCustomerLevelRes.find(pp => pp.projectId == p.dataValues.pepProjectId)||{name:'--'}).name
}
ctx.status = 200;
ctx.body = proRes

11
api/app/lib/models/report_automatic.js

@ -53,7 +53,7 @@ module.exports = dc => {
},
reportPicPath: {
type: DataTypes.STRING,
allowNull: false,
allowNull: true,
defaultValue: null,
comment: "",
primaryKey: false,
@ -141,6 +141,15 @@ module.exports = dc => {
field: "factors",
autoIncrement: false
},
overview: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "",
primaryKey: false,
field: "overview",
autoIncrement: false
},
}, {
tableName: "report_automatic",
comment: "",

2
api/app/lib/routes/project/index.js

@ -62,4 +62,6 @@ module.exports = function (app, router, opts) {
app.fs.api.logAttr['GET/project/workOrders/repairRank'] = { content: '获取工单修复信息', visible: true };
router.get('project/workOrders/repairRank', projectGroup.getWorkOrdersRepairRank);
app.fs.api.logAttr['GET/project/workOrders/avgTime'] = { content: '获取工单平均修复时长', visible: true };
router.get('project/workOrders/avgTime', projectGroup.getworkOrdersAvgTimes);
};

30
api/app/lib/schedule/alarms_push.js

@ -1503,16 +1503,38 @@ module.exports = function (app, opts) {
let alarmHtmlTitle = packageTableTitle(alarmTitleArr)
let accumulate = 0
if (type == 1) {
console.log('xx111112222',alarmData)
//调整结构物位置
alarmData.map((h, hi) => {
if (h.projects && h.projects.length) {
h.projects.map((x, xi) => {
let problem = 0;
let count = 0;
if (x.factor && x.factor.length) {
x.factor.map((f, fi) => {
problem += f.problem;
count += f.devicesLength;
});
// 如果 problem 等于 count,将该结构物移到前面
if (problem === count) {
h.projects.splice(xi, 1); // 先移除当前元素
h.projects.unshift(x); // 然后将该结构物移到数组前面
}
}
});
}
})
alarmData.map((h, hi) => {
accumulate += h.rowspan || 0
if (h.projects && h.projects.length) {
h.projects.map((x, xi) => {
let flag
//用于设备全部中断做特殊标记
let problem=0
let count=0
let showOne1 = (xi == 0) ? true : false
if (x.factor && x.factor.length) {
x.factor.map((f, fi) => {
problem+=f.problem
count+=f.devicesLength
let showOne2 = (fi == 0) ? true : false
if (f.devices && f.devices.length) {
f.devices.map((c, ci) => {
@ -1537,7 +1559,7 @@ module.exports = function (app, opts) {
break;
case 'Structure':
if (showOne2 && showOne3 && showOne4) {
tableData += `<th rowspan=${x.rowspan}>${x['name'] || ''}</th>`
tableData +=problem==count?`<th style="color: red;" rowspan=${x.rowspan}>${x['name'](测点数据全部中断) || ''}</th>`: `<th rowspan=${x.rowspan}>${x['name'] || ''}</th>`
}
break;
case 'factor':

4
api/app/lib/schedule/workOrder.js

@ -64,17 +64,15 @@ module.exports = function (app, opts,ctx) {
: ''}`
).toPromise()
const procinstIds = [...new Set(formRes.map(e => e.procinstId))];
console.log('formRes1',procinstIds)
// 获取流程实例变量
if(formRes && formRes.length > 0){
let procinstsVariables = await request.post(encodeURI(opts.camundarest.host+'/'+opts.camundarest.root+`/engine-rest/history/variable-instance`))
.auth(username, password)
.set('Content-Type', 'application/json')
.send({processInstanceIdIn: procinstIds})
console.log('formRes2',procinstsVariables)
if(procinstsVariables.body&&procinstsVariables.body.length){
for (let f of formRes) {
const parseData = parseProcessData({
const parseData =f.formSchema&& parseProcessData({
formSchema: JSON.parse(f.formSchema),
formData: JSON.parse(f.formData)
})

5
script/3.9/schema/1.update_report_automatic.sql

@ -0,0 +1,5 @@
alter table report_automatic
add overview varchar(300);
alter table report_automatic
alter column reportpic_path drop not null;

4
web/client/src/layout/components/header/index.jsx

@ -13,7 +13,7 @@ import layout from '../../containers/layout';
let newScrollbar;
const Header = (props) => {
const { dispatch, history, user, actions, socket, headerItems, tochange, projectGroup } = props;
const { install, projectGroup: projectGroupAC, layout } = actions
const { install, projectGroup: projectGroupAC, layout,problem } = actions
const [pomsList, setPomsList] = useState([])
const [pomsName, setPomsName] = useState('全局')
const [pepProjectId, setPepProjectId] = useState()
@ -63,7 +63,7 @@ const Header = (props) => {
setCount(res.payload.data?.count)
}
})
dispatch(problem.getAlarmDataGroup())
}
}, [])

34
web/client/src/sections/control/containers/control.jsx

@ -202,7 +202,8 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
useEffect(() => {
//
let data = ['overall', 'workbench', 'statistical', 'analyse', 'dynamic']
let data = ['overall_new', 'workbench', 'statistical', 'analyse', 'dynamic']
localStorage.getItem('overall')?localStorage.removeItem('overall'):""
data.map(v => {
localStorage.getItem(v) == null
? localStorage.setItem(v, JSON.stringify(show[v]))
@ -226,14 +227,13 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
}, [pepProjectId])
useEffect(() => {
if (exhibition.current?.overall?.find(v => v.key == 'tool')) {
if (exhibition.current?.overall_new?.find(v => v.key == 'tool')) {
consoleToollink()
}
}, [exhibition.current])
useEffect(() => {
async function concentration2 () {
if (exhibition.current?.overall?.find(v => v.key == 'analyse')) {
if (exhibition.current?.overall_new?.find(v => v.key == 'analyse')) {
// BI-
await dispatch(control.getDataAlarmsAggDay({ pepProjectId: pepProjectId })).then(res => {
if (res.success) setDataBI(res.payload.data)
@ -329,7 +329,7 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
}
})
}
if (exhibition.current?.overall?.find(v => v.key == 'statistical')) {
if (exhibition.current?.overall_new?.find(v => v.key == 'statistical')) {
concentration4()
}
}, [projectId, exhibition.current])
@ -391,7 +391,7 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
}
}
if (exhibition.current?.overall?.find(v => v.key == 'dynamic')) {
if (exhibition.current?.overall_new?.find(v => v.key == 'dynamic')) {
concentration3()
}
@ -580,14 +580,14 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
let Select = {
overall: ['workbench', 'statistical', 'dataAnalyse', 'analyse', 'dynamic', 'tool'],
overall_new: ['workbench', 'statistical', 'dataAnalyse', 'analyse', 'dynamic', 'tool'],
workbench: ['project', 'data', 'app', 'device'],
statistical: ['milestone', 'personnel', 'DeviceAccess', 'web', 'problem'],
analyse: ['dataInterrupt', 'dataAbnormal', 'policyHit', 'videoException', 'appAbnormal', 'deviceAbnormal', 'problemAnalysis'],
dynamic: ['discovery', 'notice', 'handle', 'confirm'],
}
let show = {
overall: ['workbench', 'dataAnalyse'],
overall_new: ['workbench', 'dataAnalyse'],
workbench: ['project', 'data', 'app', 'device'],
statistical: ['milestone', 'personnel', 'web', 'problem'],
analyse: ['dataInterrupt', 'dataAbnormal', 'policyHit', 'videoException', 'appAbnormal', 'deviceAbnormal', 'problemAnalysis'],
@ -662,8 +662,8 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
<div style={{ width: 25, height: 25, cursor: "pointer" }}>
<img src="/assets/images/console/icon_all.png" alt="" style={{ width: '100%', height: '100%' }} onClick={() => {
setSetup(true)
setTableType('overall')
attribute('overall')
setTableType('overall_new')
attribute('overall_new')
setSetData(6)
}} />
</div>
@ -672,7 +672,7 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
<div style={{ display: 'flex', width: '100%' }}>
{/* 左边 */}
<div style={{
width: exhibition.current?.overall?.find(v => v.key == 'dynamic' || v.key == 'tool') ?
width: exhibition.current?.overall_new?.find(v => v.key == 'dynamic' || v.key == 'tool') ?
'calc(100% - 434px)' : "calc(100%)"
}}>
{/* 工作台和统计概览 */}
@ -750,7 +750,7 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
{/* 统计概览 */}
{
exhibition.current?.overall?.find(v => v.key == 'statistical') ? <>
exhibition.current?.overall_new?.find(v => v.key == 'statistical') ? <>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginTop: 25 }}>
<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>
@ -994,12 +994,12 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
{/* 图表 */}
{
exhibition.current?.overall?.find(v => v.key == 'dataAnalyse') &&
exhibition.current?.overall_new?.find(v => v.key == 'dataAnalyse') &&
<AlarmChart />
}
{/* BI分析模块 */}
{exhibition.current?.overall?.find(v => v.key == 'analyse') ?
{exhibition.current?.overall_new?.find(v => v.key == 'analyse') ?
<div style={{ background: '#FFFFFF', boxShadow: '0px 0px 12px 2px rgba(220,222,224,0.2)', borderRadius: 2, paddingTop: 20, paddingLeft: 24, marginTop: 22 }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', alignItems: 'center' }}>
@ -1193,10 +1193,10 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
</div>
{/* 右边 */}
{exhibition.current?.overall?.find(v => v.key == 'dynamic' || v.key == 'tool')
{exhibition.current?.overall_new?.find(v => v.key == 'dynamic' || v.key == 'tool')
&& <div style={{ width: 415, marginLeft: 20 }}>
{/* 最新动态 */}
{exhibition.current?.overall?.find(v => v.key == 'dynamic')
{exhibition.current?.overall_new?.find(v => v.key == 'dynamic')
&& <div style={{ width: 415, background: '#FFFFFF', marginBottom: 20, boxShadow: '0px 0px 12px 2px rgba(220,222,224,0.2)', borderRadius: 2, paddingTop: 20, paddingLeft: 21, height: 639, }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', alignItems: 'center' }}>
@ -1260,7 +1260,7 @@ const Control = ({ dispatch, actions, user, history, loading, socket, pepProject
</div>
</div>}
{/* 我常用的工具 */}
{exhibition.current?.overall?.find(v => v.key == 'tool') ?
{exhibition.current?.overall_new?.find(v => v.key == 'tool') ?
<div style={{ background: '#FFFFFF', boxShadow: '0px 0px 12px 2px rgba(220,222,224,0.2)', borderRadius: 2, padding: 20 }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', alignItems: 'center' }}>

9
web/client/src/sections/install/containers/AbnRecognize.jsx

@ -10,7 +10,7 @@ import Interrupt from './interrupt'
const AbnRecognize = (props) => {
// const {abnCompareData}=props
const {calcMethod,abnCompareData,factorId,structId,strunctChange,itName,sensorId,project}=props
const {calcMethod,abnCompareData,factorId,structId,strunctChange,itName,sensorId,project,limits,query,changeQuery,limitChange}=props
// let originalData = [''], calcArray = [], key, itemName, start, end;
// let stationsData = [];
// if (abnCompareData &&calcMethod == abnCompareData.method) {
@ -56,12 +56,11 @@ const AbnRecognize = (props) => {
// }
// }
const renderContent=()=> {
const SubContent = {
'interrupt': <Interrupt project={project} sensorId={sensorId} structId={structId} factorId={factorId} />,
'burr': <Burr project={project} sensorId={sensorId} structId={structId} factorId={factorId} itName={itName} />,
'trend': <Trend project={project} sensorId={sensorId} structId={structId} factorId={factorId} itName={itName}/>,
'interrupt': <Interrupt limitChange={limitChange} query={query} changeQuery={changeQuery} limits={limits} project={project} sensorId={sensorId} structId={structId} factorId={factorId} />,
'burr': <Burr limitChange={limitChange} query={query} changeQuery={changeQuery} limits={limits} project={project} sensorId={sensorId} structId={structId} factorId={factorId} itName={itName} />,
'trend': <Trend limitChange={limitChange} query={query} changeQuery={changeQuery} limits={limits} project={project} sensorId={sensorId} structId={structId} factorId={factorId} itName={itName}/>,
};
return SubContent[calcMethod];
}

57
web/client/src/sections/install/containers/burr.jsx

@ -2,12 +2,12 @@
import React, { useState,useRef } from 'react';
import { connect } from 'react-redux';
import { Row, Col, Button, Table, Card, Popconfirm, Tag,Notification, Form } from '@douyinfe/semi-ui';
import { Row, Col, Button, Table, Card, Popconfirm, Tag,Notification, Form,Pagination } from '@douyinfe/semi-ui';
import BurrModal from '../components/burrModal';
import { useEffect } from 'react';
const Burr = (props) => {
const {factorId,abnParam,structId,dispatch,actions,itName,sensorId,project}=props
const {factorId,abnParam,structId,dispatch,actions,itName,sensorId,project,limits,query,changeQuery}=props
const form = useRef()
const [selectedRowKeys, setSelectedRowKeys] = useState([])
const [filterFunc, setFilterFunc] = useState({})
@ -33,7 +33,12 @@ const Burr = (props) => {
dispatch(install.deleteAbnParams(e)).then(res=>{
if(res.success){
const id = [factorId, -1].join(',')
dispatch(install.getAbnParamList({ factorId: id }))
changeQuery(10,0)
dispatch(install.getAbnParamList({ factorId: id,limit:10, page: 0,type:2})).then(rs=>{
if(rs.success){
limitChange(rs.payload.data.count)
}
})
}
})
};
@ -62,7 +67,12 @@ const Burr = (props) => {
dispatch(install.batchCfgAbnParams(ids,data)).then(res=>{
if(res.success){
const id = [factorId, -1].join(',')
dispatch(install.getAbnParamList({ factorId: id }))
changeQuery(10,0)
dispatch(install.getAbnParamList({ factorId: id,limit:10, page: 0,type:2})).then(rs=>{
if(rs.success){
limitChange(rs.payload.data.count)
}
})
}
})
}
@ -74,7 +84,12 @@ const Burr = (props) => {
dispatch(install.deleteAbnParams(ids)).then(res=>{
if(res.success){
const id = [factorId, -1].join(',')
dispatch(install.getAbnParamList({ factorId: id }))
changeQuery(10,0)
dispatch(install.getAbnParamList({ factorId: id,limit:10, page: 0,type:2})).then(rs=>{
if(rs.success){
limitChange(rs.payload.data.count)
}
})
}
})
@ -102,7 +117,12 @@ const Burr = (props) => {
dispatch(install.batchCfgAbnParams(ids,data)).then(res=>{
if(res.success){
const id = [factorId, -1].join(',')
dispatch(install.getAbnParamList({ factorId: id }))
changeQuery(10,0)
dispatch(install.getAbnParamList({ factorId: id,limit:10, page:0,type:2})).then(rs=>{
if(rs.success){
limitChange(rs.payload.data.count)
}
})
}
})
} else if (dataSource.length != 0) {
@ -236,7 +256,28 @@ const Burr = (props) => {
</Col>
</Row>
</Form>
<Table rowSelection={rowSelection} columns={columns} dataSource={tmpds} />
<Table rowSelection={rowSelection} columns={columns} dataSource={tmpds} pagination={false}/>
<div
style={{
display: "flex",
justifyContent: "flex-end",
padding: "20px 20px",
}}
>
<span style={{ lineHeight: "30px", fontSize: 13, color: 'rgba(0,90,189,0.8)' }}>
{limits}条信息
</span>
<Pagination
total={limits}
showSizeChanger
currentPage={query.page + 1}
pageSizeOpts={[10, 20, 30, 40]}
onChange={(currentPage, pageSize) => {
changeQuery( pageSize, currentPage - 1)
page.current = currentPage - 1
}}
/>
</div>
{modalVisible ? <BurrModal
project={project}
structId={structId}
@ -261,7 +302,7 @@ function mapStateToProps(state) {
return {
isRequesting: false,//
abnParam: abnParam?.data||[],
abnParam: abnParam?.data?.rows || [],
actions:global.actions
}
}

43
web/client/src/sections/install/containers/cacl.jsx

@ -32,6 +32,9 @@ const Calc = (props) => {
const [sensorId, setSensorId] = useState([])//id'
const [itemId, setItemId] = useState(null)//
const [itemName, setItemName] = useState('')//name
const [query, setQuery] = useState({ limit: 10, page: 0 }); //
const [limits,setLimits]=useState(0)
// const [methodValue,setMethodValue]=useState(1)//
const form = useRef()
const form2 = useRef()
const method = {
@ -44,13 +47,23 @@ const Calc = (props) => {
// getData()
dispatch(install.getAbnMethods())
}, [])
console.log('factore111',factorId)
//
const pageChange=(arg1,arg2)=>{
setQuery( {limit: arg1, page:arg2 })
}
const limitChange=(arg)=>{
setLimits(arg)
}
useEffect(() => {
if(project&&factorId){
const id = [factorId, -1].join(',')
dispatch(install.getAbnParamList({ factorId: id }))
dispatch(install.getAbnParamList({ factorId: id,limit:query.limit, page: query.page,type:method[methodType]})).then(rs=>{
if(rs.success){
setLimits(rs.payload.data.count)
}
})
}
}, [factorId,project])
}, [factorId,project,methodType,query])
//
useEffect(() => {
@ -114,11 +127,11 @@ const Calc = (props) => {
let seStaName = sensorList.find(a => a.value == selectIds[i]).label
let cfg
if (methodType == "interrupt") {
cfg = abnParam.find(a => a.abnType == 1 && a.factorId == factorId
cfg = abnParam?.find(a => a.abnType == 1 && a.factorId == factorId
&& a.sensorId == project+':'+ selectIds[i])
} else {
let type = methodType == "burr" ? 2 : 3
cfg = abnParam.find(a => a.abnType == type && a.factorId == factorId
cfg = abnParam?.find(a => a.abnType == type && a.factorId == factorId
&& a.sensorId ==project+':'+ selectIds[i])
}
if (!cfg) {
@ -140,7 +153,6 @@ const Calc = (props) => {
form2.current.validate().then(res => {
if (sensorId.length != 0) {
let ids = getStationstoSave()
console.log('xx111',ids)
if (ids.toSave.length != 0) {
let paramJson = getJson(res)
let data = {
@ -170,7 +182,11 @@ const Calc = (props) => {
dispatch(install.addAbnParam(pushData)).then(res => {
if (res.success) {
const id = [factorId, -1].join(',')
dispatch(install.getAbnParamList({ factorId: id }))
dispatch(install.getAbnParamList({ factorId: id,limit:query.limit, page: query.page,type:method[methodType]})).then(rs=>{
if(rs.success){
setLimits(rs.payload.data.count)
}
})
}
})
if (ids.notToSave.length != 0) {
@ -315,6 +331,7 @@ const Calc = (props) => {
)
}
const changeMethod = (value) => {
setQuery({ limit: 10, page: 0 })
setMethodType(value)
}
const clearFactorAndSensor = () => {
@ -325,7 +342,10 @@ const Calc = (props) => {
setStructId(value)
clearFactorAndSensor()
}
// const methodChange=(e)=>{
// console.log('methodChange',e)
// setMethodValue(e)
// }
const renderParamsConfig = () => {
switch (methodType) {
@ -439,7 +459,7 @@ const Calc = (props) => {
<Form.Select showSearch filter label="异常识别算法" field="method" onChange={changeMethod}
placeholder="请选择异常识别算法" style={{ textAlign: 'left', width: 127 }} >
{abnMethods?.map(item => {
return <Form.Select.Option value={item.name} label={item.des}></Form.Select.Option>;
return <Form.Select.Option value={item.name} label={item.des} ></Form.Select.Option>;
})}
</Form.Select>
</Col>
@ -464,7 +484,7 @@ const Calc = (props) => {
</Row>
</Form>
<AbnRecognize project={project} sensorId={sensorId} calcMethod={methodType} factorId={factorId} structId={structId} itName={itemName} />
<AbnRecognize limitChange={limitChange} query={query} changeQuery={pageChange} limits={limits} project={project} sensorId={sensorId} calcMethod={methodType} factorId={factorId} structId={structId} itName={itemName} />
</div>
</div>
@ -484,13 +504,14 @@ const Calc = (props) => {
function mapStateToProps(state) {
const { auth, global, OrganizationDeps, abnMethods, abnParam } = state;
return {
loading: OrganizationDeps.isRequesting,
user: auth.user,
actions: global.actions,
pepProjectId: global.pepProjectId,
abnMethods: abnMethods?.data || [],
abnParam: abnParam?.data || []
abnParam: abnParam?.data?.rows || []
};
}
export default connect(mapStateToProps)(Calc);

57
web/client/src/sections/install/containers/interrupt.jsx

@ -2,13 +2,13 @@
import React, { useRef, useState, useEffect } from 'react';
import { connect } from 'react-redux';
import { Row, Col, Button, Table, Card, Popconfirm, Tag, Notification, Form } from '@douyinfe/semi-ui';
import { Row, Col, Button, Table, Card, Popconfirm, Tag, Notification, Form,Pagination } from '@douyinfe/semi-ui';
import InterruptModal from '../components/interruptModal';
import '../style.less'
const Interrupt = (props) => {
const {dispatch, abnParam,structId,factorId,actions,sensorId,project} = props
const {dispatch, abnParam,structId,factorId,actions,sensorId,project,limits,query,changeQuery,limitChange} = props
const form = useRef()
const [selectedRowKeys, setSelectedRowKeys] = useState([])
const [filterFunc, setFilterFunc] = useState({})
@ -31,7 +31,12 @@ const Interrupt = (props) => {
dispatch(install.deleteAbnParams(e)).then(res=>{
if(res.success){
const id = [factorId, -1].join(',')
dispatch(install.getAbnParamList({ factorId: id }))
changeQuery(10,0)
dispatch(install.getAbnParamList({ factorId: id,limit:10, page: 0,type:1})).then(rs=>{
if(rs.success){
limitChange(rs.payload.data.count)
}
})
}
})
}
@ -59,7 +64,12 @@ const Interrupt = (props) => {
dispatch(install.batchCfgAbnParams(ids,data)).then(res=>{
if(res.success){
const id = [factorId, -1].join(',')
dispatch(install.getAbnParamList({ factorId: id }))
changeQuery(10,0)
dispatch(install.getAbnParamList({ factorId: id,limit:10, page: 0,type:1})).then(rs=>{
if(rs.success){
limitChange(rs.payload.data.count)
}
})
}
})
@ -72,7 +82,12 @@ const Interrupt = (props) => {
dispatch(install.deleteAbnParams(ids)).then(res=>{
if(res.success){
const id = [factorId, -1].join(',')
dispatch(install.getAbnParamList({ factorId: id }))
changeQuery(10,0)
dispatch(install.getAbnParamList({ factorId: id,limit:10, page: 0,type:1})).then(rs=>{
if(rs.success){
limitChange(rs.payload.data.count)
}
})
}
})
} else {
@ -96,7 +111,12 @@ const Interrupt = (props) => {
dispatch(install.batchCfgAbnParams(ids,data)).then(res=>{
if(res.success){
const id = [factorId, -1].join(',')
dispatch(install.getAbnParamList({ factorId: id }))
changeQuery(10,0)
dispatch(install.getAbnParamList({ factorId: id,limit:10, page:0,type:1})).then(rs=>{
if(rs.success){
limitChange(rs.payload.data.count)
}
})
}
})
} else if (dataSource.length != 0) {
@ -229,7 +249,28 @@ const Interrupt = (props) => {
</Col>
</Row>
</Form>
<Table rowSelection={rowSelection} columns={columns} dataSource={tmpds} />
<Table rowSelection={rowSelection} columns={columns} dataSource={tmpds} pagination={false}/>
<div
style={{
display: "flex",
justifyContent: "flex-end",
padding: "20px 20px",
}}
>
<span style={{ lineHeight: "30px", fontSize: 13, color: 'rgba(0,90,189,0.8)' }}>
{limits}条信息
</span>
<Pagination
total={limits}
showSizeChanger
currentPage={query.page + 1}
pageSizeOpts={[10, 20, 30, 40]}
onChange={(currentPage, pageSize) => {
changeQuery( pageSize, currentPage - 1)
page.current = currentPage - 1
}}
/>
</div>
{modalVisible ? <InterruptModal
structId={structId}
visible={true}
@ -260,7 +301,7 @@ function mapStateToProps(state) {
return {
isRequesting: false,//
abnParam: abnParam?.data || [],
abnParam: abnParam?.data?.rows || [],
actions:global.actions,
}
}

38
web/client/src/sections/install/containers/roles.jsx

@ -1,6 +1,6 @@
import React, { useEffect, useState, useRef } from 'react';
import { connect } from 'react-redux';
import { Skeleton, Table, RadioGroup, Radio, Button, Pagination, Popconfirm, Tooltip } from '@douyinfe/semi-ui';
import { Skeleton, Table, RadioGroup, Radio, Button, Pagination, Popconfirm, Tooltip,Input } from '@douyinfe/semi-ui';
import { SkeletonScreen, } from "$components";
import AdminModal from '../components/adminModal';
import MemberModal from '../components/memberModal';
@ -371,13 +371,14 @@ const Roles = (props) => {
},
},
])
// const [data, setdata] = useState([])//
// const [data, setData] = useState([])//
const tableData = useRef([]); //
const page = useRef(query.page);//
const [limits, setLimits] = useState()//
const mylimits = useRef(); //
const [pepList, setPepList] = useState([])//
const [pomsList, setPomsList] = useState([])//
const [keywords,setKeywords]=useState('')
const userAdmin = user?.pomsUserInfo?.role.includes('admin') //
useEffect(() => {
@ -397,7 +398,8 @@ const Roles = (props) => {
let searchData = { ...query, role: roleChoose }
dispatch(install.getOrganizationUser(searchData)).then((res) => {//
if (res.success) {
tableData.current = res.payload.data.users.rows;
tableData.current = res.payload.data.users.rows
// setData(res.payload.data.users.rows)
let notCreatedArr = []
let notCreatedNum = 5 - res.payload.data.admin.length
for (let i = 0; i < notCreatedNum; i++) {
@ -425,6 +427,28 @@ const Roles = (props) => {
function roleOnChange (e) {//
setRoleChoose(e.target.value);
}
const handleChange = (value) => {
setKeywords(value)
}
const searchHanlder = () => {
let searchData = { ...query, limit: Number(10), page: 0 , role: roleChoose,keywords }
dispatch(install.getOrganizationUser(searchData)).then((res) => {//
if (res.success) {
tableData.current = res.payload.data.users.rows
// setData(res.payload.data.users.rows)
let notCreatedArr = []
let notCreatedNum = 5 - res.payload.data.admin.length
for (let i = 0; i < notCreatedNum; i++) {
notCreatedArr.push('')
}
if (userAdmin) notCreatedArr = []
setRoleAssignment(res.payload.data.admin.concat(notCreatedArr))
setLimits(res.payload.data.users.count)
mylimits.current = res.payload.data.users.rows.length
}
})
}
return (
<>
<div style={{ background: '#FFFFFF', margin: '8px 12px', padding: '20px 20px 0px 20px' }}>
@ -552,7 +576,7 @@ const Roles = (props) => {
<div style={{ marginLeft: 6, fontSize: 12, color: '#969799', fontFamily: "DINExp", }}>MANAGEMENT OF MEMBERS</div>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20 }}>
<div style={{ fontSize: 12, color: '#8B8B8B' }}>平台有4种类型的成员角色分别是数据分析师售后运维资源管理者和客户服务每名项目成员可拥有多种成员角色</div>
<div style={{ fontSize: 12, color: '#8B8B8B' }}>平台有5种类型的成员角色分别是数据分析师售后运维资源管理者客户服务和设备维护每名项目成员可拥有多种成员角色</div>
<div className='roleRadio' style={{ display: 'flex', alignItems: 'center' }}>
<div>
<RadioGroup onChange={roleOnChange} value={roleChoose} aria-label="单选组合示例" name="demo-radio-group">
@ -564,6 +588,9 @@ const Roles = (props) => {
<Radio value='firmware_upgrade'>设备维护</Radio>
</RadioGroup>
</div>
<div style={{ display: 'flex', alignItems: 'center',marginLeft:10 }}><Input style={{width: 200,height: 32, borderRadius: 2, marginRight: 10, }} placeholder='请输入人员姓名' onChange={handleChange}/>
<Button onClick={searchHanlder} theme="solid">查询人员</Button></div>
<div>
<Button
theme="solid"
@ -572,7 +599,7 @@ const Roles = (props) => {
width: 108,
height: 32,
borderRadius: 2,
marginLeft: 40
marginLeft: 10
}}
onClick={() => {
setEditObj({})
@ -584,6 +611,7 @@ const Roles = (props) => {
>
添加成员
</Button>
</div>
</div>
</div>

11
web/client/src/sections/install/containers/system.jsx

@ -150,7 +150,7 @@ const Example = (props) => {
title: '安心云项目名称',
dataIndex: "anxinProject",
key: 'anxinProject',
width: 400,
width: 300,
render: (_, row) => {
let anxinerror = false
let anxinerrorArr = []
@ -225,6 +225,15 @@ const Example = (props) => {
)
}
},
{
title: '客户等级',
dataIndex: "customerLevel",
key: 'customerLevel',
// render: (_, row) => {
// let data = { wisdom: '', monitor: '', other: '' }
// return data[row.mappingClass]
// }
},
{
title: '映射类型',
dataIndex: "mappingClass",

57
web/client/src/sections/install/containers/trend.jsx

@ -2,14 +2,14 @@
import React, { Component, useRef,useState } from 'react';
import { connect } from 'react-redux';
import { Row, Col, Button, Table, Card, Popconfirm, Tag, Notification, Form, Select } from '@douyinfe/semi-ui'
import { Row, Col, Button, Table, Card, Popconfirm, Tag, Notification, Form, Select,Pagination } from '@douyinfe/semi-ui'
import {IconPlus} from "@douyinfe/semi-icons"
import TrendModal from '../components/TrendModal';
const Trend = (props) => {
const { abnParam, factorId,itName,actions,dispatch,sensorId,project } = props
const { abnParam, factorId,itName,actions,dispatch,sensorId,project,limits,query,changeQuery,limitChange } = props
const form = useRef()
const [selectedRowKeys, setSelectedRowKeys] = useState([])
const [filterFunc, setFilterFunc] = useState({})
@ -39,7 +39,12 @@ const Trend = (props) => {
dispatch(install.deleteAbnParams(e)).then(res=>{
if(res.success){
const id = [factorId, -1].join(',')
dispatch(install.getAbnParamList({ factorId: id }))
changeQuery(10,0)
dispatch(install.getAbnParamList({ factorId: id,limit:10, page: 0,type:3})).then(rs=>{
if(rs.success){
limitChange(rs.payload.data.count)
}
})
}
})
}
@ -68,7 +73,12 @@ const Trend = (props) => {
dispatch(install.batchCfgAbnParams(ids,data)).then(res=>{
if(res.success){
const id = [factorId, -1].join(',')
dispatch(install.getAbnParamList({ factorId: id }))
changeQuery(10,0)
dispatch(install.getAbnParamList({ factorId: id,limit:10, page: 0,type:3})).then(rs=>{
if(rs.success){
limitChange(rs.payload.data.count)
}
})
}
})
}
@ -81,7 +91,12 @@ const Trend = (props) => {
dispatch(install.deleteAbnParams(ids)).then(res=>{
if(res.success){
const id = [factorId, -1].join(',')
dispatch(install.getAbnParamList({ factorId: id }))
changeQuery(10,0)
dispatch(install.getAbnParamList({ factorId: id,limit:10, page: 0,type:3})).then(rs=>{
if(rs.success){
limitChange(rs.payload.data.count)
}
})
}
})
} else {
@ -112,7 +127,12 @@ const Trend = (props) => {
dispatch(install.batchCfgAbnParams(ids,data)).then(res=>{
if(res.success){
const id = [factorId, -1].join(',')
dispatch(install.getAbnParamList({ factorId: id }))
changeQuery(10,0)
dispatch(install.getAbnParamList({ factorId: id,limit:10, page: 0,type:3})).then(rs=>{
if(rs.success){
limitChange(rs.payload.data.count)
}
})
}
})
} else if (dataSource.length != 0) {
@ -399,7 +419,28 @@ const Trend = (props) => {
</Col>
</Row> : ''}
</Form>
<Table rowSelection={rowSelection} columns={columns} dataSource={tmpds} />
<Table rowSelection={rowSelection} columns={columns} dataSource={tmpds} pagination={false}/>
<div
style={{
display: "flex",
justifyContent: "flex-end",
padding: "20px 20px",
}}
>
<span style={{ lineHeight: "30px", fontSize: 13, color: 'rgba(0,90,189,0.8)' }}>
{limits}条信息
</span>
<Pagination
total={limits}
showSizeChanger
currentPage={query.page + 1}
pageSizeOpts={[10, 20, 30, 40]}
onChange={(currentPage, pageSize) => {
changeQuery( pageSize, currentPage - 1)
page.current = currentPage - 1
}}
/>
</div>
{modalVisible ? <TrendModal
// structId={structId}
visible={true}
@ -420,7 +461,7 @@ function mapStateToProps(state) {
return {
isRequesting: false,//
abnParam: abnParam?.data||[],
abnParam: abnParam?.data?.rows || [],
actions:global.actions
}
}

2
web/client/src/sections/install/style.less

@ -1,6 +1,6 @@
.roleRadio{
.semi-radio{
margin-right: 40px;
// margin-right: 40px;
font-size: 13px;
}
}

2
web/client/src/sections/problem/actions/problem.jsx

@ -72,7 +72,7 @@ export function getAlarmDataGroup (query) { //获取数据告警分类
actionType: 'GET_ALARM_DATA_GROUP',
url: `${ApiTable.getAlarmDataGroup}`,
msg: { option: '获取数据告警分类' },
reducer: { name: '' }
reducer: { name: 'alarmDataGroup' }
});
}

29
web/client/src/sections/problem/components/tableData.jsx

@ -4,7 +4,7 @@ import { Button, Form, Modal, Skeleton, Pagination, Table, Tooltip, Toast } from
import { SkeletonScreen, } from "$components";
import moment from "moment";
const TableData = ({ route, dispatch, actions, collectData, setSetup, exhibition, pepProjectId,
const TableData = ({alarmDataGroup, route, dispatch, actions, collectData, setSetup, exhibition, pepProjectId,
selected, setSelected, setIfBulk, setConfirm, genre, setGenre, query, setQuery, tableData, setTableData, location, user, statusId, setStatusId }) => {
const { problem } = actions
@ -82,7 +82,7 @@ const TableData = ({ route, dispatch, actions, collectData, setSetup, exhibition
break;
default:
if (genre?.length > 0) {
dispatch(problem.getAlarmDataList({ ...query, ...search.current, groupId: groupId.current.map(v => v.id).join(), pepProjectId: pepProjectId })).then((res) => {
dispatch(problem.getAlarmDataList({...(route === 'deviceAbnormal' ? { timestamps: moment().valueOf() } : {}), ...query, ...search.current, groupId: groupId.current.map(v => v.id).join(), pepProjectId: pepProjectId })).then((res) => {
if (res.success) {
setCount(res.payload.data?.count || 0)
let tableDatas = res.payload.data?.rows?.map(v => ({
@ -124,13 +124,13 @@ const TableData = ({ route, dispatch, actions, collectData, setSetup, exhibition
api.current?.setValues({ ...location, state: 'new' })
}
if (route !== 'videoAbnormal' && route !== 'useAbnormal') {
dispatch(problem.getAlarmDataGroup()).then((res) => {
if (res.success) {
// dispatch(problem.getAlarmDataGroup()).then((res) => {
// if (res.success) {
let data
if (route == 'dataLnterrupt') data = res.payload.data?.filter(v => v.desc == '数据中断')
if (route == 'dataAbnormal') data = res.payload.data?.filter(v => v.desc == '数据异常')
if (route == 'strategyHit') data = res.payload.data?.filter(v => v.desc == '策略命中')
if (route == 'deviceAbnormal') data = res.payload.data?.filter(v => v.desc == '掉线' || v.desc == '不活跃')
if (route == 'dataLnterrupt') data = alarmDataGroup?.filter(v => v.desc == '数据中断')
if (route == 'dataAbnormal') data = alarmDataGroup?.filter(v => v.desc == '数据异常')
if (route == 'strategyHit') data = alarmDataGroup?.filter(v => v.desc == '策略命中')
if (route == 'deviceAbnormal') data = alarmDataGroup?.filter(v => v.desc == '掉线' || v.desc == '不活跃')
groupId.current = data
let genreData = []
data?.map(v => {
@ -139,8 +139,8 @@ const TableData = ({ route, dispatch, actions, collectData, setSetup, exhibition
})
})
setGenre(genreData)
}
})
// }
// })
}
if (route == 'useAbnormal') {
setGenre({ element: "元素异常", apiError: "接口报错 ", timeout: "加载超时" })
@ -158,8 +158,7 @@ const TableData = ({ route, dispatch, actions, collectData, setSetup, exhibition
}
})
}
}, [])
}, [route])
const handleExport = () => {
let url = ''
let { keywordTarget, keyword = '', errType = '', state = '', kindId = '', statusId = '', groupUnitId = '', confirmState = '', onlineState = '', sustainTimeStart = '', sustainTimeEnd = '' } = search.current
@ -211,7 +210,7 @@ const TableData = ({ route, dispatch, actions, collectData, setSetup, exhibition
})
break;
default:
dispatch(problem.getAlarmDataList({ ...query, ...search.current, limit: 1, sustainTimeStart, sustainTimeEnd, groupId: groupId.current.map(v => v.id).join(), pepProjectId: pepProjectId })).then((res) => {
dispatch(problem.getAlarmDataList({...(route === 'deviceAbnormal' ? { timestamps: moment().valueOf() } : {}), ...query, ...search.current, limit: 1, sustainTimeStart, sustainTimeEnd, groupId: groupId.current.map(v => v.id).join(), pepProjectId: pepProjectId })).then((res) => {
if (res.success) {
if (res.payload.data.count) {
let groups = {
@ -379,7 +378,6 @@ const TableData = ({ route, dispatch, actions, collectData, setSetup, exhibition
placeholder={SkeletonScreen()}
>
{(() => {
console.log(tableData);
console.log((route == 'useAbnormal' || route == 'videoAbnormal') ?
(tableData?.slice(query.page * query.limit, (query.page + 1) * query.limit) || [])
: tableData);
@ -481,7 +479,7 @@ const TableData = ({ route, dispatch, actions, collectData, setSetup, exhibition
function mapStateToProps (state) {
const { auth, global, members } = state;
const { auth, global, members,alarmDataGroup } = state;
// console.log(global);
return {
user: auth.user,
@ -489,6 +487,7 @@ function mapStateToProps (state) {
global: global,
pepProjectId: global.pepProjectId,
// members: members,
alarmDataGroup:alarmDataGroup.data||[]
};
}
export default connect(mapStateToProps)(TableData);

2
web/client/src/sections/problem/containers/dataAlarm.jsx

@ -46,7 +46,6 @@ const DataAlarm = (props) => {
const statistic = { dataLnterrupt: '数据中断统计', dataAbnormal: '数据异常统计', strategyHit: '策略命中统计', videoAbnormal: '视频异常统计', useAbnormal: '应用半自动化巡检', deviceAbnormal: '设备异常统计' }
useEffect(() => {
if (route) {
//
let data = columns[route]
@ -408,7 +407,6 @@ const DataAlarm = (props) => {
})
return confirmItems;
}
return (
// route=='dataLnterrupt'|| route=='dataAbnormal'|| route=='strategyHit'?
<div style={{ minWidth: 1000 }}>

16
web/client/src/sections/projectGroup/actions/group.js

@ -135,3 +135,19 @@ export function getWorkOrdersRepairRank (query) {
});
}
export function getWorkOrdersAvgTimes (query) {
return (dispatch) => basicAction({
type: "get",
dispatch: dispatch,
query,
actionType: "GET_WORK_ORDERS_AVG_TIMES",
url: `${ApiTable.getWorkOrdersAvgTimes}`,
msg: { error: "获取工单修复平均时长" },
reducer: {
name: "workOrdersAvgTimes",
params: { noClear: true }
},
});
}

368
web/client/src/sections/projectGroup/containers/bigscreen.jsx

@ -1,5 +1,6 @@
import React, { useEffect, useRef, useState } from 'react';
import { Skeleton, Button, Pagination, Select, Popconfirm, Table, Tooltip } from '@douyinfe/semi-ui';
import { Skeleton, Button, Pagination, Select, Popconfirm, Table, Tooltip,Tabs,TabPane} from '@douyinfe/semi-ui';
import { IconChevronUpDown,IconChevronUp,IconChevronDown } from '@douyinfe/semi-icons'
import { connect } from 'react-redux';
import { push } from 'react-router-redux';
import Header from '../components/header';
@ -15,7 +16,7 @@ let interrupt
let repair
let overviewScrollbar;
const Bigscreen = (props) => {
const { dispatch, actions, user, match, history, clientHeight, groupStatisticOnline, pomsProjectBasicAll,...restProps } = props
const { dispatch, actions, user, match, history, clientHeight, groupStatisticOnline, pomsProjectBasicAll, ...restProps } = props
const [InterruptRank, setInterruptRank] = useState([])
const [online, setOnline] = useState([])
@ -25,13 +26,15 @@ const Bigscreen = (props) => {
const [proportion, setProportion] = useState([])
const [formatter, setFormatter] = useState({})
const [groupDetail, setGroupDetail] = useState({})
const [allProjects,setAllProjects]=useState([])
const [allProjects, setAllProjects] = useState([])
const [alarmData, setAlarmData] = useState()//
const [biggest, setBiggest] = useState()//
const [mockData, setMockData] = useState()//
const [xData, setXData] = useState([])//
const self = useRef({ myChart: null });
const [state, setState] = useState(0)
const [interruptData,setInterruptData]=useState([])
const [avgTmes,setAvgTimes]=useState([])//
// const [queryUserId, setQueryUserId] = useState('')
useEffect(() => {
@ -143,25 +146,37 @@ const Bigscreen = (props) => {
useEffect(() => {
if(groupDetail?.pomsProjectIds&&groupDetail?.pomsProjectIds.length&&allProjects&&allProjects.length){
const query=groupDetail?.pomsProjectIds+''
dispatch(actions.projectGroup.getProjectWorkOrders({projectIds:query})).then(res=>{
if(res.success){
setProportion([...res.payload.data?.slice(0, 3)?.map(v => ({ name: allProjects?.find(item=>item.value===v.projectId)?.label, value: Number(v.count) })),
{ name: '其它', value: res.payload.data&&res.payload.data.length>3?res.payload.data?.slice(3)?.reduce((p,c)=>{
return p+Number(c.count)
},0):0 }])
if (groupDetail?.pomsProjectIds && groupDetail?.pomsProjectIds.length && allProjects && allProjects.length) {
const query = groupDetail?.pomsProjectIds + ''
dispatch(actions.projectGroup.getProjectWorkOrders({ projectIds: query })).then(res => {
if (res.success) {
setProportion([...res.payload.data?.slice(0, 3)?.map(v => ({ name: allProjects?.find(item => item.value === v.projectId)?.label, value: Number(v.count) })),
{
name: '其它', value: res.payload.data && res.payload.data.length > 3 ? res.payload.data?.slice(3)?.reduce((p, c) => {
return p + Number(c.count)
}, 0) : 0
}])
}
})
dispatch(actions.projectGroup.getWorkOrdersRepairRank({projectIds:query})).then(res=>{
if(res.success){
setGroupProject(res.payload.data?.slice(0, 10).map(v => ({name:v.formname,startTime:moment(v?.startTime).format('YYYY-MM-DD'),duration:moment(v?.endTime).add(8, 'hours').diff(v?.startTime,'hours') })) || [])
dispatch(actions.projectGroup.getWorkOrdersRepairRank({ projectIds: query })).then(res => {
if (res.success) {
setGroupProject(res.payload.data?.slice(0, 10).map(v => ({ name: v.formname, startTime: moment(v?.startTime).format('YYYY-MM-DD'), duration: moment(v?.endTime).add(8, 'hours').diff(v?.startTime, 'hours') })) || [])
}
})
//
dispatch(actions.projectGroup.getWorkOrdersAvgTimes({ projectIds: query })).then(res=>{
if (res.success) {
const data=res.payload.data?.map(v=>{
return {projectName:allProjects?.find(item => item.value == v.project_id)?.label,
avgTime: Math.ceil(v.avgTime / 60 / 60),
project_id:v.project_id
}
})
setAvgTimes(data)
}
})
}
},[groupDetail,allProjects])
}, [groupDetail, allProjects])
let statisticOnline = (groupId) => {
dispatch(actions.projectGroup.groupStatisticOnline({ groupId })).then(res => {
if (res.success) {
@ -171,8 +186,9 @@ const Bigscreen = (props) => {
Interrupt.push({ name: v.name, ...v.offline })
}
})
Interrupt = Interrupt?.sort((a, b) => b.offline - a.offline)
Interrupt = Interrupt?.sort((a, b) =>a.offnum/a.totnum- b.offnum/b.totnum)
setInterruptRank(Interrupt)
setInterruptData(Interrupt)
setOnline(res.payload.data?.slice(0, 10) || [])
setValue(res.payload.data?.map(v => v.id)?.slice(0, 10) || [])
}
@ -191,8 +207,41 @@ const Bigscreen = (props) => {
timeRequest(groupId)
}, 1000 * 60 * (minuteDifference + 1 || 61));
}
//
const topClick=(e)=>{
let data=[]
interruptData.map(v=>{data.push(v)})
switch (e) {
case 'perBottom':
setInterruptRank(data.sort((a, b) => b.offnum/b.totnum-a.offnum/a.totnum))
setState(1)
break;
case 'perTop':
setInterruptRank(data.sort((a, b) => a.offnum/a.totnum - b.offnum/b.totnum))
setState(0)
break;
case 'timeBottom':
setInterruptRank(data.sort((a, b) => b.offline-a.offline ))
setState(3)
break;
case 'timeTop':
setInterruptRank(data.sort((a, b) => a.offline - b.offline ))
setState(2)
break;
case 'countBottom':
setInterruptRank(data.sort((a, b) => b.totnum-a.totnum ))
setState(5)
break;
case 'countTop':
setInterruptRank(data.sort((a, b) => a.totnum-b.totnum ))
setState(4)
break;
default:
return
}
}
// console.log('sortOrder',sortOrder)
useEffect(() => {
let count = 0;
let currentIndex = -1;
@ -235,7 +284,92 @@ const Bigscreen = (props) => {
<Body>
<div style={{ width: "100%", height: '100%' }}>
<div style={{ width: '100%', height: "45%", display: 'flex' }}>
<div style={{ width: "calc(50% - 8px)", height: "100%", marginRight: 16, display: 'flex' }}>
<Card title='数据在线率' tooltipContent='在线率计算:设备存活/总设备(存活判断:普通设备2h以内有实时数据,GNSS设备8h以内有实时数据)' style={{ width: "calc(50% - 8px)", height: "100%", }}>
<div style={{ height: '100%', position: 'relative' }}>
{/* <div > */}
<Select
showClear
filter
value={value}
multiple={true}
maxTagCount={1}
style={{ width: 300, position: 'absolute', top: 0, right: 0, zIndex: 99 }}
optionList={groupStatisticOnline?.map(v => ({ value: v.id, label: v.name })) || []}
onChange={v => {
setValue(v)
setOnline(groupStatisticOnline?.filter(s => v.includes(s.id)))
}}
/>
{/* </div> */}
<ReactECharts
option={{
title: {
// text: v.name,
},
grid: {
left: 27,
right: 10,
bottom: 20,
},
tooltip: {
trigger: 'axis',
formatter: function (params) {
//
// console.log(params);
let title = params[0].data[0] + '<br/>' + '<br/>'
params.forEach(v => {
let find = online?.find(s => s.name == v.seriesName)?.online?.find(d => moment(d.collect_time).format('YYYY-MM-DD HH') == v.data[0]) || {}
title = title + v.seriesName + ":" + "&nbsp" + "&nbsp" + v.data[1] + "%" + "(" + find?.online + "/" + find?.total + ")" + '<br/>'
})
return title
}
},
xAxis: {
type: 'time',
// name: "",
boundaryGap: false,
minInterval: 1000 * 60 * 60,
},
dataZoom:[
{
show: true,
realtime: true,
start: 0,
end: 100
},
{
type: 'inside',
realtime: true,
start: 0,
end: 100
}
],
yAxis: {
type: 'value',
name: "单位%",
areaStyle: {
color: '#FFF',
},
},
series: online?.map(v => ({
type: 'line',
name: v.name,
smooth: true,
areaStyle: {
color: '#0e9cff26',
},
data: v.online?.map(f => [moment(f.collect_time).format('YYYY-MM-DD HH'), f.rate.toFixed(1)]) || []
})) || []
}}
notMerge={true}
lazyUpdate={true}
style={{ width: "100%", height: "100%" }}
theme={'ReactEChart'}
/>
</div>
</Card>
<div style={{ width: "calc(50% - 8px)", height: "100%", marginLeft: 16, display: 'flex' }}>
<Card title='项目工单占比' tooltipContent='项目工单占比:一个月内项目发起工单修复的次数占比。' style={{ width: "calc(50% - 8px)", height: "100%", marginRight: 16 }}>
<div style={{ height: '100%', position: 'relative' }}>
<div style={{ height: clientHeight * 0.55 - 300, display: 'flex', justifyContent: "center", position: 'relative' }}>
@ -315,15 +449,18 @@ const Bigscreen = (props) => {
</div>
</Card>
<Card title='修复排名' tooltipContent='修复时间排名:一个月内,计算每个工单的修复时间' style={{ width: "calc(50% - 8px)", height: "100%" }}>
<Card title='修复排名' style={{ width: "calc(50% - 8px)", height: "100%" }} tooltipContent='修复时间排名:一个月内,计算每个工单的修复时间'>
<Tabs type="line">
<TabPane tab="修复排名" itemKey="1">
<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: '25%' }}>序号</div>
<div style={{ textAlign: 'center', width: '49%' }}>工单名称</div>
<div style={{ textAlign: 'center', width: '25%' }}>修复时长</div>
</div>
<div id="repair" style={{ position: 'relative', height: clientHeight * 0.55 - 220 }}>
<AutoRollComponent content={<> {groupProject?.map((c, index) => {
<div id="repair" style={{ position: 'relative', height: clientHeight * 0.55 - 220 - 52 }}>
<AutoRollComponent content={<> {groupProject?.map((c, index) => {
return index < 10 ? <div style={{ display: "flex", background: index % 2 == 1 ? "#F6F9FF" : '', padding: 6, height: 50, alignItems: 'center' }}>
<div style={{ textAlign: 'center', width: '25%', fontFamily: 'SourceHanSansCN-Regular', color: '#2C66F3', fontWeight: 400 }}>
NO.{index + 1}</div>
@ -332,31 +469,16 @@ const Bigscreen = (props) => {
<div style={{ textAlign: 'center', width: '25%', fontFamily: 'SourceHanSansCN-Regular', fontWeight: 400 }}>
{c.duration}h</div>
</div> : <></>
})}</>} containerStyle={{ position: "relative", height: "95%", }}
divHeight={"100%"} divId={"rank"} />
})}</>} containerStyle={{ position: "relative", height: "95%", }}
divHeight={"100%"} divId={"rank"} />
</div>
</div>
</Card>
</div>
<Card title='数据在线率' tooltipContent='在线率计算:设备存活/总设备(存活判断:普通设备2h以内有实时数据,GNSS设备8h以内有实时数据)' style={{ width: "calc(50% - 8px)", height: "100%", }}>
<div style={{ height: '100%', position: 'relative' }}>
{/* <div > */}
<Select
showClear
filter
value={value}
multiple={true}
maxTagCount={1}
style={{ width: 300, position: 'absolute', top: 0, right: 0, zIndex: 99 }}
optionList={groupStatisticOnline?.map(v => ({ value: v.id, label: v.name })) || []}
onChange={v => {
setValue(v)
setOnline(groupStatisticOnline?.filter(s => v.includes(s.id)))
}}
/>
{/* </div> */}
<ReactECharts
</TabPane>
<TabPane tab="项目统计" itemKey="2">
<div style={{ height: clientHeight * 0.55 - 220 - 52, fontFamily: 'SourceHanSansCN-Regular', fontSize: 14,width:'100%' }}>
<ReactECharts
option={{
title: {
// text: v.name,
@ -367,54 +489,100 @@ const Bigscreen = (props) => {
bottom: 20,
},
tooltip: {
trigger: 'axis',
formatter: function (params) {
//
// console.log(params);
let title = params[0].data[0] + '<br/>' + '<br/>'
params.forEach(v => {
let find = online?.find(s => s.name == v.seriesName)?.online?.find(d => moment(d.collect_time).format('YYYY-MM-DD HH') == v.data[0]) || {}
title = title + v.seriesName + ":" + "&nbsp" + "&nbsp" + v.data[1] + "%" + "(" + find?.online + "/" + find?.total + ")" + '<br/>'
})
return title
}
// trigger: 'axis',
position: ['5%', '50%'] ,
},
xAxis: {
type: 'time',
// name: "",
boundaryGap: false,
minInterval: 1000 * 60 * 60,
show:true,
type: 'category',
data: avgTmes?.map(s => s.projectName),
axisLabel: {
formatter: function (value) {
//
return value.substring(0, 5) + (value.length > 5 ? '...' : '');
},
},
},
yAxis: {
type: 'value',
name: "单位%",
areaStyle: {
color: '#FFF',
},
name: "单位(小时)",
// areaStyle: {
// color: '#FFF',
// },
},
series: online?.map(v => ({
type: 'line',
name: v.name,
smooth: true,
areaStyle: {
color: '#0e9cff26',
},
data: v.online?.map(f => [moment(f.collect_time).format('YYYY-MM-DD HH'), f.rate.toFixed(1)]) || []
})) || []
series: [
{
type: 'bar',
data: avgTmes?.map(s => s.avgTime),
}
]
}}
notMerge={true}
// notMerge={true}
lazyUpdate={true}
style={{ width: "100%", height: "100%" }}
theme={'ReactEChart'}
/>
</div>
</TabPane>
</Tabs>
</Card>
</div>
</div>
</Card>
</div>
<div style={{ width: '100%', height: "calc(55% - 24px)", display: 'flex', marginTop: 24 }}>
<Card title='中断排名' tooltipContent='中断时长:当前时间-最后一条数据时间。中断个数:结构物下中断测点个数/结构物总测点个数。' style={{ width: "calc(50% - 8px)", 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%', position: 'relative' }}>中断百分比<i class="angle_top" id={state==0?'angleSelected':null} onClick={()=>topClick('perTop')}></i><i id={state==1?'angleSelected':null} class="angle_bottom" onClick={()=>topClick('perBottom')}></i> </div>
<div style={{ textAlign: 'center', width: '33%', position: 'relative' }}>中断时长<i class="angle_top" id={state==2?'angleSelected':null} onClick={()=>topClick('timeTop')}></i><i id={state==3?'angleSelected':null} class="angle_bottom" onClick={()=>topClick('timeBottom')}></i></div>
<div style={{ textAlign: 'center', width: '33%', position: 'relative' }}>中断个数<i class="angle_top" id={state==4?'angleSelected':null} onClick={()=>topClick('countTop')}></i><i id={state==5?'angleSelected':null} class="angle_bottom" onClick={()=>topClick('countBottom')}></i></div>
</div>
<div id="interrupt" style={{ position: 'relative', height: clientHeight * 0.55 - 170 }}>
<AutoRollComponent content={<>
{InterruptRank?.map((c, index) => {
let title
if (c.offline) {
if (c.offline >= 1440 && Math.floor(c.offline / 1440)) title = Math.floor(c.offline / 1440) + "天"
if ((c.offline % 1440) >= 60 && Math.floor(c.offline % 1440 / 60)) {
if (title) {
title = title + Math.floor(c.offline % 1440 / 60) + "时"
} else {
title = Math.floor(c.offline % 1440 / 60) + "时"
}
}
if (c.offline % 1440 % 60) {
if (title) {
title = title + c.offline % 1440 % 60 + "分"
} else {
title = c.offline % 1440 % 60 + "分"
}
}
}
//
const cc = title.split('天')
if (cc.length > 1) {
if (Number(cc[0]) > 200) {
return
}
}
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%', fontFamily: 'SourceHanSansCN-Regular', color: '#F33B3B', fontWeight: 400 }}>{((c.offnum / c.totnum) * 100).toFixed(2)}%</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>
})}</>} containerStyle={{ position: "relative", height: "85%", }}
divHeight={"100%"} divId={"interruptchart"} />
</div>
</div>
</Card>
<Card title='告警排名TOP20' tooltipContent='(1)超阈值个数:一周内结构物超阈值告警的个数。(2)手动恢复个数:一个月内超阈值告警手动恢复的个数' style={{
width: "calc(50% - 8px)", height: "100%", marginRight: 16
width: "calc(50% - 8px)", height: "100%", marginLeft: 16
}} >
{alarmData && alarmData.length > 0 ? (<div style={{ height: '100%' }}>
<div style={{ display: "flex", justifyContent: 'flex-end' }}>
@ -458,46 +626,6 @@ const Bigscreen = (props) => {
</div>
</div>) : ''}
</Card>
<Card title='中断排名' tooltipContent='中断时长:当前时间-最后一条数据时间。中断个数:结构物下中断测点个数/结构物总测点个数。' style={{ width: "calc(50% - 8px)", 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 }}>
<AutoRollComponent content={<>
{InterruptRank?.map((c, index) => {
let title
if (c.offline) {
if (c.offline >= 1440 && Math.floor(c.offline / 1440)) title = Math.floor(c.offline / 1440) + "天"
if ((c.offline % 1440) >= 60 && Math.floor(c.offline % 1440 / 60)) {
if (title) {
title = title + Math.floor(c.offline % 1440 / 60) + "时"
} else {
title = Math.floor(c.offline % 1440 / 60) + "时"
}
}
if (c.offline % 1440 % 60) {
if (title) {
title = title + c.offline % 1440 % 60 + "分"
} else {
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+`(${((c.offnum/c.totnum)*100).toFixed(2)}%)`}</div>
</div>
})}</> } containerStyle={{ position: "relative", height: "85%", }}
divHeight={"100%"} divId={"interruptchart"}/>
</div>
</div>
</Card>
</div>
</div >
@ -506,9 +634,9 @@ const Bigscreen = (props) => {
</div >
)
}
function mapStateToProps (state) {
function mapStateToProps(state) {
const { auth, global, groupStatisticOnline,pomsProjectBasicAll } = state;
const { auth, global, groupStatisticOnline, pomsProjectBasicAll } = state;
return {
user: auth.user,
actions: global.actions,

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

@ -104,6 +104,46 @@
margin-left: 134.48px;
}
.angle_top {
content: '';
width: 0;
height: 0;
display: block;
border-style: solid;
border-width: 0 6px 6px;
// border-color: transparent transparent #5e5e5e;
position: absolute;
transform: rotate(180deg);
bottom: 3px;
right: 62px;
}
.angle_bottom {
content: '';
width: 0;
height: 0;
display: block;
border-style: solid;
border-width: 0 6px 6px;
// border-color: transparent transparent #5e5e5e;
position: absolute;
top: 2px;
right: 62px;
}
.angle_bottom,.angle_top:first-child{
border-color: transparent transparent #5e5e5e;
}
.angle_bottom,.angle_top:nth-child(2){
border-color: transparent transparent #5e5e5e;
}
.angle_bottom,.angle_top:nth-child(3){
border-color: transparent transparent #5e5e5e;
}
#angleSelected {
/* 添加选中时的样式 */
border-color: transparent transparent blue
}

16
web/client/src/sections/service/components/automatic-Modal.jsx

@ -22,7 +22,6 @@ const AutomaticModal = ({ actions, dispatch, apiRoot, qiniuUrl, visible, eidtDat
useEffect(async () => {
if (eidtData?.id) {
console.log(eidtData);
setProjectId(eidtData?.projectId)
setStructId(eidtData?.structId)
setFactorId(eidtData?.factors?.map(s => s.codeName) || [])
@ -63,6 +62,7 @@ const AutomaticModal = ({ actions, dispatch, apiRoot, qiniuUrl, visible, eidtDat
projectName: v.projectName,
reportType: v.reportType,
reportPicPath: v.reportPicPath[0]?.response?.url,
overview: v.overview[0]?.response?.url,
framer: v.framer,
auditor: v.auditor,
ratifier: v.ratifier,
@ -139,7 +139,7 @@ const AutomaticModal = ({ actions, dispatch, apiRoot, qiniuUrl, visible, eidtDat
>
<Form.Input field="reportName" label='报表名称' style={{ width: 300 }} placeholder="请输入报表名称" showClear
initValue={eidtData?.reportName || ""}
rules={[{ required: true, message: "请输入报表名称,15字以内", max: 15 }]}
// rules={[{ required: true, message: ",15", max: 15 }]}
/>
<Form.Select label="所属项目" field="projectId" placeholder="请选择项目" showClear style={{ width: 300 }} filter
initValue={eidtData?.projectId || ""}
@ -169,7 +169,17 @@ const AutomaticModal = ({ actions, dispatch, apiRoot, qiniuUrl, visible, eidtDat
/>
<Form.Upload label="首页图片" field="reportPicPath" style={{ display: 'inline-block', }}
initValue={eidtData?.reportPicPath && [{ url: `/_file-server/${eidtData?.reportPicPath?.slice(qiniuUrl.length + 1)}`, name: eidtData.reportPicPath?.split('/')?.pop(), status: 'success', preview: ['png', 'jpg', 'jpeg'].includes(eidtData.reportPicPath?.split('.')?.pop()?.replace('.', '')) }] || null}
rules={[{ required: true, message: "请上传首页图片" }]}
// rules={[{ required: true, message: "" }]}
action={`${apiRoot}/attachments/p`}
accept={'.txt, .doc, .docx, .xls, .xlsx, .pdf, .png, .jpg, .rar, .zip'}
limit={1} maxSize={5120}
>
<Button icon={<IconUpload />} theme="light">
文件上传
</Button>
</Form.Upload>
<Form.Upload label="项目概况" field="overview" style={{ display: 'inline-block', }}
initValue={eidtData?.overview && [{ url: `/_file-server/${eidtData?.overview?.slice(qiniuUrl.length + 1)}`, name: eidtData.overview?.split('/')?.pop(), status: 'success', preview: ['png', 'jpg', 'jpeg'].includes(eidtData.reportPicPath?.split('.')?.pop()?.replace('.', '')) }] || null}
action={`${apiRoot}/attachments/p`}
accept={'.txt, .doc, .docx, .xls, .xlsx, .pdf, .png, .jpg, .rar, .zip'}
limit={1} maxSize={5120}

4
web/client/src/sections/workOrder/containers/initiated.jsx

@ -16,6 +16,7 @@ const Rest = (props) => {
const [workflowModalType, setWorkflowModalType] = useState('')
const [checkProcessInstanceId, setCheckProcessInstanceId] = useState(null)
const [params, setParams] = useState({})
const [page,setPage]=useState(1)//
useEffect(() => {
backlogData()
if (!pomsProjectBasicAll.length) {
@ -194,7 +195,7 @@ const Rest = (props) => {
})
.then(res => {
setLoading(false)
backlogData()
backlogData({limit:query.limit,page})
Toast.success({ content: '撤销流程成功', duration: 1, })
}, error => {
Toast.error({ content: '撤销流程失败', duration: 1, })
@ -309,6 +310,7 @@ const Rest = (props) => {
currentPage={query.offset + 1}
pageSizeOpts={[10, 20, 30, 40]}
onChange={(currentPage, pageSize) => {
setPage(currentPage)
setQuery({ limit: pageSize, offset: currentPage - 1 });
backlogData({ ...params, limit: pageSize, offset: currentPage - 1 })
}}

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

@ -188,7 +188,7 @@ export const ApiTable = {
deleteAbnParams: 'delete/abnormal/params/{id}',//删除配置
editAbnParams: 'edit/abnormal/params/{id}',//修改配置
getAbnTaskResult: 'struct/{structId}/abnTask/result/{start}/{end}',//
getWorkOrdersAvgTimes:'project/workOrders/avgTime'
};
// 项企的接口

Loading…
Cancel
Save