@ -0,0 +1,355 @@ |
|||||
|
'use strict'; |
||||
|
|
||||
|
const moment = require("moment"); |
||||
|
|
||||
|
|
||||
|
async function findPatrolRecords(ctx, next) { |
||||
|
const sequelize = ctx.fs.dc.orm; |
||||
|
try { |
||||
|
let rslt = { planCount: 0, done: 0 } |
||||
|
const models = ctx.fs.dc.models |
||||
|
const { projectId, startTime, endTime } = ctx.query |
||||
|
|
||||
|
|
||||
|
const plan = await models.PatrolPlan.findAll({ |
||||
|
where: { |
||||
|
structureId: { $in: projectId.split(',') }, |
||||
|
$or: [{ |
||||
|
startTime: { $lte: startTime }, |
||||
|
endTime: { $gte: endTime } |
||||
|
}, |
||||
|
{ |
||||
|
startTime: { $gt: startTime }, |
||||
|
endTime: { $lt: endTime } |
||||
|
}, |
||||
|
{ |
||||
|
startTime: { $between: [startTime, endTime] }, |
||||
|
}, |
||||
|
{ |
||||
|
endTime: { $between: [startTime, endTime] } |
||||
|
}, |
||||
|
|
||||
|
] |
||||
|
} |
||||
|
}) |
||||
|
if (plan && plan.length) { |
||||
|
for (let { dataValues: c } of plan) { |
||||
|
let frequency = Number(c.frequency.split('次')[0]) || 0 |
||||
|
let points = c.points.length || 0 |
||||
|
let done = 0 |
||||
|
//
|
||||
|
if (moment(c.startTime).isSameOrBefore(moment(startTime)) && moment(c.endTime).isSameOrAfter(moment(endTime))) { |
||||
|
done = await models.PatrolRecord.count({ |
||||
|
where: { |
||||
|
inspectionTime: { $between: [c.startTime, endTime] }, |
||||
|
patrolPlanId: c.id |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
} else if (moment(c.startTime).isSameOrAfter(moment(startTime)) && moment(c.startTime).isSameOrBefore(moment(endTime))) { |
||||
|
done = await models.PatrolRecord.count({ |
||||
|
where: { |
||||
|
inspectionTime: { $between: [c.startTime, endTime] }, |
||||
|
patrolPlanId: c.id |
||||
|
} |
||||
|
}) |
||||
|
} else if (moment(c.endTime).isSameOrAfter(moment(startTime)) && moment(c.endTime).isSameOrBefore(moment(endTime))) { |
||||
|
done = await models.PatrolRecord.count({ |
||||
|
where: { |
||||
|
inspectionTime: { $between: [c.startTime, c.endTime] }, |
||||
|
patrolPlanId: c.id |
||||
|
} |
||||
|
}) |
||||
|
} else if (moment(c.startTime).isAfter(moment(startTime)) && moment(c.endTime).isBefore(moment(endTime))) { |
||||
|
done = await models.PatrolRecord.count({ |
||||
|
where: { |
||||
|
inspectionTime: { $between: [c.startTime, c.endTime] }, |
||||
|
patrolPlanId: c.id |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
let dones = await models.PatrolRecord.count({ |
||||
|
where: { |
||||
|
inspectionTime: { $between: [startTime, endTime] }, |
||||
|
patrolPlanId: c.id |
||||
|
} |
||||
|
}) |
||||
|
rslt.planCount += frequency * points - done |
||||
|
rslt.done += dones |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
ctx.status = 200 |
||||
|
ctx.body = rslt |
||||
|
|
||||
|
} catch (error) { |
||||
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { message: '查询巡检记录失败' } |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
async function findPatrolRate(ctx) { |
||||
|
try { |
||||
|
const models = ctx.fs.dc.models |
||||
|
const sequelize = ctx.fs.dc.orm; |
||||
|
const { projectId, startTime, endTime } = ctx.query |
||||
|
const res = await models.PatrolRecord.findAll({ |
||||
|
attributes: ['id'], |
||||
|
where: { |
||||
|
projectId: { $in: projectId.split(',') }, |
||||
|
}, |
||||
|
include: [ |
||||
|
{ |
||||
|
model: models.PatrolRecordIssueHandle, |
||||
|
required: true, |
||||
|
where: { |
||||
|
createTime: { $between: [startTime, endTime] }, |
||||
|
}, |
||||
|
attributes: ['createTime', 'state'], |
||||
|
}, |
||||
|
], |
||||
|
|
||||
|
}); |
||||
|
ctx.body = res |
||||
|
ctx.status = 200 |
||||
|
} catch (error) { |
||||
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { message: '查询巡检完成率失败' } |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
async function countByProject(ctx) { |
||||
|
try { |
||||
|
const models = ctx.fs.dc.models |
||||
|
const sequelize = ctx.fs.dc.orm; |
||||
|
const { projectId, } = ctx.query |
||||
|
const res = await models.Project.findAll({ |
||||
|
attributes: [ |
||||
|
'id', |
||||
|
'name', |
||||
|
[sequelize.fn('COUNT', sequelize.literal('"PatrolRecords"."id"')), 'patrolRecordCount'], |
||||
|
[sequelize.fn('COUNT', sequelize.literal('"PatrolRecords->patrolRecordIssueHandles"."id"')), 'issueHandleCount'], |
||||
|
], |
||||
|
include: [ |
||||
|
{ |
||||
|
model: models.PatrolRecord, |
||||
|
// as: 'PatrolRecords',
|
||||
|
attributes: [], |
||||
|
include: [ |
||||
|
{ |
||||
|
model: models.PatrolRecordIssueHandle, |
||||
|
attributes: [], |
||||
|
// as: 'PatrolRecordIssueHandles',
|
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
], |
||||
|
where: { |
||||
|
id: { $in: projectId.split(',') }, |
||||
|
}, |
||||
|
group: ['project.id', 'project.name'], |
||||
|
order: [ |
||||
|
[sequelize.fn('COUNT', sequelize.literal('"PatrolRecords"."id"')), 'DESC'], |
||||
|
], |
||||
|
}); |
||||
|
ctx.body = res |
||||
|
ctx.status = 200 |
||||
|
} catch (error) { |
||||
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { message: '根据结构物汇集失败' } |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
async function devicesGuarantee(ctx) { |
||||
|
try { |
||||
|
let rslt = {} |
||||
|
const models = ctx.fs.dc.models |
||||
|
const sequelize = ctx.fs.dc.orm; |
||||
|
const { projectId, } = ctx.query |
||||
|
let option = { |
||||
|
// where: searchWhere,
|
||||
|
order: [["id", "desc"]], |
||||
|
include: [{ |
||||
|
model: models.PointDevice, |
||||
|
include: { |
||||
|
model: models.Point, |
||||
|
where: { projectId: { $in: projectId.split(',') } } |
||||
|
} |
||||
|
}] |
||||
|
} |
||||
|
const res = await models.Device.findAll(option); |
||||
|
rslt.count = res.length |
||||
|
let underGuarantee = 0 |
||||
|
for (let { dataValues: c } of res) { |
||||
|
if (moment(c.dateGuarantee).isAfter(moment())) { |
||||
|
underGuarantee += 1 |
||||
|
} |
||||
|
} |
||||
|
rslt.underGuarantee = underGuarantee |
||||
|
const rs = await sequelize.query(` |
||||
|
SELECT d.type, COUNT(d.id) as count |
||||
|
FROM device d |
||||
|
LEFT JOIN point_device pd |
||||
|
ON d.id = pd.device_id |
||||
|
LEFT JOIN point p |
||||
|
ON pd.point_id = p.id |
||||
|
WHERE p.project_id IN (${projectId}) |
||||
|
GROUP by d.type`)
|
||||
|
rslt.rs = rs[0] |
||||
|
ctx.body = rslt |
||||
|
ctx.status = 200 |
||||
|
} catch (error) { |
||||
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { message: '查询设备失败' } |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
async function getHistoricalFaults(ctx) { |
||||
|
try { |
||||
|
const models = ctx.fs.dc.models |
||||
|
const sequelize = ctx.fs.dc.orm; |
||||
|
const { projectId, startTime, endTime } = ctx.query |
||||
|
const rslt = await sequelize.query(` |
||||
|
select p.name, |
||||
|
count(1) as count, |
||||
|
count(case when prih.state=6 then 1 end) as bCount |
||||
|
from project p |
||||
|
left join patrol_record pr |
||||
|
on p.id = pr.project_id |
||||
|
left join patrol_record_issue_handle prih |
||||
|
on pr.id = prih.patrol_record_id |
||||
|
and prih.create_time |
||||
|
between '${startTime}' |
||||
|
and '${endTime}' |
||||
|
where p.id in (${projectId}) |
||||
|
group by p.name |
||||
|
|
||||
|
`)
|
||||
|
ctx.body = rslt[0] |
||||
|
ctx.status = 200 |
||||
|
} catch (error) { |
||||
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { message: '查询历史故障失败' } |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
async function getFaultsRank(ctx) { |
||||
|
try { |
||||
|
let rslt = [] |
||||
|
const models = ctx.fs.dc.models |
||||
|
const sequelize = ctx.fs.dc.orm; |
||||
|
const { projectId, } = ctx.query |
||||
|
const rs = await models.PatrolRecord.findAll( |
||||
|
{ |
||||
|
where: |
||||
|
{ projectId: { $in: projectId.split(',') } } |
||||
|
} |
||||
|
) |
||||
|
for (let { dataValues: c } of rs) { |
||||
|
if (c.points.inspectContent && c.points.inspectContent.length) { |
||||
|
for (let p of c.points.inspectContent) { |
||||
|
if (p.deviceId) { |
||||
|
if(p.alarm){ |
||||
|
const isExist = rslt.find(item => item.id === p.deviceId) |
||||
|
if (!isExist) { |
||||
|
rslt.push({ id: p.deviceId, name: p.deviceName, count: 1 }) |
||||
|
} else { |
||||
|
isExist.count += 1 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
rslt.sort((a, b) => b.count - a.count) |
||||
|
ctx.body = rslt |
||||
|
ctx.status = 200 |
||||
|
} catch (error) { |
||||
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { message: '查询故障排名失败' } |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
async function getCenterData(ctx) { |
||||
|
try{ |
||||
|
let rslt = {} |
||||
|
const models = ctx.fs.dc.models |
||||
|
const sequelize = ctx.fs.dc.orm; |
||||
|
const { projectId, } = ctx.query |
||||
|
let option = { |
||||
|
// where: searchWhere,
|
||||
|
order: [["id", "desc"]], |
||||
|
include: [{ |
||||
|
model: models.PointDevice, |
||||
|
include: { |
||||
|
model: models.Point, |
||||
|
where: { projectId: { $in: projectId.split(',') } } |
||||
|
} |
||||
|
}] |
||||
|
} |
||||
|
const res = await models.Device.findAll(option) |
||||
|
const rs = await sequelize.query(` |
||||
|
select |
||||
|
count(1) as count, |
||||
|
count(case when prih.state=6 then 1 end) as bCount |
||||
|
from project p |
||||
|
left join patrol_record pr |
||||
|
on p.id = pr.project_id |
||||
|
left join patrol_record_issue_handle prih |
||||
|
on pr.id = prih.patrol_record_id |
||||
|
where p.id in (${projectId}) |
||||
|
`)
|
||||
|
const record=await models.PatrolRecord.count({where:{projectId:{$in:projectId.split(',')}}}) |
||||
|
const reportCount=await models.ReportInfo.count({ |
||||
|
where:{ |
||||
|
$or:[ {projectId:{$in:projectId.split(',') }}, |
||||
|
|
||||
|
{ |
||||
|
structureIds:{$contains:projectId.split(',').map(item=>parseInt(item))} |
||||
|
} |
||||
|
|
||||
|
] |
||||
|
|
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
rslt.deviceCount=res.length |
||||
|
rslt.questions=rs[0][0]?Number(rs[0][0].count):0 |
||||
|
rslt.handleCount=rs[0][0]?Number(rs[0][0].count):0 |
||||
|
rslt.records=record |
||||
|
rslt.reportCount=reportCount |
||||
|
ctx.body = rslt |
||||
|
ctx.status = 200 |
||||
|
}catch(error){ |
||||
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { message: '领导驾驶舱中间数据查询失败' } |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
module.exports = { |
||||
|
findPatrolRecords, |
||||
|
findPatrolRate, |
||||
|
countByProject, |
||||
|
devicesGuarantee, |
||||
|
getHistoricalFaults, |
||||
|
getFaultsRank, |
||||
|
getCenterData |
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
'use strict'; |
||||
|
const leader = require('../../controllers/bigScreen/leader'); |
||||
|
|
||||
|
module.exports = function (app, router, opts) { |
||||
|
|
||||
|
|
||||
|
app.fs.api.logAttr['GET/bigScreen/patrolRecord'] = { content: '查询对应结构物下的结构物相关的', visible: false }; |
||||
|
router.get('/bigScreen/patrolRecord', leader.findPatrolRecords) |
||||
|
|
||||
|
app.fs.api.logAttr['GET/bigScreen/patrolRate'] = { content: '查询巡检率', visible: false }; |
||||
|
router.get('/bigScreen/patrolRate', leader.findPatrolRate) |
||||
|
|
||||
|
|
||||
|
app.fs.api.logAttr['GET/bigScreen/patrolCount'] = { content: '根据结构物汇集巡检', visible: false }; |
||||
|
router.get('/bigScreen/patrolCount', leader.countByProject) |
||||
|
|
||||
|
app.fs.api.logAttr['GET/bigScreen/devices/guarantee'] = { content: '查询设备寿命相关', visible: false }; |
||||
|
router.get('/bigScreen/devices/guarantee', leader.devicesGuarantee) |
||||
|
|
||||
|
app.fs.api.logAttr['GET/bigScreen/historicalFaults'] = { content: '查询历史错误', visible: false }; |
||||
|
router.get('/bigScreen/historicalFaults', leader.getHistoricalFaults) |
||||
|
|
||||
|
app.fs.api.logAttr['GET/bigScreen/faultsRank'] = { content: '查询故障排名', visible: false }; |
||||
|
router.get('/bigScreen/faultsRank', leader.getFaultsRank) |
||||
|
|
||||
|
app.fs.api.logAttr['GET/bigScreen/centerData'] = { content: '领导驾驶仓中间数据', visible: false }; |
||||
|
router.get('/bigScreen/centerData', leader.getCenterData) |
||||
|
} |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 862 KiB |
After Width: | Height: | Size: 8.4 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 8.6 MiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 918 B |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 923 B |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 8.5 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 890 KiB |
After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 665 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,49 @@ |
|||||
|
import React, { useLayoutEffect, forwardRef } from 'react'; |
||||
|
|
||||
|
import { useAutoResize } from '@jiaminghi/data-view-react'; |
||||
|
import './style.less'; |
||||
|
|
||||
|
const FullScreenContainer = forwardRef(({ |
||||
|
children, className, style, designWidth = 1920, designHeight = 1080, onlyAutoSize = false, divRef, dispatch, |
||||
|
|
||||
|
}, ref) => { |
||||
|
const { domRef } = useAutoResize(ref); |
||||
|
|
||||
|
useLayoutEffect(() => { |
||||
|
const bodyWidth = Math.max(document.documentElement.clientWidth, document.body.clientWidth); |
||||
|
const bodyHeight = Math.max(document.documentElement.clientHeight, document.body.clientHeight); |
||||
|
const w = bodyWidth / designWidth; |
||||
|
const h = bodyHeight / designHeight; |
||||
|
const scale = w < h ? w : h; |
||||
|
const divRect = divRef?.current?.getBoundingClientRect(); |
||||
|
if (onlyAutoSize) { |
||||
|
Object.assign(domRef.current.style, { |
||||
|
width: `${divRect?.width || 0}px`, |
||||
|
height: `${divRect?.height || 0}px`, |
||||
|
position: 'fixed', |
||||
|
// zIndex: 999,
|
||||
|
top: `${divRect?.top || 0}px`, |
||||
|
left: `${divRect?.left || 0}px`, |
||||
|
}); |
||||
|
} else { |
||||
|
Object.assign(domRef.current.style, { |
||||
|
width: `${designWidth}px`, |
||||
|
height: `${designHeight}px`, |
||||
|
}); |
||||
|
domRef.current.style.transform = `scale(${scale}) translate(-50%, -50%)`; |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
return ( |
||||
|
<div |
||||
|
id={onlyAutoSize ? 'dv-screen-container' : 'custom-dv-full-screen-container'} |
||||
|
className={className} |
||||
|
style={style} |
||||
|
ref={domRef} |
||||
|
> |
||||
|
{children} |
||||
|
</div> |
||||
|
); |
||||
|
}); |
||||
|
|
||||
|
export default FullScreenContainer; |
@ -0,0 +1,310 @@ |
|||||
|
#custom-dv-full-screen-container { |
||||
|
position: fixed; |
||||
|
top: 50%; |
||||
|
left: 50%; |
||||
|
overflow: hidden; |
||||
|
transform-origin: left top; |
||||
|
// padding: 14px 8px 28px 8px; |
||||
|
transition: 0.3s; |
||||
|
} |
||||
|
|
||||
|
#super-screen-container { |
||||
|
width: 100%; |
||||
|
height: 100vh; |
||||
|
background-image: url('/assets/bigScreen/bg.png'); |
||||
|
overflow: hidden; |
||||
|
color: #fff; |
||||
|
} |
||||
|
#emergency-command-modal { |
||||
|
color: #fff; |
||||
|
|
||||
|
.onpoint { |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
.close { |
||||
|
display: flex; |
||||
|
justify-content: flex-end; |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
|
||||
|
.top { |
||||
|
display: flex; |
||||
|
justify-content: flex-end; |
||||
|
margin-bottom: 10px; |
||||
|
|
||||
|
.cell-active { |
||||
|
background-image: url("/assets/images/screen/cockpit/modal/cell_bg.png"); |
||||
|
background-size: 100% 100%; |
||||
|
} |
||||
|
|
||||
|
.cell { |
||||
|
padding: 6px 18px; |
||||
|
margin: 0 6px; |
||||
|
border: 1px solid #051043; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.content { |
||||
|
.left { |
||||
|
height: 95%; |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
|
||||
|
img { |
||||
|
height: 100%; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.right { |
||||
|
height: 95%; |
||||
|
font-size: 20px; |
||||
|
overflow-y: auto; |
||||
|
|
||||
|
.task-item { |
||||
|
background: #061A2F; |
||||
|
height: 38px; |
||||
|
padding: 4px 8px; |
||||
|
margin: 8px 0; |
||||
|
font-size: 18px; |
||||
|
text-align: center; |
||||
|
overflow: hidden; |
||||
|
white-space: nowrap; |
||||
|
text-overflow: ellipsis; |
||||
|
width: 96%; |
||||
|
} |
||||
|
|
||||
|
.task-item-active { |
||||
|
background-image: url("/assets/images/screen/cockpit/modal/task_bg.png"); |
||||
|
background-size: 100% 100%; |
||||
|
text-align: center; |
||||
|
height: 38px; |
||||
|
padding: 4px 8px; |
||||
|
margin: 8px 0; |
||||
|
font-size: 18px; |
||||
|
text-align: center; |
||||
|
overflow: hidden; |
||||
|
white-space: nowrap; |
||||
|
text-overflow: ellipsis; |
||||
|
width: 96%; |
||||
|
} |
||||
|
|
||||
|
.right-content { |
||||
|
background-image: url("/assets/images/screen/cockpit/modal/text_bg.png"); |
||||
|
background-size: 100% 100%; |
||||
|
height: 100%; |
||||
|
width: 90%; |
||||
|
padding: 5%; |
||||
|
|
||||
|
.time { |
||||
|
border-bottom: 2px solid #174683; |
||||
|
padding-bottom: 6px; |
||||
|
margin-bottom: 5%; |
||||
|
color: #c1c1c1; |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
|
||||
|
.content-text { |
||||
|
letter-spacing: 0.2rem; |
||||
|
word-break: break-all; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.yuntai { |
||||
|
height: 100%; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
justify-content: center; |
||||
|
|
||||
|
.label { |
||||
|
background-image: url("/assets/images/screen/cockpit/modal/yuntai_label.png"); |
||||
|
background-size: 100% 100%; |
||||
|
background-repeat: no-repeat; |
||||
|
width: fit-content; |
||||
|
padding: 6px 10px; |
||||
|
margin-bottom: 4px; |
||||
|
} |
||||
|
|
||||
|
.control { |
||||
|
border: 1px solid #174683; |
||||
|
height: 85%; |
||||
|
width: 90%; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
|
||||
|
.btn-group { |
||||
|
background-image: linear-gradient(0deg, |
||||
|
#16299e, |
||||
|
#245cd0 50%, |
||||
|
#3389ff); |
||||
|
border-radius: 50%; |
||||
|
width: 150px; |
||||
|
height: 150px; |
||||
|
margin: 10px 0 30px 0; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
|
||||
|
.control-icon { |
||||
|
color: #000; |
||||
|
font-size: 28px; |
||||
|
} |
||||
|
|
||||
|
.left-right { |
||||
|
width: 100%; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
|
||||
|
.control-center { |
||||
|
background-color: #000000; |
||||
|
padding: 8px; |
||||
|
border-radius: 50%; |
||||
|
|
||||
|
.circle { |
||||
|
width: 40px; |
||||
|
height: 40px; |
||||
|
border-radius: 50%; |
||||
|
background-image: linear-gradient(0deg, |
||||
|
#16299e, |
||||
|
#245cd0 50%, |
||||
|
#3389ff); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.add-or-minus { |
||||
|
width: 40%; |
||||
|
display: flex; |
||||
|
justify-content: space-around; |
||||
|
margin: 20px 0; |
||||
|
font-size: 18px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.right::-webkit-scrollbar { |
||||
|
/* 滚动条整体样式 */ |
||||
|
width: 11px; |
||||
|
/* 高宽分别对应横竖滚动条的尺寸 */ |
||||
|
height: 5px; |
||||
|
} |
||||
|
|
||||
|
.right::-webkit-scrollbar-thumb { |
||||
|
/* 滚动条里面小方块 */ |
||||
|
background: #2d7fe2; |
||||
|
} |
||||
|
|
||||
|
.right::-webkit-scrollbar-track { |
||||
|
/* 滚动条里面轨道 */ |
||||
|
background: #154780; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
#alarm-confirm { |
||||
|
height: 100%; |
||||
|
|
||||
|
.title { |
||||
|
font-size: 22px; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
|
||||
|
.icon { |
||||
|
color: #fff; |
||||
|
margin-right: 5px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.content { |
||||
|
margin-left: 50px; |
||||
|
margin-top: 30px; |
||||
|
|
||||
|
.confirm-input { |
||||
|
width: 350px; |
||||
|
margin-top: 30px; |
||||
|
color: #0057C9; |
||||
|
font-size: 16px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.button-group { |
||||
|
position: absolute; |
||||
|
bottom: 70px; |
||||
|
right: 70px; |
||||
|
font-size: 16px; |
||||
|
|
||||
|
.confirm { |
||||
|
color: #fff; |
||||
|
background-color: #0057C9; |
||||
|
border: none; |
||||
|
} |
||||
|
|
||||
|
.cancel { |
||||
|
margin-right: 10px; |
||||
|
border: none; |
||||
|
background-color: #fff; |
||||
|
color: black; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.auto-size-container { |
||||
|
overflow: hidden; |
||||
|
transform-origin: left top; |
||||
|
transition: 0.3s; |
||||
|
position: fixed; |
||||
|
// left: 50%; |
||||
|
} |
||||
|
|
||||
|
.gradient-text-one { |
||||
|
margin-top: -10px; |
||||
|
font-size: 16px; |
||||
|
background-image: -webkit-linear-gradient(bottom, |
||||
|
#fff, |
||||
|
red, |
||||
|
); |
||||
|
-webkit-background-clip: text; |
||||
|
-webkit-text-fill-color: |
||||
|
transparent; |
||||
|
} |
||||
|
|
||||
|
// 超载车数量文字渐变 |
||||
|
.gradient-text-number { |
||||
|
font-weight: Italic; |
||||
|
font-style: italic; |
||||
|
font-size: 25px; |
||||
|
margin-top: -15px; |
||||
|
background-image: -webkit-linear-gradient(bottom, |
||||
|
#fff, |
||||
|
red, |
||||
|
); |
||||
|
-webkit-background-clip: text; |
||||
|
-webkit-text-fill-color: |
||||
|
transparent; |
||||
|
} |
||||
|
|
||||
|
.gradient-text-numbercolor { |
||||
|
font-weight: Italic; |
||||
|
font-style: italic; |
||||
|
font-size: 25px; |
||||
|
margin-top: -15px; |
||||
|
background-image: -webkit-linear-gradient(bottom, |
||||
|
#fff, |
||||
|
#0E88D5, |
||||
|
); |
||||
|
-webkit-background-clip: text; |
||||
|
-webkit-text-fill-color: |
||||
|
transparent; |
||||
|
} |
@ -1,74 +1,364 @@ |
|||||
'use strict'; |
'use strict' |
||||
import React from 'react'; |
import React, { useState, useEffect, useMemo } from 'react' |
||||
import { Menu } from 'antd'; |
import { Menu } from 'antd' |
||||
import { Link } from 'react-router-dom'; |
import { Link } from 'react-router-dom' |
||||
import { connect } from 'react-redux'; |
import { connect } from 'react-redux' |
||||
import styles from './style.css'; |
import styles from './style.css' |
||||
import { |
import { setCurrentTab } from '$utils/someStores' |
||||
MenuFoldOutlined, MenuUnfoldOutlined, UserOutlined, LogoutOutlined |
import { WEATHERMARGIN, ICONSMAP } from '../../constants/weather' |
||||
} from '@ant-design/icons'; |
import { RouteRequest } from '@peace/utils' |
||||
|
import moment from 'moment' |
||||
|
import ShowTime from './showTime' |
||||
|
import { MenuFoldOutlined, MenuUnfoldOutlined, UserOutlined, LogoutOutlined } from '@ant-design/icons' |
||||
|
|
||||
const Header = props => { |
const Header = props => { |
||||
const { dispatch, history, user, pathname, toggleCollapsed, collapsed, actions } = props |
const { dispatch, history, user, pathname, actions, clientWidth=100, toggleCollapsed, globalTab, tabChange } = props |
||||
|
const [tabs, setTabs] = useState({ |
||||
|
patrolManage: [ |
||||
|
{ name: '巡检管理', value: 'manage' }, |
||||
|
{ name: '巡检项', value: 'item' }, |
||||
|
{ name: '巡检日历', value: 'calendar' }, |
||||
|
{ name: '巡检报告', value: 'report' }, |
||||
|
], |
||||
|
deviceManageTabs: [ |
||||
|
{ name: '设备统计', value: 'statistics' }, |
||||
|
{ name: '设备台账', value: 'list' }, |
||||
|
], |
||||
|
}) |
||||
|
const [patrolManageVisible, setPatrolManageVisible] = useState(false) |
||||
|
const [deviceManageTabsVisible, setDeviceManageTabsVisible] = useState(false) |
||||
|
const [currentSubMenuTab, setCurrentSubMenuTab] = useState('') |
||||
|
const [tab, setTab] = useState('error') |
||||
|
const [weather, setWeather] = useState([]) |
||||
|
console.log('globalTab', globalTab) |
||||
|
let headerTitleStyle = { |
||||
|
position: 'absolute', |
||||
|
left: '3.125rem', |
||||
|
top: '.125rem', |
||||
|
fontSize: '1.875rem', |
||||
|
color: ' #FFFFFF', |
||||
|
fontWeight: 600, |
||||
|
fontFamily: 'PangMenZhengDao', |
||||
|
letterSpacing: '.5231rem', |
||||
|
} |
||||
|
let headerTabStyle = { |
||||
|
width: '4.375rem', |
||||
|
height: '1.125rem', |
||||
|
fontFamily: 'PangMenZhengDao', |
||||
|
fontSize: '1.125rem', |
||||
|
color: '#CCE6FF', |
||||
|
letterSpacing: '.0231rem' |
||||
|
} |
||||
|
|
||||
|
|
||||
|
useEffect(() => { |
||||
|
queryWeather() |
||||
|
const timeUpdate = setInterval(() => { |
||||
|
queryWeather() |
||||
|
}, WEATHERMARGIN) |
||||
|
return () => { |
||||
|
clearInterval(timeUpdate) |
||||
|
} |
||||
|
}, []) |
||||
|
|
||||
|
const queryWeather = () => { |
||||
|
// RouteRequest.get(`/query/weather/3d?location=101240101`).then(res => {
|
||||
|
// if (res?.daily?.length === 3) {
|
||||
|
// setWeather(res.daily)
|
||||
|
// }
|
||||
|
// })
|
||||
|
} |
||||
|
|
||||
|
const iconSrc = useMemo(() => { |
||||
|
if (weather.length === 3) { |
||||
|
const icon = [ICONSMAP[weather[0].textDay], ICONSMAP[weather[1].textDay], ICONSMAP[weather[2].textDay]] |
||||
|
return icon |
||||
|
} |
||||
|
return [] |
||||
|
}, [weather]) |
||||
const handelClick = item => { |
const handelClick = item => { |
||||
if (item.key == 'logout') { |
if (item.key == 'logout') { |
||||
dispatch(actions.auth.logout(user)); |
dispatch(actions.auth.logout(user)) |
||||
dispatch({ type: 'CLEAR_GLOBAL_SITE_LIST' });//清空用户关注工地列表
|
dispatch({ type: 'CLEAR_GLOBAL_SITE_LIST' }) //清空用户关注工地列表
|
||||
history.push(`/signin`); |
history.push(`/signin`) |
||||
} |
} |
||||
} |
} |
||||
|
const onClick1 = tab => { |
||||
let current = pathname; |
setTab(tab) |
||||
if (pathname == '/' || pathname == '') { |
if (tab == 'patrolManage') { |
||||
current = 'default'; |
setPatrolManageVisible(true) |
||||
} else if (pathname.charAt(0) == '/') { |
setDeviceManageTabsVisible(false) |
||||
current = pathname.substring(1); |
} else if (tab == 'device') { |
||||
|
setDeviceManageTabsVisible(true) |
||||
|
setPatrolManageVisible(false) |
||||
|
} else { |
||||
|
setPatrolManageVisible(false) |
||||
|
setDeviceManageTabsVisible(false) |
||||
|
setCurrentSubMenuTab('') |
||||
|
// dispatch({ type: 'TAB-CHANGE', data: tab })
|
||||
} |
} |
||||
|
tabChange(tab) |
||||
if (current.indexOf('/') != -1) { |
|
||||
current = current.substring(0, current.indexOf('/')); |
|
||||
} |
} |
||||
|
|
||||
|
|
||||
return ( |
return ( |
||||
<div className={styles.header}> |
<div className={styles.header} > |
||||
<div className={styles['header-fold']}> |
<div className={styles['header-fold']}> |
||||
{/* <span onClick={toggleCollapsed} style={{ marginRight: 20 }}> |
{/* <img src='/assets/images/logo.svg' style={{ margin: '-14px 12px 0 0', height: 24 }} /> */} |
||||
{collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />} |
|
||||
</span> */} |
|
||||
<img src='/assets/images/logo.svg' style={{ margin: '-14px 12px 0 0', height: 24 }} /> |
|
||||
<div className={styles['header-title']} style={{}}> |
<div className={styles['header-title']} style={{}}> |
||||
<div className={styles['title-cn']}>运维巡检平台</div> |
<span style={headerTitleStyle}>河州路河州路河州路河州路河州路</span> |
||||
<div className={styles['title-en']}>RUNNING MANAGEMENT SYSTEM</div> |
|
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
<div id="nav" className={styles['header-nav']}> |
<div |
||||
|
style={{ |
||||
|
color: '#FFFFFF', |
||||
|
fontSize: '1rem', |
||||
|
fontWeight: 400, |
||||
|
position: 'absolute', |
||||
|
left: '48.25rem', |
||||
|
top: '.4375rem', |
||||
|
}}> |
||||
|
<a |
||||
|
onClick={() => { |
||||
|
onClick1('leader') |
||||
|
}} |
||||
|
style={{ |
||||
|
...headerTabStyle, |
||||
|
// color: tab == 'leader' ? '#E9CF14' : '#FFFFFF',
|
||||
|
// fontWeight: tab == 'leader' ? 500 : 400,
|
||||
|
position: 'relative', |
||||
|
marginRight: '1.375rem', |
||||
|
}}> |
||||
|
{/* <img style={{ marginRight: 4, display: tab == 'leader' ? 'inline-block' : 'none' }} src="/assets/bigScreen/left.png" /> */} |
||||
|
领导驾驶舱 |
||||
|
{/* <img style={{ marginLeft: 4, display: tab == 'leader' ? 'inline-block' : 'none' }} src="/assets/bigScreen/right.png" /> */} |
||||
|
<img |
||||
|
style={{width:'8.3125rem',height:'5.625rem', position: 'absolute', left: '-1.1875rem', top: '-1.5625rem', display: tab == 'leader' ? 'inline-block' : 'none' }} |
||||
|
src='/assets/bigscreen/selected-btn.png' |
||||
|
/> |
||||
|
</a> |
||||
|
<a |
||||
|
onClick={() => { |
||||
|
onClick1('run') |
||||
|
}} |
||||
|
style={{ |
||||
|
...headerTabStyle, |
||||
|
// color: tab == 'run' ? '#E9CF14' : '#FFFFFF',
|
||||
|
position: 'relative', marginRight: '1.375rem' |
||||
|
}}> |
||||
|
{/* <img style={{ marginRight: 4, display: tab == 'run' ? 'inline-block' : 'none' }} src="/assets/bigscreen/left.png" /> */} |
||||
|
运行监控 |
||||
|
{/* <img style={{ marginLeft: 4, display: tab == 'run' ? 'inline-block' : 'none' }} src="/assets/bigscreen/right.png" /> */} |
||||
|
<img |
||||
|
style={{width:'8.3125rem',height:'5.625rem', position: 'absolute', left: '-1.75rem', top: '-1.5625rem', display: tab == 'run' ? 'inline-block' : 'none' }} |
||||
|
src='/assets/bigscreen/selected-btn.png' |
||||
|
/> |
||||
|
</a> |
||||
|
<a |
||||
|
onClick={() => { |
||||
|
onClick1('error') |
||||
|
}} |
||||
|
style={{ |
||||
|
...headerTabStyle, |
||||
|
// color: tab == 'error' ? '#E9CF14' : '#FFFFFF',
|
||||
|
position: 'relative', marginRight: '1.375rem' |
||||
|
}}> |
||||
|
{/* <img style={{ marginRight: 4, display: tab == 'error' ? 'inline-block' : 'none' }} src="/assets/bigscreen/left.png" /> */} |
||||
|
故障管理 |
||||
|
{/* <img style={{ marginLeft: 4, display: tab == 'error' ? 'inline-block' : 'none' }} src="/assets/bigscreen/right.png" /> */} |
||||
|
<img |
||||
|
|
||||
|
style={{ width:'8.3125rem',height:'5.625rem',position: 'absolute', left: '-1.75rem', top: '-1.5625rem', display: tab == 'error' ? 'inline-block' : 'none' }} |
||||
|
src='/assets/bigscreen/selected-btn.png' |
||||
|
/> |
||||
|
</a> |
||||
|
<a |
||||
|
onClick={() => { |
||||
|
onClick1('inspection') |
||||
|
}} |
||||
|
style={{ |
||||
|
...headerTabStyle, |
||||
|
// color: tab == 'inspection' ? '#E9CF14' : '#FFFFFF',
|
||||
|
position: 'relative', marginRight: '1.375rem' }}> |
||||
|
{/* <img style={{ marginRight: 4, display: tab == 'inspection' ? 'inline-block' : 'none' }} src="/assets/bigscreen/left.png" /> */} |
||||
|
巡检管理 |
||||
|
{/* <img style={{ marginLeft: 4, display: tab == 'inspection' ? 'inline-block' : 'none' }} src="/assets/bigscreen/right.png" /> */} |
||||
|
<img |
||||
|
style={{ |
||||
|
width:'8.3125rem',height:'5.625rem', |
||||
|
position: 'absolute', |
||||
|
left: '-1.75rem', top: '-1.5625rem', |
||||
|
display: tab == 'inspection' ? 'inline-block' : 'none', |
||||
|
}} |
||||
|
src='/assets/bigscreen/selected-btn.png' |
||||
|
/> |
||||
|
</a> |
||||
|
<a |
||||
|
onClick={() => { |
||||
|
onClick1('aiot') |
||||
|
}} |
||||
|
style={{ |
||||
|
...headerTabStyle, |
||||
|
|
||||
|
// color: tab == 'aiot' ? '#E9CF14' : '#FFFFFF',
|
||||
|
position: 'relative',marginRight: '1.375rem' }}> |
||||
|
{/* <img style={{ marginRight: 4, display: tab == 'aiot' ? 'inline-block' : 'none' }} src="/assets/bigscreen/left.png" /> */} |
||||
|
AIOT运维 |
||||
|
{/* <img style={{ marginLeft: 4, display: tab == 'aiot' ? 'inline-block' : 'none' }} src="/assets/bigscreen/right.png" /> */} |
||||
|
<img |
||||
|
style={{width:'8.3125rem',height:'5.625rem', position: 'absolute', left: '-1.75rem', top: '-1.5625rem', display: tab == 'aiot' ? 'inline-block' : 'none' }} |
||||
|
src='/assets/bigscreen/selected-btn.png' |
||||
|
/> |
||||
|
</a> |
||||
|
<a |
||||
|
onClick={() => { |
||||
|
onClick1('device') |
||||
|
}} |
||||
|
style={{ |
||||
|
...headerTabStyle, |
||||
|
// color: tab == 'device' ? '#E9CF14' : '#FFFFFF',
|
||||
|
position: 'relative', marginRight: '1.375rem' }}> |
||||
|
{/* <img style={{ marginRight: 4, display: tab == 'device' ? 'inline-block' : 'none' }} src="/assets/bigscreen/left.png" /> */} |
||||
|
设备管理 |
||||
|
{/* <img style={{ marginLeft: 4, display: tab == 'device' ? 'inline-block' : 'none' }} src="/assets/bigscreen/right.png" /> */} |
||||
|
<img |
||||
|
style={{width:'8.3125rem',height:'5.625rem', position: 'absolute',left: '-1.75rem', top: '-1.5625rem', display: tab == 'device' ? 'inline-block' : 'none' }} |
||||
|
src='/assets/bigscreen/selected-btn.png' |
||||
|
/> |
||||
|
</a> |
||||
|
<a |
||||
|
onClick={() => { |
||||
|
onClick1('expert') |
||||
|
}} |
||||
|
style={{ |
||||
|
// color: tab == 'expert' ? '#E9CF14' : '#FFFFFF',
|
||||
|
...headerTabStyle, |
||||
|
position: 'relative', marginRight: '1.375rem' }}> |
||||
|
{/* <img style={{ marginRight: 4, display: tab == 'expert' ? 'inline-block' : 'none' }} src="/assets/bigscreen/left.png" /> */} |
||||
|
运维专家 |
||||
|
{/* <img style={{ marginLeft: 4, display: tab == 'expert' ? 'inline-block' : 'none' }} src="/assets/bigscreen/right.png" /> */} |
||||
|
<img |
||||
|
style={{width:'8.3125rem',height:'5.625rem', position: 'absolute', left: '-1.75rem', top: '-1.5625rem', display: tab == 'expert' ? 'inline-block' : 'none' }} |
||||
|
src='/assets/bigscreen/selected-btn.png' |
||||
|
/> |
||||
|
</a> |
||||
|
<a |
||||
|
onClick={() => { |
||||
|
onClick1('info') |
||||
|
}} |
||||
|
style={{ |
||||
|
...headerTabStyle, |
||||
|
// color: tab == 'info' ? '#E9CF14' : '#FFFFFF',
|
||||
|
position: 'relative', marginRight: '1.375rem' }}> |
||||
|
{/* <img style={{ marginRight: 4, display: tab == 'info' ? 'inline-block' : 'none' }} src="/assets/bigscreen/left.png" /> */} |
||||
|
知识库 |
||||
|
{/* <img style={{ marginLeft: 4, display: tab == 'info' ? 'inline-block' : 'none' }} src="/assets/bigscreen/right.png" /> */} |
||||
|
<img |
||||
|
style={{width:'8.3125rem',height:'5.625rem', position: 'absolute', left: '-1.75rem', top: '-1.5625rem', display: tab == 'info' ? 'inline-block' : 'none' }} |
||||
|
src='/assets/bigscreen/selected-btn.png' |
||||
|
/> |
||||
|
</a> |
||||
|
<a |
||||
|
onClick={() => { |
||||
|
onClick1('task') |
||||
|
}} |
||||
|
style={{ |
||||
|
...headerTabStyle, |
||||
|
// color: tab == 'task' ? '#E9CF14' : '#FFFFFF',
|
||||
|
position: 'relative', marginRight:'2.1875rem' }}> |
||||
|
{/* <img style={{ marginRight: 4, display: tab == 'task' ? 'inline-block' : 'none' }} src="/assets/bigscreen/left.png" /> */} |
||||
|
任务统计 |
||||
|
{/* <img style={{ marginLeft: 4, display: tab == 'task' ? 'inline-block' : 'none' }} src="/assets/bigscreen/right.png" /> */} |
||||
|
<img |
||||
|
style={{width:'8.3125rem',height:'5.625rem', position: 'absolute', left: '-1.75rem', top: '-1.5625rem', display: tab == 'task' ? 'inline-block' : 'none' }} |
||||
|
src='/assets/bigscreen/selected-btn.png' |
||||
|
/> |
||||
|
</a> |
||||
|
<ShowTime marginRight={'0.075rem'} /> |
||||
|
<div style={{ float: 'right', lineHeight: '.1875rem', marginTop: '.5rem' , marginRight: '.875rem' }}> |
||||
|
<div style={{ display: 'flex', alignItems: 'center' }}> |
||||
|
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}> |
||||
|
<div style={{ color: '#FFF' }}>{weather[0]?.textDay}</div> |
||||
|
{/* <div style={{ color: '#24DCF7' }}>{weather[0]?.tempMin}-{weather[0]?.tempMax}℃</div> */} |
||||
|
</div> |
||||
|
<img src={iconSrc[0] || ICONSMAP.未知} alt='icon' style={{ width: '2.6875rem', height: '2.375rem', margin: '.29rem .3125rem' }} /> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
{patrolManageVisible || deviceManageTabsVisible ? ( |
||||
|
<div |
||||
|
style={{ |
||||
|
position: 'absolute', |
||||
|
// width: '29%',
|
||||
|
height: '3.125rem', |
||||
|
top: tab == 'oprations' ? '4.125rem' : '4.8125rem', |
||||
|
left: patrolManageVisible ? '28%' : '36%', |
||||
|
display: 'flex', |
||||
|
// justifyContent: 'space-between',
|
||||
|
justifyContent: 'center', |
||||
|
padding: '.75rem', |
||||
|
}}> |
||||
|
{(patrolManageVisible ? tabs.patrolManage : tabs.deviceManageTabs).map((tab, index) => ( |
||||
|
<div> |
||||
|
<a |
||||
|
onClick={() => this.clickSubMenuTab(tab.value)} |
||||
|
style={{ |
||||
|
color: currentSubMenuTab == tab.value ? '#E9CF14' : 'white', |
||||
|
fontSize: '1rem', |
||||
|
margin: '0 .625rem', |
||||
|
}}> |
||||
|
{tab.name} |
||||
|
</a> |
||||
|
<span |
||||
|
style={{ |
||||
|
display: |
||||
|
index < (patrolManageVisible ? tabs.patrolManage : tabs.deviceManageTabs).length - 1 |
||||
|
? 'inline-block' |
||||
|
: 'none', |
||||
|
}}> |
||||
|
<img src={`/assets/images/bigscreen/boring_${currentSubMenuTab == tab.value ? 1 : 0}.png`} /> |
||||
|
</span> |
||||
|
</div> |
||||
|
))} |
||||
|
</div> |
||||
|
) : ( |
||||
|
'' |
||||
|
)} |
||||
|
|
||||
|
<div id='nav' className={styles['header-nav']}> |
||||
<Menu |
<Menu |
||||
mode='horizontal' |
mode='horizontal' |
||||
selectedKeys={[current]} |
style={{ border: 0 }} |
||||
style={{ border: 0, background: '#004093' }} |
|
||||
onClick={handelClick} |
onClick={handelClick} |
||||
theme={'light'} |
theme={'light'} |
||||
items={[{ |
items={[ |
||||
|
{ |
||||
label: <span style={{ color: 'aliceblue' }}>{user.displayName}</span>, |
label: <span style={{ color: 'aliceblue' }}>{user.displayName}</span>, |
||||
key: "user", |
key: 'user', |
||||
icon: <img className={styles['header-nav-user-img']} src={`/assets/images/avatar/5.png`} />, |
icon: <img className={styles['header-nav-user-img']} src={`/assets/images/avatar/5.png`} />, |
||||
children: [{ |
children: [ |
||||
label: '退出', key: 'logout' |
{ |
||||
}], |
label: '退出', |
||||
}]} |
key: 'logout', |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
]} |
||||
/> |
/> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
); |
) |
||||
}; |
} |
||||
|
|
||||
function mapStateToProps (state) { |
function mapStateToProps(state) { |
||||
const { global, auth } = state; |
const { global, auth, globalTab } = state |
||||
return { |
return { |
||||
actions: global.actions, |
actions: global.actions, |
||||
user: auth.user |
user: auth.user, |
||||
}; |
clientWidth: global.clientWidth, |
||||
|
clientHeight:global.clientHeight, |
||||
|
globalTab: globalTab.tab, |
||||
|
} |
||||
} |
} |
||||
|
|
||||
export default connect(mapStateToProps)(Header); |
export default connect(mapStateToProps)(Header) |
||||
|
@ -0,0 +1,38 @@ |
|||||
|
'use strict'; |
||||
|
import React, { useState, useEffect, useMemo } from 'react'; |
||||
|
import { connect } from 'react-redux'; |
||||
|
import moment from 'moment' |
||||
|
|
||||
|
|
||||
|
|
||||
|
const ShowTime = props => { |
||||
|
const {marginRight}=props |
||||
|
const [date, setDate] = useState(moment()); |
||||
|
const setTime = () => { |
||||
|
setDate(moment()); |
||||
|
setTimeout(() => { |
||||
|
setTime() |
||||
|
}, 1000); |
||||
|
} |
||||
|
|
||||
|
useEffect(()=>{ |
||||
|
setTime() |
||||
|
},[]) |
||||
|
|
||||
|
|
||||
|
return ( <span style={{ color: '#C3E6FF', fontSize: '.9rem',marginRight:marginRight }}>{date.format('YYYY-MM-DD HH:mm:ss')}</span> |
||||
|
) |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
function mapStateToProps(state) { |
||||
|
return { |
||||
|
|
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(ShowTime) |
@ -1,54 +1,60 @@ |
|||||
.header { |
.header { |
||||
position: relative; |
position: relative; |
||||
height: 65px; |
height: 5.75rem; |
||||
min-width: 520px; |
min-width: 32.5rem; |
||||
background-color: #004093; |
/* background-color: #004093; */ |
||||
|
background-image: url('/assets/bigScreen/top.png'); |
||||
} |
} |
||||
|
|
||||
.header-fold { |
.header-fold { |
||||
float: left; |
float: left; |
||||
padding-left: 32px; |
padding-left: 2rem; |
||||
font-size: 16px; |
font-size: 1rem; |
||||
} |
} |
||||
|
|
||||
.header-title { |
.header-title { |
||||
margin-top: 19px; |
margin-top: 1.1875rem; |
||||
height: 60px; |
height: 3.75rem; |
||||
display: inline-block; |
display: inline-block; |
||||
color: #fff; |
color: #fff; |
||||
text-shadow: 0 4px 3px rgba(54, 77, 108, 0.20); |
text-shadow: 0 .25rem .1875rem rgba(54, 77, 108, 0.20); |
||||
} |
} |
||||
|
|
||||
.header-title .title-cn { |
.header-title .title-cn { |
||||
font-family: YouSheBiaoTiHei; |
font-family: YouSheBiaoTiHei; |
||||
font-size: 18px; |
font-size: 1.125rem; |
||||
line-height: 18px; |
line-height: 1.125rem; |
||||
letter-spacing: 3px; |
letter-spacing: .1875rem; |
||||
} |
} |
||||
|
|
||||
.header-title .title-en { |
.header-title .title-en { |
||||
font-family: D-DINExp-Italic; |
font-family: D-DINExp-Italic; |
||||
line-height: 8px; |
line-height: .5rem; |
||||
font-size: 8px; |
font-size: .5rem; |
||||
} |
} |
||||
|
|
||||
.header-nav { |
.header-nav { |
||||
float: right; |
float: right; |
||||
|
margin-top:.4375rem; |
||||
|
margin-right:0px; |
||||
} |
} |
||||
|
|
||||
.header-nav-notification { |
.header-nav-notification { |
||||
/* color : #666; */ |
color : #666; |
||||
font-size: 16px; |
font-size: 1rem; |
||||
} |
} |
||||
|
|
||||
.header-nav-user-img-wrapper { |
.header-nav-user-img-wrapper { |
||||
display: inline; |
display: inline; |
||||
margin: 14px 8px; |
margin: .875rem .5rem; |
||||
} |
} |
||||
|
|
||||
.header-nav-user-img { |
.header-nav-user-img { |
||||
width: 36px; |
width: 2.25rem; |
||||
height: 36px; |
height: 2.25rem; |
||||
position: relative; |
position: relative; |
||||
bottom: 2px; |
bottom: .125rem; |
||||
|
} |
||||
|
.ant-menu{ |
||||
|
background: transparent; |
||||
} |
} |
@ -0,0 +1,89 @@ |
|||||
|
export const WEATHERArr = [ |
||||
|
{ |
||||
|
lbl: '未知', |
||||
|
key: 'weizhi', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '暴雪', |
||||
|
key: 'baoxue', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '多云', |
||||
|
key: 'duoyun', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '浮沉', |
||||
|
key: 'fucheng', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '雷阵雨', |
||||
|
key: 'leizhengyu', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '霾', |
||||
|
key: 'mai', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '强沙尘暴', |
||||
|
key: 'qiangshachengbao', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '晴', |
||||
|
key: 'qing', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '沙尘暴', |
||||
|
key: 'shachengbao', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '特大暴雨', |
||||
|
key: 'tedabaoyu', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '雾', |
||||
|
key: 'wu', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '小雪', |
||||
|
key: 'xiaoxue', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '小雨', |
||||
|
key: 'xiaoyu', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '扬沙', |
||||
|
key: 'yangsha', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '阴天', |
||||
|
key: 'yingtian', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '雨夹雪', |
||||
|
key: 'yujiaxue', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '阵雨', |
||||
|
key: 'zhenyu', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '中雪', |
||||
|
key: 'zhongxue', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '中雨', |
||||
|
key: 'zhongyu', |
||||
|
}, |
||||
|
{ |
||||
|
lbl: '大雨', |
||||
|
key: 'dayu', |
||||
|
}, |
||||
|
]; |
||||
|
export const WEATHERMARGIN = 1 * 60 * 60 * 1000; |
||||
|
export let ICONSMAP = {}; |
||||
|
|
||||
|
WEATHERArr.forEach(({ lbl, key }) => { |
||||
|
const icon = `/assets/images/weather/${key}.png`; |
||||
|
ICONSMAP[lbl] = icon; |
||||
|
}); |
@ -0,0 +1,24 @@ |
|||||
|
'use strict'; |
||||
|
|
||||
|
import Immutable from 'immutable'; |
||||
|
|
||||
|
const initState = { |
||||
|
tab: 'error', |
||||
|
showCG: true |
||||
|
}; |
||||
|
|
||||
|
export default function globalTab(state = initState, action) { |
||||
|
switch (action.type) { |
||||
|
case 'TAB-CHANGE': |
||||
|
return Immutable.fromJS(state).merge({ |
||||
|
tab: action.data |
||||
|
}).toJS(); |
||||
|
|
||||
|
case 'SHOW-CG-CLOSE': |
||||
|
return Immutable.fromJS(state).merge({ |
||||
|
showCG: false |
||||
|
}).toJS(); |
||||
|
default: |
||||
|
return state; |
||||
|
} |
||||
|
} |
@ -0,0 +1,6 @@ |
|||||
|
'use strict'; |
||||
|
import leader from './leader' |
||||
|
export default { |
||||
|
...leader, |
||||
|
|
||||
|
} |
@ -0,0 +1,111 @@ |
|||||
|
'use strict'; |
||||
|
import { basicAction } from '@peace/utils' |
||||
|
import { ApiTable } from '$utils' |
||||
|
|
||||
|
export function findPatrolRecords(query) { |
||||
|
return dispatch => basicAction({ |
||||
|
type: 'get', |
||||
|
query, |
||||
|
dispatch: dispatch, |
||||
|
actionType: 'FIND_PATROL_RECORDS', |
||||
|
url: `${ApiTable.findPatrolRecords}`, |
||||
|
msg: { error: '获取巡检记录数' }, |
||||
|
reducer: { name: 'patrolRecords'} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
export function findPatrolRate(query) { |
||||
|
return dispatch => basicAction({ |
||||
|
type: 'get', |
||||
|
query, |
||||
|
dispatch: dispatch, |
||||
|
actionType: 'FIND_PATROL_RATE', |
||||
|
url: `${ApiTable.findPatrolRate}`, |
||||
|
msg: { error: '获取巡检率失败' }, |
||||
|
reducer: { name: 'patrolRate'} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
export function countByProject(query) { |
||||
|
return dispatch => basicAction({ |
||||
|
type: 'get', |
||||
|
query, |
||||
|
dispatch: dispatch, |
||||
|
actionType: 'COUNT_BY_PROJECT', |
||||
|
url: `${ApiTable.countByProject}`, |
||||
|
msg: { error: '获取巡检排名失败' }, |
||||
|
reducer: { name: 'patrolRank'} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
export function getDevices(query) { |
||||
|
return dispatch => basicAction({ |
||||
|
type: 'get', |
||||
|
query, |
||||
|
dispatch: dispatch, |
||||
|
actionType: 'GET_DEVICES', |
||||
|
url: `${ApiTable.getDevices}`, |
||||
|
msg: { error: '获取设备寿命相关' }, |
||||
|
reducer: { name: 'devices'} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
export function getHistoricalFaults(query) { |
||||
|
return dispatch => basicAction({ |
||||
|
type: 'get', |
||||
|
query, |
||||
|
dispatch: dispatch, |
||||
|
actionType: 'GET_HISTORICAL_FAULTS', |
||||
|
url: `${ApiTable.getHistoricalFaults}`, |
||||
|
msg: { error: '获取历史故障统计' }, |
||||
|
reducer: { name: 'historyFaults'} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
export function getFaultsRank(query) { |
||||
|
return dispatch => basicAction({ |
||||
|
type: 'get', |
||||
|
query, |
||||
|
dispatch: dispatch, |
||||
|
actionType: 'GET_FAULTS_RANK', |
||||
|
url: `${ApiTable.getFaultsRank}`, |
||||
|
msg: { error: '获取故障排名' }, |
||||
|
reducer: { name: 'faultsRank'} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
export function getCenterData(query) { |
||||
|
return dispatch => basicAction({ |
||||
|
type: 'get', |
||||
|
query, |
||||
|
dispatch: dispatch, |
||||
|
actionType: 'GET_CENTER_DATA', |
||||
|
url: `${ApiTable.getCenterData}`, |
||||
|
msg: { error: '获取大屏中心数据' }, |
||||
|
reducer: { name: 'centerData'} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
export default{ |
||||
|
findPatrolRecords, |
||||
|
findPatrolRate, |
||||
|
countByProject, |
||||
|
getDevices, |
||||
|
getHistoricalFaults, |
||||
|
getFaultsRank, |
||||
|
getCenterData |
||||
|
} |
@ -0,0 +1,140 @@ |
|||||
|
'use strict' |
||||
|
import React, { Component } from 'react'; |
||||
|
import { Row, Col } from 'antd'; |
||||
|
|
||||
|
export default class AutoRollComponent extends Component { |
||||
|
|
||||
|
constructor(props) { |
||||
|
super(props); |
||||
|
this.scrollElem = null; |
||||
|
this.stopscroll = false; |
||||
|
this.preTop = 0; |
||||
|
this.cloneEle = null; |
||||
|
this.currentTop = 0; |
||||
|
this.marqueesHeight = 0; |
||||
|
this.interval = null; |
||||
|
this.state = { |
||||
|
enabledScroll: false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
get enabledScroll() { |
||||
|
let scrollElem = document.getElementById(this.props.divId); |
||||
|
let fatherElem = scrollElem?.parentNode || null; |
||||
|
if (scrollElem && fatherElem) { |
||||
|
return scrollElem.scrollHeight > fatherElem.scrollHeight |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
marque = (height) => { |
||||
|
try { |
||||
|
this.scrollElem = document.getElementById(this.props.divId); |
||||
|
this.marqueesHeight = height; |
||||
|
if (this.scrollElem) { |
||||
|
this.scrollElem.style.height = this.marqueesHeight; |
||||
|
console.log('marqueesHeight',this.marqueesHeight) |
||||
|
this.scrollElem.style.overflow = 'hidden'; |
||||
|
} |
||||
|
this.repeat(); |
||||
|
} catch (e) { console.log(e) } |
||||
|
} |
||||
|
|
||||
|
|
||||
|
repeat = () => { |
||||
|
this.scrollElem.scrollTop = 0; |
||||
|
let offset = 1.5 |
||||
|
|
||||
|
this.interval = setInterval(() => { |
||||
|
if (this.stopscroll) return; |
||||
|
this.currentTop = this.currentTop + offset; |
||||
|
this.preTop = this.scrollElem.scrollTop; |
||||
|
this.scrollElem.scrollTop = this.scrollElem.scrollTop + offset; |
||||
|
// console.log(`this.scrollElem.scrollTop:${this.scrollElem.scrollTop} === this.preTop:${this.preTop}`);
|
||||
|
if (this.preTop === this.scrollElem.scrollTop) { |
||||
|
this.scrollElem.scrollTop = this.marqueesHeight; |
||||
|
this.scrollElem.scrollTop = this.scrollElem.scrollTop + offset; |
||||
|
} |
||||
|
}, 100); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
componentWillUnmount() { |
||||
|
clearInterval(this.interval); |
||||
|
} |
||||
|
|
||||
|
componentWillReceiveProps(nextProps) { |
||||
|
requestAnimationFrame(() => { |
||||
|
if (this.enabledScroll) { |
||||
|
if (!this.state.enabledScroll) { |
||||
|
this.setState({ enabledScroll: true }, () => { |
||||
|
this.marque(10) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
componentDidMount() { |
||||
|
if (this.enabledScroll) { |
||||
|
this.setState({ enabledScroll: true }, () => { |
||||
|
this.marque(10) |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
onMouseOver = () => { |
||||
|
this.stopscroll = true; |
||||
|
} |
||||
|
|
||||
|
onMouseOut = () => { |
||||
|
this.stopscroll = false; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
render() { |
||||
|
|
||||
|
const { changeStyleCol, heads, spans, data, divId, divHeight, content, containerStyle = {} } = this.props; |
||||
|
|
||||
|
return ( |
||||
|
<div style={{ ...containerStyle, textAlign: 'left' }}> |
||||
|
{ |
||||
|
heads ? |
||||
|
<Row style={{ lineHeight: '40px', height: 40 }}> |
||||
|
{heads.map((c, index) => { |
||||
|
return <Col span={spans[index]} key={index}>{c}</Col> |
||||
|
}) |
||||
|
} |
||||
|
</Row> : '' |
||||
|
} |
||||
|
|
||||
|
<div id={divId} style={{ overflow: 'hidden', height: divHeight }} onMouseOver={this.onMouseOver} onMouseOut={this.onMouseOut}> |
||||
|
<div> |
||||
|
{content ? content : ''} |
||||
|
{this.state.enabledScroll && content ? content : ''} |
||||
|
{ |
||||
|
data ? |
||||
|
data.map((q, idx) => { |
||||
|
return ( |
||||
|
<div key={idx}> |
||||
|
<Row gutter={16} style={{ borderBottom: '0px solid grey' }}> |
||||
|
{heads.map((c, index) => { |
||||
|
return <Col span={spans[index]} key={index} style={{ paddingTop: 8, textAlign: 'left', wordBreak: 'break-word', color: `${c === changeStyleCol ? q.changeColor : ''}` }}> |
||||
|
{index == 1 ? q.data[index] == -1 ? "-" : q.data[index] : index == 2 ? q.data[1] == -1 ? '-' : q.data[index] : q.data[index]}</Col> |
||||
|
}) |
||||
|
} |
||||
|
</Row> |
||||
|
</div> |
||||
|
) |
||||
|
}) : '' |
||||
|
} |
||||
|
<div style={{ margin: 16 }}></div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div > |
||||
|
) |
||||
|
} |
||||
|
} |
@ -0,0 +1,40 @@ |
|||||
|
import React, { useEffect, useState } from 'react' |
||||
|
import { Spin, Popconfirm, message, Button, Input } from 'antd' |
||||
|
import { connect } from 'react-redux' |
||||
|
import ProTable from '@ant-design/pro-table' |
||||
|
import moment from 'moment' |
||||
|
import ReactEcharts from 'echarts-for-react' |
||||
|
import PerfectScrollbar from 'perfect-scrollbar' |
||||
|
import '../style.less' |
||||
|
|
||||
|
|
||||
|
const Bottom = props => { |
||||
|
const { dispatch, clientHeight, clientWidth, actions } = props |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
return ( |
||||
|
<> |
||||
|
|
||||
|
</> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
function mapStateToProps(state) { |
||||
|
const { auth, global } = state |
||||
|
return { |
||||
|
clientHeight: global.clientHeight, |
||||
|
clientWidth: global.clientWidth, |
||||
|
actions: global.actions, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(Bottom) |
@ -0,0 +1,38 @@ |
|||||
|
//故障管理
|
||||
|
'use strict'; |
||||
|
|
||||
|
|
||||
|
import React, { useEffect, useState } from 'react' |
||||
|
import { Spin, Popconfirm, message, Button, Input } from 'antd'; |
||||
|
import { connect } from 'react-redux'; |
||||
|
import ProTable from '@ant-design/pro-table'; |
||||
|
import moment from 'moment'; |
||||
|
import Bottom from './bottom'; |
||||
|
import Top from './top'; |
||||
|
import '../style.less' |
||||
|
const Error = (props) => { |
||||
|
const {actions,dispatch, globalTab, } = props |
||||
|
|
||||
|
|
||||
|
return <> |
||||
|
<Top/> |
||||
|
<Bottom/> |
||||
|
</> |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
function mapStateToProps(state) { |
||||
|
const { auth, global, device } = state; |
||||
|
return { |
||||
|
clientHeight: global.clientHeight, |
||||
|
actions: global.actions, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(Error) |
||||
|
|
@ -0,0 +1,21 @@ |
|||||
|
.errorContainer { |
||||
|
display: flex; |
||||
|
width: 33.625rem; |
||||
|
height: 20.3125rem; |
||||
|
margin-top: 2.6875rem; |
||||
|
background-image: linear-gradient(180deg, #0080ff00 3%, #0080ff1a 54%, #0080ff3d 100%); |
||||
|
.topHeader { |
||||
|
// width: 33.375rem; |
||||
|
// height: 2.6875rem; |
||||
|
background: url(/assets/bigScreen/cardHeader.png) no-repeat; |
||||
|
background-size: 100% 100%; |
||||
|
height: 2.6875rem; |
||||
|
font-family: PangMenZhengDao; |
||||
|
font-size: 1.125rem; |
||||
|
color: #CCE6FF; |
||||
|
letter-spacing: .0231rem; |
||||
|
display: flex; |
||||
|
padding-left: 2.375rem; |
||||
|
justify-content: space-between, |
||||
|
} |
||||
|
} |
@ -0,0 +1,49 @@ |
|||||
|
import React, { useEffect, useState } from 'react' |
||||
|
import { Spin, Popconfirm, message, Button, Input } from 'antd' |
||||
|
import { connect } from 'react-redux' |
||||
|
import ProTable from '@ant-design/pro-table' |
||||
|
import moment from 'moment' |
||||
|
import ReactEcharts from 'echarts-for-react' |
||||
|
import PerfectScrollbar from 'perfect-scrollbar' |
||||
|
import './style.less' |
||||
|
|
||||
|
|
||||
|
const Top = props => { |
||||
|
const { dispatch, clientHeight, clientWidth, actions } = props |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
return ( |
||||
|
<> |
||||
|
<div style={{display:'flex'}}> |
||||
|
{/* 上1 */} |
||||
|
<div style={{ position: 'relative' }} className='errorContainer'> |
||||
|
<div className='topHeader'> |
||||
|
<div>故障等级分布</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
{/* 上2 */} |
||||
|
<div style={{ position: 'relative' }} className='errorContainer'> |
||||
|
<div className='topHeader'> |
||||
|
<div>问题发现趋势(30天)</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
function mapStateToProps(state) { |
||||
|
const { auth, global } = state |
||||
|
return { |
||||
|
clientHeight: global.clientHeight, |
||||
|
clientWidth: global.clientWidth, |
||||
|
actions: global.actions, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(Top) |
@ -0,0 +1,50 @@ |
|||||
|
import React, { Component } from 'react'; |
||||
|
// import './style.less';
|
||||
|
import { push } from 'react-router-redux'; |
||||
|
import Leader from './leader'; |
||||
|
import Run from './run' |
||||
|
import Error from './error'; |
||||
|
|
||||
|
import { Modal, Form } from 'antd'; |
||||
|
// const { RouteTable, RouteRequest, ApiTable, Request } = WebAPI;
|
||||
|
|
||||
|
// const model = {
|
||||
|
// 'leader': Leader,
|
||||
|
// 'run':Run,
|
||||
|
// 'error':Error,
|
||||
|
// 'inspection':Inspection,//巡检
|
||||
|
// 'item':Item,//巡检项
|
||||
|
// 'Calendar':Calendar,//日历
|
||||
|
// 'report':Report,//报告
|
||||
|
// 'aiot':Aiot,
|
||||
|
// // 'device':Device,
|
||||
|
// 'statistics':Statistics,//设备统计
|
||||
|
// 'list':List,//设备台账
|
||||
|
// 'expert':Expert,
|
||||
|
// 'info':Info,
|
||||
|
// 'task':Task
|
||||
|
// };
|
||||
|
// console.log('Leader',Leader)
|
||||
|
const HomePage=(props)=>{ |
||||
|
const{globalTab}=props |
||||
|
|
||||
|
|
||||
|
return <> |
||||
|
|
||||
|
{globalTab === 'leader' && <Leader />} |
||||
|
{globalTab === 'run' && <Run />} |
||||
|
{globalTab === 'error' && <Error />} |
||||
|
{/* {globalTab === 'run' && <Run />} |
||||
|
{globalTab === 'error' && <Error />} |
||||
|
{globalTab === 'inspection' && <Inspection />} */} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
</> |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
export default HomePage; |
@ -0,0 +1,61 @@ |
|||||
|
//领导驾驶舱
|
||||
|
'use strict'; |
||||
|
|
||||
|
import Left from './left'; |
||||
|
import Right from './right'; |
||||
|
import React, { useEffect, useState } from 'react' |
||||
|
import { Spin, Popconfirm, message, Button, Input } from 'antd'; |
||||
|
import { connect } from 'react-redux'; |
||||
|
import ProTable from '@ant-design/pro-table'; |
||||
|
import moment from 'moment'; |
||||
|
import '../style.less' |
||||
|
const Leader = (props) => { |
||||
|
const {actions,dispatch, globalTab, } = props |
||||
|
const {bigScreen}=actions |
||||
|
const [centerData,setCenterData]=useState({}) |
||||
|
const fontStyle={ |
||||
|
fontSize:'1.2rem', |
||||
|
|
||||
|
} |
||||
|
useEffect(()=>{ |
||||
|
const structArr = JSON.parse(sessionStorage.getItem('user')).monitorObject |
||||
|
dispatch(bigScreen.getCenterData({projectId:structArr.toString()})).then(res=>{ |
||||
|
if(res.success){ |
||||
|
console.log('res.payload.data',res.payload.data) |
||||
|
setCenterData(res.payload.data) |
||||
|
} |
||||
|
}) |
||||
|
},[]) |
||||
|
return <> |
||||
|
<div style={{ display: 'flex', justifyContent: 'space-between',position:'relative' }}> |
||||
|
<Left></Left> |
||||
|
<Right></Right> |
||||
|
</div> |
||||
|
<div style={{position:'absolute',top:'-10rem',left:'27rem',}}> |
||||
|
<img src='/assets/bigScreen/center.webp' style={{display:'inline-block' ,width: '64.47rem', height: '62.3125rem'}}></img> |
||||
|
</div> |
||||
|
<div style={{position:'absolute',top:'15.6rem',left:'38rem',}}><span>设备总数</span><span>{centerData.deviceCount}</span></div> |
||||
|
<div style={{position:'absolute',top:'12rem',left:'45rem',}}><span>发现问题</span><span>{centerData.questions}</span></div> |
||||
|
<div style={{position:'absolute',top:'15rem',left:'57.5rem',}}><div>{centerData.handleCount}</div> <span>累计巡检数</span></div> |
||||
|
<div style={{position:'absolute',top:'12rem',left:'68rem',}}><span>出具报告数</span><span>{centerData.records}</span></div> |
||||
|
<div style={{position:'absolute',top:'15.6rem',left:'75rem',}}><span>处理故障数</span><span>{centerData.reportCount}</span></div> |
||||
|
|
||||
|
</> |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
function mapStateToProps(state) { |
||||
|
const { auth, global, device } = state; |
||||
|
return { |
||||
|
clientHeight: global.clientHeight, |
||||
|
actions: global.actions, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(Leader) |
||||
|
|
@ -0,0 +1,473 @@ |
|||||
|
import React, { useEffect, useState } from 'react' |
||||
|
import { Spin, Popconfirm, message, Button, Input } from 'antd' |
||||
|
import { connect } from 'react-redux' |
||||
|
import ProTable from '@ant-design/pro-table' |
||||
|
import moment from 'moment' |
||||
|
import ReactEcharts from 'echarts-for-react' |
||||
|
import PerfectScrollbar from 'perfect-scrollbar' |
||||
|
import '../style.less' |
||||
|
import AutoRollComponent from '../AutoRollComponent' |
||||
|
|
||||
|
let scrollbarLeft |
||||
|
let problems |
||||
|
const Left = props => { |
||||
|
const { dispatch, clientHeight, clientWidth, actions } = props |
||||
|
const [startTime, setStartTime] = useState(moment().startOf('week').format('YYYY-MM-DD HH:mm:ss')) |
||||
|
const [endTime, setEndTime] = useState(moment().endOf('week').format('YYYY-MM-DD HH:mm:ss')) |
||||
|
const [plan, setPlan] = useState(0) |
||||
|
const [done, setDone] = useState(0) |
||||
|
const [cRate, setCRate] = useState([]) //完成率
|
||||
|
const [rRate, setRRate] = useState([]) //修复率
|
||||
|
const [months, setMonths] = useState([]) |
||||
|
const [period, setPeriod] = useState('week') |
||||
|
const [rank,setRank]=useState([]) |
||||
|
const [state, setState] = useState(0) |
||||
|
const [rankCopy,setRankCopy]=useState([])//用于排序(巡检次数)
|
||||
|
const { bigScreen } = actions |
||||
|
// const questFontColor = { color: '#8f7a49' } //有问题的颜色
|
||||
|
const normalFontColor = { color: 'yellow' } //正常的颜色
|
||||
|
useEffect(() => { |
||||
|
scrollbarLeft = new PerfectScrollbar('#left1', { suppressScrollX: true }) |
||||
|
const dom = document.getElementById('left1') |
||||
|
if (dom) { |
||||
|
scrollbarLeft.update() |
||||
|
// dom.scrollTop = 0
|
||||
|
} |
||||
|
// getData()
|
||||
|
queryData() |
||||
|
const months = generateMonthNames() |
||||
|
setMonths(months) |
||||
|
}, []) |
||||
|
useEffect(() => { |
||||
|
getData() |
||||
|
}, [startTime]) |
||||
|
|
||||
|
const queryData = async () => { |
||||
|
let repair = [] |
||||
|
const structArr = JSON.parse(sessionStorage.getItem('user')).monitorObject |
||||
|
const sTime = moment().subtract(6, 'months').format('YYYY-MM-DD HH:mm:ss') |
||||
|
const eTime = moment().format('YYYY-MM-DD HH:mm:ss') |
||||
|
// let count={}
|
||||
|
let cRate = [] |
||||
|
for (let i = 5; i >= 0; i--) { |
||||
|
const currentTime = moment() |
||||
|
const startOfMonth = currentTime.subtract(i, 'months').startOf('month') |
||||
|
const startTime = startOfMonth.format('YYYY-MM-DD HH:mm:ss') |
||||
|
const endTime = startOfMonth.endOf('month').format('YYYY-MM-DD HH:mm:ss') |
||||
|
await dispatch(bigScreen.findPatrolRecords({ projectId: structArr.toString(), startTime, endTime })).then(res => { |
||||
|
if (res.success) { |
||||
|
const data = res.payload.data |
||||
|
// count[i] = { plan: data.planCount, done: data.done, rate:((data.done/data.planCount+data.done)*100).toFixed(2) }
|
||||
|
cRate.push( |
||||
|
Number(data.planCount + data.done > 0 ? ((data.done / (data.planCount + data.done)) * 100).toFixed(2) : 0) |
||||
|
) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
setCRate(cRate) |
||||
|
dispatch(bigScreen.findPatrolRate({ projectId: structArr.toString(), startTime: sTime, endTime: eTime })).then( |
||||
|
res => { |
||||
|
if (res.success) { |
||||
|
const data = res.payload.data |
||||
|
if (data && data.length) { |
||||
|
const repairObject = {} |
||||
|
for (let i = 0; i < 6; i++) { |
||||
|
const currentDate = moment().subtract(i, 'months') |
||||
|
const month = currentDate.month() + 1 |
||||
|
const year = currentDate.year() |
||||
|
repairObject[`${year}-${month}`] = { done: 0, quests: 0, ratio: 0 } |
||||
|
} |
||||
|
data.forEach(item => { |
||||
|
const createTime = moment(item.patrolRecordIssueHandles[0].createTime) |
||||
|
const month = createTime.month()+1 |
||||
|
const year = createTime.year() |
||||
|
const state = item.patrolRecordIssueHandles[0].state |
||||
|
if (state === 6) { |
||||
|
repairObject[`${year}-${month}`].done++ |
||||
|
} |
||||
|
|
||||
|
repairObject[`${year}-${month}`].quests++ |
||||
|
}) |
||||
|
//计算比例
|
||||
|
Object.values(repairObject).forEach(item => { |
||||
|
repair.push(item.quests === 0 ? 0 : Number((item.done / item.quests * 100).toFixed(2))); |
||||
|
}); |
||||
|
setRRate(repair) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
) |
||||
|
dispatch(bigScreen.countByProject({ projectId: structArr.toString()})).then(res=>{ |
||||
|
if(res.success){ |
||||
|
//[{},{},{},{},{},{},{},{}]||
|
||||
|
// [{id:1,issueHandleCount:1,patrolRecordCount:2},
|
||||
|
// {id:1,issueHandleCount:2,patrolRecordCount:3},
|
||||
|
// {id:1,issueHandleCount:3,patrolRecordCount:2},
|
||||
|
// {id:1,issueHandleCount:6,patrolRecordCount:4},
|
||||
|
// {id:1,issueHandleCount:7,patrolRecordCount:5},
|
||||
|
// {id:1,issueHandleCount:10,patrolRecordCount:6},
|
||||
|
// {id:1,issueHandleCount:11,patrolRecordCount:7},
|
||||
|
// {id:1,issueHandleCount:19,patrolRecordCount:9}]
|
||||
|
const data=res.payload.data |
||||
|
if(data.length>2){ |
||||
|
let problemstop = 0 |
||||
|
let problemsId = document.getElementById('left1'); |
||||
|
if (problems) clearInterval(problems) |
||||
|
if (problemsId) { |
||||
|
function problemstart () { |
||||
|
problems = setInterval(() => { |
||||
|
problemstop += 5 |
||||
|
problemsId.scrollTop = problemstop |
||||
|
if (problemsId.scrollTop >= problemsId.scrollHeight / 2) problemstop = 0, problemsId.scrollTop = problemstop |
||||
|
}, 500); |
||||
|
problemsId.onmouseover = () => clearInterval(problems) |
||||
|
} |
||||
|
problemsId.onmouseout = () => problemstart() |
||||
|
setTimeout(problemstart(), 1000); |
||||
|
} |
||||
|
} |
||||
|
if(data.length>10){ |
||||
|
setRank(data.slice(0,10)) |
||||
|
}else{ |
||||
|
setRank(data) |
||||
|
|
||||
|
} |
||||
|
setRankCopy(data) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
function generateMonthNames() { |
||||
|
const currentTime = moment() |
||||
|
const monthNames = [] |
||||
|
for (let i = 0; i < 6; i++) { |
||||
|
const currentMonth = currentTime.clone().subtract(i, 'months').format('MMMM') |
||||
|
monthNames.unshift(currentMonth) |
||||
|
} |
||||
|
return monthNames |
||||
|
} |
||||
|
|
||||
|
const getData = () => { |
||||
|
const structArr = JSON.parse(sessionStorage.getItem('user')).monitorObject |
||||
|
dispatch(bigScreen.findPatrolRecords({ projectId: structArr.toString(), startTime, endTime })).then(res => { |
||||
|
if (res.success) { |
||||
|
const data = res.payload.data |
||||
|
setPlan(data.planCount) |
||||
|
setDone(data.done) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
const selectTime = time => { |
||||
|
if (time === 'week') { |
||||
|
setPeriod('week') |
||||
|
setStartTime(moment().startOf('week').format('YYYY-MM-DD HH:mm:ss')) |
||||
|
setEndTime(moment().endOf('week').format('YYYY-MM-DD HH:mm:ss')) |
||||
|
} else { |
||||
|
setPeriod('month') |
||||
|
setStartTime(moment().startOf('month').format('YYYY-MM-DD HH:mm:ss')) |
||||
|
setEndTime(moment().endOf('month').format('YYYY-MM-DD HH:mm:ss')) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const topClick=(e)=>{ |
||||
|
switch (e) { |
||||
|
case 'perBottom': |
||||
|
const rs=rankCopy.sort((a,b)=>b.patrolRecordCount-a.patrolRecordCount) |
||||
|
if(rs.length>10){ |
||||
|
setRank(rs.slice(0,10)) |
||||
|
}else{ |
||||
|
setRank(rs) |
||||
|
} |
||||
|
setState(1) |
||||
|
break; |
||||
|
case 'perTop': |
||||
|
const rs1=rankCopy.sort((a,b)=>a.patrolRecordCount-b.patrolRecordCount) |
||||
|
if(rs1.length>10){ |
||||
|
setRank(rs1.slice(0,10)) |
||||
|
}else{ |
||||
|
setRank(rs1) |
||||
|
} |
||||
|
setState(0) |
||||
|
break; |
||||
|
case 'timeBottom': |
||||
|
const rs2=rankCopy.sort((a,b)=>b.issueHandleCount-a.issueHandleCount) |
||||
|
if(rs2.length>10){ |
||||
|
setRank(rs2.slice(0,10)) |
||||
|
}else{ |
||||
|
setRank(rs2) |
||||
|
} |
||||
|
setState(3) |
||||
|
break; |
||||
|
case 'timeTop': |
||||
|
const rs3=rankCopy.sort((a,b)=>a.issueHandleCount-b.issueHandleCount) |
||||
|
if(rs3.length>10){ |
||||
|
setRank(rs3.slice(0,10)) |
||||
|
}else{ |
||||
|
setRank(rs3) |
||||
|
} |
||||
|
setState(2) |
||||
|
break; |
||||
|
default: |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
return ( |
||||
|
<> |
||||
|
{/* 左一 */} |
||||
|
{/**backgroundImage: 'linear-gradient(269deg, #000080ff 0%, #1a0080ff 58%, #3d0080ff 100%)' */} |
||||
|
<div> |
||||
|
<div style={{ position: 'relative' }} className='contanier'> |
||||
|
<div |
||||
|
style={{ |
||||
|
display: 'flex', |
||||
|
justifyContent: 'space-between', |
||||
|
height: '2.6875rem', |
||||
|
background: 'url(/assets/bigScreen/cardHeader.png)', |
||||
|
backgroundSize: '100% 100%', |
||||
|
backgroundRepeat: 'no-repeat', |
||||
|
}}> |
||||
|
<div className='title'>巡检数据统计</div> |
||||
|
<div className='monthOrWeek'> |
||||
|
<span |
||||
|
style={{ color: period === 'week' ? '#6EECE9' : '#8FCFFF' }} |
||||
|
onClick={() => { |
||||
|
selectTime('week') |
||||
|
}}> |
||||
|
周 |
||||
|
</span> |
||||
|
| |
||||
|
<span |
||||
|
style={{ color: period === 'month' ? '#6EECE9' : '#8FCFFF' }} |
||||
|
onClick={() => { |
||||
|
selectTime('month') |
||||
|
}}> |
||||
|
月 |
||||
|
</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div |
||||
|
style={{ |
||||
|
width: '26.3125rem', |
||||
|
height: '9.5625rem', |
||||
|
display: 'flex', |
||||
|
justifyContent: 'center', |
||||
|
alignItems: 'center', |
||||
|
}}> |
||||
|
<img src='/assets/bigScreen/doneRate.png'></img> |
||||
|
</div> |
||||
|
<div className='rate' style={{ bottom: '6.5125rem', left: '11.875rem' }}> |
||||
|
{`${plan > 0 ? ((done / done + plan) * 100).toFixed(2) : 0}%`} |
||||
|
</div> |
||||
|
<div style={{ display: 'flex', justifyContent: 'center', marginTop: '.5rem' }}>当前巡检完成率</div> |
||||
|
<div style={{ display: 'flex', justifyContent: 'space-between' }}> |
||||
|
<div |
||||
|
style={{ |
||||
|
background: 'url(/assets/bigScreen/plan.png)', |
||||
|
width: '10.375rem', |
||||
|
height: '3.625rem', |
||||
|
position: 'relative', |
||||
|
marginLeft: '.7rem', |
||||
|
backgroundSize: '100% 100%', |
||||
|
}}> |
||||
|
<div |
||||
|
style={{ |
||||
|
position: 'absolute', |
||||
|
bottom: '1.7rem', |
||||
|
right: '2.35rem', |
||||
|
width: '3.75rem', |
||||
|
height: '.75rem', |
||||
|
textAlign: 'center', |
||||
|
}} |
||||
|
className='plan'> |
||||
|
计划巡检数 |
||||
|
</div> |
||||
|
<div |
||||
|
style={{ |
||||
|
position: 'absolute', |
||||
|
bottom: '.1044rem', |
||||
|
right: '2.35rem', |
||||
|
width: '3.75rem', |
||||
|
height: '1.375rem', |
||||
|
textAlign: 'center', |
||||
|
}} |
||||
|
className='number'> |
||||
|
{plan} |
||||
|
</div> |
||||
|
</div> |
||||
|
<div |
||||
|
style={{ |
||||
|
background: 'url(/assets/bigScreen/plan.png)', |
||||
|
width: '10.375rem', |
||||
|
height: '3.625rem', |
||||
|
position: 'relative', |
||||
|
marginLeft: '.7rem', |
||||
|
backgroundSize: '100% 100%', |
||||
|
marginRight: '.625rem', |
||||
|
}}> |
||||
|
<div |
||||
|
style={{ |
||||
|
position: 'absolute', |
||||
|
bottom: '1.7rem', |
||||
|
right: '1.75rem', |
||||
|
width: '4.75rem', |
||||
|
height: '.75rem', |
||||
|
textAlign: 'center', |
||||
|
}} |
||||
|
className='plan'> |
||||
|
已完成巡检数 |
||||
|
</div> |
||||
|
<div |
||||
|
style={{ |
||||
|
position: 'absolute', |
||||
|
bottom: '.1044rem', |
||||
|
right: '1.75rem', |
||||
|
width: '4.75rem', |
||||
|
height: '1.375rem', |
||||
|
textAlign: 'center', |
||||
|
}} |
||||
|
className='number'> |
||||
|
{done} |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
{/* 左二 */} |
||||
|
<div className='contanier' style={{ height: '17.8125rem' }}> |
||||
|
<div |
||||
|
style={{ |
||||
|
display: 'flex', |
||||
|
justifyContent: 'space-between', |
||||
|
height: '2.5rem', |
||||
|
background: 'url(/assets/bigScreen/cardHeader.png)', |
||||
|
backgroundSize: '100% 100%', |
||||
|
backgroundRepeat: 'no-repeat', |
||||
|
}}> |
||||
|
<div className='title'>巡检成效评估</div> |
||||
|
{/* <div className='monthOrWeek'>{'更多' + '>>'}</div> */} |
||||
|
</div> |
||||
|
<ReactEcharts |
||||
|
style={{ height: '13.4375rem', width: '25.2662rem' }} |
||||
|
option={{ |
||||
|
tooltip: { |
||||
|
trigger: 'axis', |
||||
|
axisPointer: { |
||||
|
type: 'shadow', |
||||
|
}, |
||||
|
}, |
||||
|
legend: { |
||||
|
right: 0, |
||||
|
textStyle: { color: '#CCE6FF' }, |
||||
|
}, |
||||
|
grid: { |
||||
|
left: '3%', |
||||
|
right: '4%', |
||||
|
bottom: '3%', |
||||
|
containLabel: true, |
||||
|
}, |
||||
|
xAxis: [ |
||||
|
{ |
||||
|
type: 'category', |
||||
|
data: months, |
||||
|
}, |
||||
|
], |
||||
|
yAxis: [ |
||||
|
{ |
||||
|
type: 'value', |
||||
|
name: '单位%', |
||||
|
}, |
||||
|
], |
||||
|
series: [ |
||||
|
{ |
||||
|
name: '巡检完成率', |
||||
|
nameTextStyle: { |
||||
|
color: ' #CCE6FF', |
||||
|
fontSize: 14, |
||||
|
fontFamily: 'SourceHanSansCN-Medium', |
||||
|
}, |
||||
|
type: 'bar', |
||||
|
stack: 'Search Engine', |
||||
|
// emphasis: {
|
||||
|
// focus: 'series'
|
||||
|
// },
|
||||
|
data: cRate, |
||||
|
}, |
||||
|
{ |
||||
|
name: '故障修复率', |
||||
|
type: 'bar', |
||||
|
stack: 'Search Engine', |
||||
|
// emphasis: {
|
||||
|
// focus: 'series'
|
||||
|
// },
|
||||
|
data: rRate, |
||||
|
}, |
||||
|
], |
||||
|
}}></ReactEcharts> |
||||
|
</div> |
||||
|
{/* 左三 */} |
||||
|
<div className='contanier'> |
||||
|
<div |
||||
|
style={{ |
||||
|
display: 'flex', |
||||
|
justifyContent: 'space-between', |
||||
|
height: '2.5rem', |
||||
|
background: 'url(/assets/bigScreen/cardHeader.png)', |
||||
|
backgroundSize: '100% 100%', |
||||
|
backgroundRepeat: 'no-repeat', |
||||
|
}}> |
||||
|
<div className='title'>巡检次数排名</div> |
||||
|
</div> |
||||
|
<div className='header' style={{ width: '24.3125rem' }}> |
||||
|
<div className='threeHeaderFontStyle'>序号</div> |
||||
|
<div className='threeHeaderFontStyle'>结构物</div> |
||||
|
<div className='threeHeaderFontStyle' style={{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 className='threeHeaderFontStyle'style={{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> |
||||
|
<div id='left1' style={{ width: '25.8125rem', height: '12rem', position: 'relative' }}> |
||||
|
|
||||
|
{rank.map((item,index)=>( |
||||
|
<div className='thridCardItem' style={{ width: '24.3125rem' }}> |
||||
|
<div className='index1'> |
||||
|
<div>{index+1}</div> |
||||
|
</div> |
||||
|
<div className='name1'>{item.name}</div> |
||||
|
<div className='num1'>{item.patrolRecordCount}</div> |
||||
|
<div className='quests1' style={{ ...normalFontColor }}> |
||||
|
{item.issueHandleCount} |
||||
|
</div> |
||||
|
</div> |
||||
|
))} |
||||
|
|
||||
|
|
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
function mapStateToProps(state) { |
||||
|
const { auth, global } = state |
||||
|
return { |
||||
|
clientHeight: global.clientHeight, |
||||
|
clientWidth: global.clientWidth, |
||||
|
actions: global.actions, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(Left) |
@ -0,0 +1,317 @@ |
|||||
|
import React, { useEffect, useState } from 'react' |
||||
|
import { Spin, Popconfirm, message, Button, Input, Progress } from 'antd' |
||||
|
import { connect } from 'react-redux' |
||||
|
import ProTable from '@ant-design/pro-table' |
||||
|
import moment from 'moment' |
||||
|
import ReactEcharts from 'echarts-for-react' |
||||
|
import '../style.less' |
||||
|
import AutoRollComponent from '../AutoRollComponent' |
||||
|
import PerfectScrollbar from 'perfect-scrollbar' |
||||
|
|
||||
|
let scrollbar |
||||
|
let diviceScrollbar |
||||
|
let rank |
||||
|
let device |
||||
|
const Right = props => { |
||||
|
const { dispatch, clientHeight, clientWidth, actions } = props |
||||
|
const { bigScreen } = actions |
||||
|
const questFontColor = { color: '#8f7a49' } //有问题的颜色
|
||||
|
const normalFontColor = { color: 'rgba(33, 106, 167)' } //正常的颜色
|
||||
|
const [deviceLists, setDeviceLists] = useState([]) |
||||
|
const [underGuarantee, setUnderGuarantee] = useState(0) |
||||
|
const [devicescount, setDevicesCount] = useState(0) |
||||
|
const [period, setPeriod] = useState('threeMonths') |
||||
|
const [startTime, setStartTime] = useState(moment().subtract(3, 'months').format('YYYY-MM-DD HH:mm:ss')) |
||||
|
const [endTime, setEndTime] = useState(moment().format('YYYY-MM-DD HH:mm:ss')) |
||||
|
const [projectName, setProjectName] = useState([]) |
||||
|
const [historyFaults, setHistoryFaults] = useState([]) |
||||
|
const [historyFaultsDone, setHistoryFaultsDone] = useState([]) |
||||
|
const [rankData, setRankData] = useState([]) |
||||
|
|
||||
|
//历史故障切换时间变化
|
||||
|
useEffect(() => { |
||||
|
const structArr = JSON.parse(sessionStorage.getItem('user')).monitorObject |
||||
|
dispatch(bigScreen.getHistoricalFaults({ projectId: structArr.toString(), startTime, endTime })).then(res => { |
||||
|
if (res.success) { |
||||
|
const data = res.payload.data |
||||
|
let nameArr = [] |
||||
|
let historyFaults = [] |
||||
|
let historyFaultsDone = [] |
||||
|
data.map(item => { |
||||
|
nameArr.push(item.name) |
||||
|
historyFaults.push(Number(item.count)) |
||||
|
historyFaultsDone.push(Number(item.bcount)) |
||||
|
}) |
||||
|
setProjectName(nameArr) |
||||
|
setHistoryFaults(historyFaults) |
||||
|
setHistoryFaultsDone(historyFaultsDone) |
||||
|
|
||||
|
} |
||||
|
}) |
||||
|
}, [period]) |
||||
|
|
||||
|
useEffect(() => { |
||||
|
scrollbar = new PerfectScrollbar('#right3', { suppressScrollX: true }) |
||||
|
const dom = document.getElementById('right3') |
||||
|
if (dom) { |
||||
|
scrollbar.update() |
||||
|
// dom.scrollTop = 0
|
||||
|
} |
||||
|
diviceScrollbar = new PerfectScrollbar('#right1', { suppressScrollX: true }) |
||||
|
const doms = document.getElementById('right1') |
||||
|
if (doms) { |
||||
|
diviceScrollbar.update() |
||||
|
// dom.scrollTop = 0
|
||||
|
} |
||||
|
getData() |
||||
|
}, []) |
||||
|
|
||||
|
const getData = () => { |
||||
|
const structArr = JSON.parse(sessionStorage.getItem('user')).monitorObject |
||||
|
dispatch(bigScreen.getDevices({ projectId: structArr.toString() })).then(res => { |
||||
|
if (res.success) { |
||||
|
const data = res.payload.data |
||||
|
setDeviceLists(data.rs) |
||||
|
setUnderGuarantee(data.underGuarantee) |
||||
|
setDevicesCount(data.count) |
||||
|
if(data.length>2){ |
||||
|
let problemstops = 0 |
||||
|
let problemsId = document.getElementById('right1'); |
||||
|
if (device) clearInterval(device) |
||||
|
if (problemsId) { |
||||
|
function problemstart () { |
||||
|
device = setInterval(() => { |
||||
|
problemstops += 5 |
||||
|
problemsId.scrollTop = problemstops |
||||
|
if (problemsId.scrollTop >= problemsId.scrollHeight / 2) problemstops = 0, problemsId.scrollTop = problemstops |
||||
|
}, 500); |
||||
|
problemsId.onmouseover = () => clearInterval(device) |
||||
|
} |
||||
|
problemsId.onmouseout = () => problemstart() |
||||
|
setTimeout(problemstart(), 1000); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
dispatch(bigScreen.getFaultsRank({ projectId: structArr.toString() })).then(res => { |
||||
|
if (res.success) { |
||||
|
//[{},{},{},{},{},{},{},{},{}] ||
|
||||
|
const data = res.payload.data |
||||
|
setRankData(data) |
||||
|
if(data.length>2){ |
||||
|
let problemstop = 0 |
||||
|
let problemsId = document.getElementById('right3'); |
||||
|
if (rank) clearInterval(rank) |
||||
|
if (problemsId) { |
||||
|
function problemstart () { |
||||
|
rank = setInterval(() => { |
||||
|
problemstop += 5 |
||||
|
problemsId.scrollTop = problemstop |
||||
|
if (problemsId.scrollTop >= problemsId.scrollHeight / 2) problemstop = 0, problemsId.scrollTop = problemstop |
||||
|
}, 500); |
||||
|
problemsId.onmouseover = () => clearInterval(rank) |
||||
|
} |
||||
|
problemsId.onmouseout = () => problemstart() |
||||
|
setTimeout(problemstart(), 1000); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
console.log('rank', rankData) |
||||
|
const selectTime = time => { |
||||
|
if (time === 'threeMonths') { |
||||
|
setPeriod('threeMonths') |
||||
|
setStartTime(moment().subtract(3, 'months').format('YYYY-MM-DD HH:mm:ss')) |
||||
|
} else if (time === 'halfYear') { |
||||
|
setPeriod('halfYear') |
||||
|
setStartTime(moment().subtract(6, 'months').format('YYYY-MM-DD HH:mm:ss')) |
||||
|
} else { |
||||
|
setPeriod('oneYear') |
||||
|
setStartTime(moment().subtract(12, 'months').format('YYYY-MM-DD HH:mm:ss')) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return ( |
||||
|
<> |
||||
|
<div> |
||||
|
{/* 右一 */} |
||||
|
<div className='contanier1'> |
||||
|
<div className='cardHeader'> |
||||
|
<div className='title'>设备数据总览</div> |
||||
|
<div className='monthOrWeek'>{'更多' + '>>'}</div> |
||||
|
</div> |
||||
|
<div className='right1bg'> |
||||
|
<img src='/assets/bigScreen/qc.png'></img> |
||||
|
</div> |
||||
|
<div className='content'> |
||||
|
<div> |
||||
|
<div className='qcNum numFontStyle'> |
||||
|
{underGuarantee} <span className='ge'>个</span> |
||||
|
</div> |
||||
|
<div className='qcDescribe describeFontStyle'>质保数</div> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div className='centerNum'> |
||||
|
{(((devicescount - underGuarantee) / devicescount) * 100).toFixed(0) || 0}% |
||||
|
</div> |
||||
|
<div className='pDescribe pLocation'>质保期比例</div> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div className='deviceNum numFontStyle'> |
||||
|
{devicescount} <span className='ge'>个</span> |
||||
|
</div> |
||||
|
<div className='deviceDescribe describeFontStyle'>设备总数</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div id='right1' style={{width:'25.25rem',height:'9.2875rem',position:'relative'}}> |
||||
|
{deviceLists?.map(item => ( |
||||
|
<div className='percent'> |
||||
|
{/* <img src='/assets/bigScreen/arrow.png'></img> */} |
||||
|
<div className='describe'> {item.type}</div> |
||||
|
<Progress |
||||
|
format={percent => (percent === 100 ? '100%' : `${percent}`)} |
||||
|
strokeColor={'#6EECE9'} |
||||
|
trailColor={'#0B4A7A'} |
||||
|
percent={(item.count / devicescount).toFixed(2) * 100} |
||||
|
/> |
||||
|
</div> |
||||
|
))} |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
{/* 右2 */} |
||||
|
<div className='contanier' style={{ height: '17.8125rem' }}> |
||||
|
<div className='cardHeader'> |
||||
|
<div className='title'>历史故障统计</div> |
||||
|
<div className='monthOrWeek'> |
||||
|
<span |
||||
|
style={{ color: period === 'threeMonths' ? '#6EECE9' : '#8FCFFF' }} |
||||
|
onClick={() => { |
||||
|
selectTime('threeMonths') |
||||
|
}}> |
||||
|
三个月 |
||||
|
</span> |
||||
|
| |
||||
|
<span |
||||
|
style={{ color: period === 'halfYear' ? '#6EECE9' : '#8FCFFF' }} |
||||
|
onClick={() => { |
||||
|
selectTime('halfYear') |
||||
|
}}> |
||||
|
{' '} |
||||
|
半年 |
||||
|
</span> |
||||
|
| |
||||
|
<span |
||||
|
style={{ color: period === 'oneYear' ? '#6EECE9' : '#8FCFFF' }} |
||||
|
onClick={() => { |
||||
|
selectTime('oneYear') |
||||
|
}}> |
||||
|
{' '} |
||||
|
一年 |
||||
|
</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
{projectName.length ? ( |
||||
|
<ReactEcharts |
||||
|
style={{ height: '13.4375rem', width: '25.2662rem' }} |
||||
|
option={{ |
||||
|
tooltip: { |
||||
|
trigger: 'axis', |
||||
|
axisPointer: { |
||||
|
type: 'shadow', |
||||
|
}, |
||||
|
}, |
||||
|
legend: { |
||||
|
right: 0, |
||||
|
textStyle: { color: '#CCE6FF' }, |
||||
|
}, |
||||
|
grid: { |
||||
|
left: '3%', |
||||
|
right: '4%', |
||||
|
bottom: '3%', |
||||
|
containLabel: true, |
||||
|
}, |
||||
|
xAxis: [ |
||||
|
{ |
||||
|
type: 'category', |
||||
|
data: projectName, |
||||
|
}, |
||||
|
], |
||||
|
yAxis: [ |
||||
|
{ |
||||
|
type: 'value', |
||||
|
name: '单位次', |
||||
|
}, |
||||
|
], |
||||
|
series: [ |
||||
|
{ |
||||
|
name: '故障数', |
||||
|
nameTextStyle: { |
||||
|
color: ' #CCE6FF', |
||||
|
fontSize: 14, |
||||
|
fontFamily: 'SourceHanSansCN-Medium', |
||||
|
}, |
||||
|
type: 'line', |
||||
|
stack: 'Search Engine', |
||||
|
// emphasis: {
|
||||
|
// focus: 'series'
|
||||
|
// },
|
||||
|
data: historyFaults, |
||||
|
}, |
||||
|
{ |
||||
|
name: '已闭环', |
||||
|
type: 'line', |
||||
|
stack: 'Search Engine', |
||||
|
// emphasis: {
|
||||
|
// focus: 'series'
|
||||
|
// },
|
||||
|
data: historyFaultsDone, |
||||
|
}, |
||||
|
], |
||||
|
}}></ReactEcharts> |
||||
|
) : ( |
||||
|
'暂无数据' |
||||
|
)} |
||||
|
</div> |
||||
|
{/*右三 */} |
||||
|
<div className='contanier'> |
||||
|
<div className='cardHeader'> |
||||
|
<div className='title'>设备故障排名</div> |
||||
|
</div> |
||||
|
<div className='header1'> |
||||
|
<div className='threeHeaderFontStyle'>序号</div> |
||||
|
<div className='threeHeaderFontStyle'>设备名称</div> |
||||
|
<div className='threeHeaderFontStyle'>故障发生次数</div> |
||||
|
</div> |
||||
|
<div id='right3' style={{ width: '25.8125rem', height: '12rem', position: 'relative' }}> |
||||
|
{rankData.map((item, index) => ( |
||||
|
<div className='thridCardItem' style={{ width: '24.3125rem' }}> |
||||
|
<div className='index'> |
||||
|
<div>{index + 1}</div> |
||||
|
</div> |
||||
|
<div className='name'>{item.name}</div> |
||||
|
<div className='quests' style={{ ...normalFontColor }}> |
||||
|
{item.count} |
||||
|
</div> |
||||
|
</div> |
||||
|
))} |
||||
|
|
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
function mapStateToProps(state) { |
||||
|
const { auth, global, device } = state |
||||
|
return { |
||||
|
clientHeight: global.clientHeight, |
||||
|
clientWidth: global.clientWidth, |
||||
|
actions: global.actions, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(Right) |
@ -0,0 +1,72 @@ |
|||||
|
import React, { useEffect, useState } from 'react' |
||||
|
import { Spin, Popconfirm, message, Button, Input } from 'antd' |
||||
|
import { connect } from 'react-redux' |
||||
|
import ProTable from '@ant-design/pro-table' |
||||
|
import moment from 'moment' |
||||
|
import ReactEcharts from 'echarts-for-react' |
||||
|
import PerfectScrollbar from 'perfect-scrollbar'; |
||||
|
import '../style.less' |
||||
|
import AutoRollComponent from '../AutoRollComponent' |
||||
|
import Left from './left'; |
||||
|
import Right from './right'; |
||||
|
|
||||
|
let scrollbar |
||||
|
|
||||
|
const Run = props => { |
||||
|
const { clientHeight, clientWidth } = props |
||||
|
const questFontColor = { color: '#8f7a49' }//有问题的颜色
|
||||
|
const normalFontColor = { color: 'rgba(33, 106, 167)' }//正常的颜色
|
||||
|
const [beginHeight, setBeginHeight] = useState(window.innerHeight); //
|
||||
|
const [isFullScreen, setIsFullScreen] = useState(false); //是否全屏
|
||||
|
|
||||
|
window.onresize = () => { |
||||
|
console.log('x1111111',) |
||||
|
// 全屏
|
||||
|
if (beginHeight!==window.innerHeight) { |
||||
|
console.log('全屏') |
||||
|
setIsFullScreen(true) |
||||
|
} |
||||
|
// 不是全屏
|
||||
|
else { |
||||
|
console.log('不全屏') |
||||
|
setIsFullScreen(false) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
useEffect(() => { |
||||
|
// scrollbar = new PerfectScrollbar('#left1', { suppressScrollX: true });
|
||||
|
// const dom = document.getElementById('left1');
|
||||
|
// console.log('dom', dom)
|
||||
|
// if (dom) {
|
||||
|
// scrollbar.update();
|
||||
|
// dom.scrollTop = 0;
|
||||
|
// }
|
||||
|
}, []) |
||||
|
|
||||
|
// useEffect(()=>{
|
||||
|
|
||||
|
// })
|
||||
|
|
||||
|
return ( |
||||
|
<> |
||||
|
<div style={{display:'flex',}}> |
||||
|
<Left isFullScreen={isFullScreen}></Left> |
||||
|
<Right isFullScreen={isFullScreen}></Right> |
||||
|
|
||||
|
</div> |
||||
|
</> |
||||
|
|
||||
|
) |
||||
|
} |
||||
|
|
||||
|
function mapStateToProps(state) { |
||||
|
const { auth, global, device } = state |
||||
|
return { |
||||
|
clientHeight: global.clientHeight, |
||||
|
clientWidth: global.clientWidth, |
||||
|
actions: global.actions, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(Run) |
@ -0,0 +1,213 @@ |
|||||
|
import React, { useEffect, useState } from 'react' |
||||
|
import { Spin, Popconfirm, message, Button, Input, Calendar, Col, Radio, Row, Select, Typography } from 'antd' |
||||
|
|
||||
|
import { connect } from 'react-redux' |
||||
|
import ProTable from '@ant-design/pro-table' |
||||
|
import moment from 'moment' |
||||
|
import ReactEcharts from 'echarts-for-react' |
||||
|
import PerfectScrollbar from 'perfect-scrollbar'; |
||||
|
import './style.less' |
||||
|
import AutoRollComponent from '../AutoRollComponent' |
||||
|
|
||||
|
|
||||
|
let scrollbar |
||||
|
|
||||
|
const Left = props => { |
||||
|
const { clientHeight, clientWidth,isFullScreen} = props |
||||
|
const questFontColor = { color: '#8f7a49' }//有问题的颜色
|
||||
|
const normalFontColor = { color: 'rgba(33, 106, 167)' }//正常的颜色
|
||||
|
|
||||
|
|
||||
|
// useEffect(()=>{
|
||||
|
|
||||
|
// })
|
||||
|
const onPanelChange = (value, mode) => { |
||||
|
console.log('value1', value); |
||||
|
}; |
||||
|
const defaultDate = moment({ year: moment().year(), month: moment().month() }); |
||||
|
|
||||
|
return ( |
||||
|
<> |
||||
|
<div > |
||||
|
{/* 左一 */} |
||||
|
<div className='left1Container'> |
||||
|
<Calendar |
||||
|
validRange={[moment(moment()).startOf('month'), moment(moment()).endOf('month')]} |
||||
|
fullscreen={false} |
||||
|
headerRender={({ value, type, onChange, onTypeChange }) => { |
||||
|
const start = 0; |
||||
|
const end = 12; |
||||
|
const monthOptions = []; |
||||
|
const current = value.clone(); |
||||
|
const localeData = value.localeData(); |
||||
|
const months = []; |
||||
|
for (let i = 0; i < 12; i++) { |
||||
|
current.month(i); |
||||
|
months.push(localeData.monthsShort(current)); |
||||
|
} |
||||
|
for (let i = start; i < end; i++) { |
||||
|
monthOptions.push( |
||||
|
<Select.Option key={i} value={i} className="month-item"> |
||||
|
{months[i]} |
||||
|
</Select.Option>, |
||||
|
); |
||||
|
} |
||||
|
const year = value.year(); |
||||
|
const month = value.month(); |
||||
|
const options = []; |
||||
|
for (let i = year - 10; i < year + 10; i += 1) { |
||||
|
// for (let j = 0; j < 12; j++) {
|
||||
|
options.push( |
||||
|
<Select.Option key={i} value={i} className="year-item"> |
||||
|
{`${i}年`} |
||||
|
</Select.Option>) |
||||
|
// }
|
||||
|
} |
||||
|
return ( |
||||
|
<div className='calendarHeader'> |
||||
|
<div className='cardHeader'> |
||||
|
<div className='title' >巡检数据统计</div> |
||||
|
</div> |
||||
|
{/* <Typography.Title level={4}>巡检数据统计</Typography.Title> */} |
||||
|
<Row gutter={8}> |
||||
|
<Col> |
||||
|
<Select |
||||
|
size="small" |
||||
|
dropdownMatchSelectWidth={false} |
||||
|
className="my-year-select" |
||||
|
value={moment().format('yyy-MM')} |
||||
|
onChange={(newYear) => { |
||||
|
console.log('x11112', newYear) |
||||
|
const now = value.clone().year(newYear); |
||||
|
onChange(now); |
||||
|
}} |
||||
|
> |
||||
|
{options} |
||||
|
</Select> |
||||
|
</Col> |
||||
|
</Row> |
||||
|
</div> |
||||
|
); |
||||
|
}} |
||||
|
onPanelChange={onPanelChange} |
||||
|
/> |
||||
|
</div> |
||||
|
{/* 左二 */} |
||||
|
<div className='left1Container'> |
||||
|
<div className='cardHeader'> |
||||
|
<div className='title' >本周巡检统计</div> |
||||
|
</div> |
||||
|
<div className='row'> |
||||
|
<div > |
||||
|
<div className='smallP'> |
||||
|
<div style={{background:'url(/assets/bigScreen/ying.png) 0% 0% / 100% 100% no-repeat'}}></div> |
||||
|
<div className='describe1'>本周应检</div> |
||||
|
</div> |
||||
|
<span className='numbers'>100</span><span>个</span> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div className='smallP'> |
||||
|
<div style={{background:'url(/assets/bigScreen/yij.png) 0% 0% / 100% 100% no-repeat',}}></div> |
||||
|
<div className='describe1'>本周已检</div> |
||||
|
</div> |
||||
|
<span className='numbers'>100</span><span>个</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div className='row'> |
||||
|
<div > |
||||
|
<div className='smallP'> |
||||
|
<div style={{background:'url(/assets/bigScreen/daij.png) 0% 0% / 100% 100% no-repeat',}}></div> |
||||
|
<div className='describe1'>本周待验</div> |
||||
|
</div> |
||||
|
<span className='numbers'>100</span><span>个</span> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div className='smallP'> |
||||
|
<div style={{background:'url(/assets/bigScreen/daic.png) 0% 0% / 100% 100% no-repeat',}}></div> |
||||
|
<div className='describe1'>待处理问题</div> |
||||
|
</div> |
||||
|
<span className='numbers'>100</span><span>个</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div className='row'> |
||||
|
<div > |
||||
|
<div className='smallP'> |
||||
|
<div style={{background:'url(/assets/bigScreen/yic.png) 0% 0% / 100% 100% no-repeat',}}></div> |
||||
|
<div className='describe1'>已处理问题</div> |
||||
|
</div> |
||||
|
<span className='numbers'>100</span><span>个</span> |
||||
|
</div> |
||||
|
<div className='last'> |
||||
|
<div className='smallP'> |
||||
|
<div></div> |
||||
|
<div className='describe1'>待处理问题</div> |
||||
|
</div> |
||||
|
<span className='numbers'>100</span><span>个</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
{/* 左三 */} |
||||
|
<div className='left1Container'> |
||||
|
<div className='cardHeader'> |
||||
|
<div className='title' >已处理问题</div> |
||||
|
</div> |
||||
|
<div className={'pieChartfs'}> |
||||
|
<ReactEcharts |
||||
|
style={{ height: !isFullScreen?'13.4375rem':'18.4375rem', width: '25.2662rem' }} |
||||
|
option={{ |
||||
|
tooltip: { |
||||
|
trigger: 'axis', |
||||
|
axisPointer: { |
||||
|
type: 'shadow', |
||||
|
}, |
||||
|
}, |
||||
|
// legend: {
|
||||
|
// right: 0,
|
||||
|
// textStyle: { color: '#CCE6FF' }
|
||||
|
// },
|
||||
|
grid: { |
||||
|
left: '3%', |
||||
|
right: '4%', |
||||
|
bottom: '3%', |
||||
|
containLabel: true, |
||||
|
}, |
||||
|
|
||||
|
|
||||
|
series: [ |
||||
|
{ |
||||
|
name: 'Access From', |
||||
|
type: 'pie', |
||||
|
radius: '50%', |
||||
|
data: [ |
||||
|
{ value: 1048, name: '严重' }, |
||||
|
{ value: 735, name: '中等' }, |
||||
|
{ value: 580, name: '轻微' }, |
||||
|
], |
||||
|
emphasis: { |
||||
|
itemStyle: { |
||||
|
shadowBlur: 10, |
||||
|
shadowOffsetX: 0, |
||||
|
shadowColor: 'rgba(0, 0, 0, 0.5)' |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
}}></ReactEcharts> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</> |
||||
|
|
||||
|
) |
||||
|
} |
||||
|
|
||||
|
function mapStateToProps(state) { |
||||
|
const { auth, global, device } = state |
||||
|
return { |
||||
|
clientHeight: global.clientHeight, |
||||
|
clientWidth: global.clientWidth, |
||||
|
actions: global.actions, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(Left) |
@ -0,0 +1,242 @@ |
|||||
|
import React, { useEffect, useState } from 'react' |
||||
|
import { Spin, Popconfirm, message, Button, Input, Progress } from 'antd'; |
||||
|
import { connect } from 'react-redux'; |
||||
|
import ProTable from '@ant-design/pro-table'; |
||||
|
import moment from 'moment'; |
||||
|
import PerfectScrollbar from 'perfect-scrollbar'; |
||||
|
import ReactEcharts from 'echarts-for-react' |
||||
|
import '../style.less' |
||||
|
|
||||
|
|
||||
|
let scrollbar |
||||
|
|
||||
|
const Right = (props) => { |
||||
|
const { clientHeight, clientWidth,isFullScreen } = props |
||||
|
const [beginHeight, setBeginHeight] = useState(window.innerHeight); //
|
||||
|
// const [isFullScreen, setIsFullScreen] = useState(false); //是否全屏
|
||||
|
const [index,setIndex]=useState('1')//默认第一个tab
|
||||
|
|
||||
|
useEffect(() => { |
||||
|
|
||||
|
}, []) |
||||
|
useEffect(()=>{ |
||||
|
scrollbar = new PerfectScrollbar('#redcordContent', { suppressScrollX: true }); |
||||
|
const dom = document.getElementById('redcordContent'); |
||||
|
console.log('dom', dom) |
||||
|
if (dom) { |
||||
|
scrollbar.update(); |
||||
|
dom.scrollTop = 0; |
||||
|
} |
||||
|
},[window.innerHeight]) |
||||
|
|
||||
|
|
||||
|
let header = [ |
||||
|
{ |
||||
|
name: '指挥中心' |
||||
|
}, |
||||
|
{ |
||||
|
name: '管廊本体' |
||||
|
}, |
||||
|
{ |
||||
|
name: '电梯系统' |
||||
|
}, |
||||
|
{ |
||||
|
name: '供配电系统' |
||||
|
}, |
||||
|
{ |
||||
|
name: '防雷与接地系统' |
||||
|
}, |
||||
|
{ |
||||
|
name: '燃气仓' |
||||
|
}, |
||||
|
{ |
||||
|
name: '给水仓' |
||||
|
}, |
||||
|
{ |
||||
|
name: '安防系统' |
||||
|
}, |
||||
|
{ |
||||
|
name: '高压电力仓' |
||||
|
}, |
||||
|
] |
||||
|
//巡检记录表头
|
||||
|
let recordHeader=[ |
||||
|
{name:'结构物名称'}, |
||||
|
{name:'上报人'}, |
||||
|
{name:'上报时间'}, |
||||
|
{name:'点位名称'}, |
||||
|
{name:'问题来源'}, |
||||
|
{name:'严重等级'}, |
||||
|
{name:'当前状态'}, |
||||
|
|
||||
|
] |
||||
|
|
||||
|
const ck=(index)=>{ |
||||
|
setIndex(index) |
||||
|
} |
||||
|
return <> |
||||
|
<div> |
||||
|
{/* 右边的抬头 */} |
||||
|
<div className='runHeader'> |
||||
|
{header.map(item => { |
||||
|
switch (item.name) { |
||||
|
case '指挥中心': |
||||
|
return <div className={index === '1' ? 'bgSelectedStyle' : 'bgUnselectedStyle'} |
||||
|
onClick={()=>{ck('1')}}>{item.name+`(${1})`}</div> |
||||
|
case '管廊本体': |
||||
|
return <div className={index === '2' ? 'bgSelectedStyle' : 'bgUnselectedStyle'} |
||||
|
onClick={()=>{ck('2')}}>{item.name+`(${1})`}</div> |
||||
|
case '电梯系统': |
||||
|
return <div className={index === '3' ? 'bgSelectedStyle' : 'bgUnselectedStyle'} |
||||
|
onClick={()=>{ck('3')}}>{item.name+`(${1})`}</div> |
||||
|
case '供配电系统': |
||||
|
return <div className={index === '4' ? 'bgSelectedStyle' : 'bgUnselectedStyle'} |
||||
|
onClick={()=>{ck('4')}}>{item.name+`(${1})`}</div> |
||||
|
case '防雷与接地系统': |
||||
|
return <div className={index === '5' ? 'bgSelectedStyle' : 'bgUnselectedStyle'} |
||||
|
onClick={()=>{ck('5')}}>{item.name+`(${1})`}</div> |
||||
|
case '燃气仓': |
||||
|
return <div className={index === '6' ? 'bgSelectedStyle' : 'bgUnselectedStyle'} |
||||
|
onClick={()=>{ck('6')}}>{item.name+`(${1})`}</div> |
||||
|
case '给水仓': |
||||
|
return <div className={index === '7' ? 'bgSelectedStyle' : 'bgUnselectedStyle'} |
||||
|
onClick={()=>{ck('7')}}>{item.name+`(${1})`}</div> |
||||
|
case '安防系统': |
||||
|
return <div className={index === '8' ? 'bgSelectedStyle' : 'bgUnselectedStyle'} |
||||
|
onClick={()=>{ck('8')}}>{item.name+`(${1})`}</div> |
||||
|
case '管廊本体': |
||||
|
return <div className={index === '9' ? 'bgSelectedStyle' : 'bgUnselectedStyle'} |
||||
|
onClick={()=>{ck('9')}}>{item.name+`(${1})`}</div> |
||||
|
case '高压电力仓': |
||||
|
return <div className={index === '10' ? 'bgSelectedStyle' : 'bgUnselectedStyle'} |
||||
|
onClick={()=>{ck('10')}}>{item.name+`(${1})`}</div> |
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
})} |
||||
|
</div> |
||||
|
{/* 中间的图片 */} |
||||
|
<div className='bigiImg'> |
||||
|
<img src='/assets/bigScreen/bigImg.png' className='bigiImg'></img> |
||||
|
</div> |
||||
|
{/* 巡检记录 */} |
||||
|
<div className='recordHeader'> |
||||
|
{recordHeader.map(item=>(<div className='recordTitle'>{item.name}</div>))} |
||||
|
</div> |
||||
|
<div id='redcordContent' className={isFullScreen?'fullStyle':'noFullStyle'} style={{ width: '88.6875rem', position: 'relative' }}> |
||||
|
<div className='redcordContent'> |
||||
|
<div>指挥中心</div> |
||||
|
<div>李一一</div> |
||||
|
<div>2023-11-02 09:23:35</div> |
||||
|
<div>燃气仓6仓</div> |
||||
|
<div>巡检上报</div> |
||||
|
<div>轻微</div> |
||||
|
<div>待制定计划</div> |
||||
|
|
||||
|
</div> |
||||
|
<div className='redcordContent'> |
||||
|
<div>指挥中心</div> |
||||
|
<div>李一一</div> |
||||
|
<div>2023-11-02 09:23:35</div> |
||||
|
<div>燃气仓6仓</div> |
||||
|
<div>巡检上报</div> |
||||
|
<div>轻微</div> |
||||
|
<div>待制定计划</div> |
||||
|
|
||||
|
</div> |
||||
|
<div className='redcordContent'> |
||||
|
<div>指挥中心</div> |
||||
|
<div>李一一</div> |
||||
|
<div>2023-11-02 09:23:35</div> |
||||
|
<div>燃气仓6仓</div> |
||||
|
<div>巡检上报</div> |
||||
|
<div>轻微</div> |
||||
|
<div>待制定计划</div> |
||||
|
|
||||
|
</div> |
||||
|
<div className='redcordContent'> |
||||
|
<div>指挥中心</div> |
||||
|
<div>李一一</div> |
||||
|
<div>2023-11-02 09:23:35</div> |
||||
|
<div>燃气仓6仓</div> |
||||
|
<div>巡检上报</div> |
||||
|
<div>轻微</div> |
||||
|
<div>待制定计划</div> |
||||
|
|
||||
|
</div> |
||||
|
<div className='redcordContent'> |
||||
|
<div>指挥中心</div> |
||||
|
<div>李一一</div> |
||||
|
<div>2023-11-02 09:23:35</div> |
||||
|
<div>燃气仓6仓</div> |
||||
|
<div>巡检上报</div> |
||||
|
<div>轻微</div> |
||||
|
<div>待制定计划</div> |
||||
|
</div> |
||||
|
<div className='redcordContent'> |
||||
|
<div>指挥中心</div> |
||||
|
<div>李一一</div> |
||||
|
<div>2023-11-02 09:23:35</div> |
||||
|
<div>燃气仓6仓</div> |
||||
|
<div>巡检上报</div> |
||||
|
<div>轻微</div> |
||||
|
<div>待制定计划</div> |
||||
|
</div> |
||||
|
<div className='redcordContent'> |
||||
|
<div>指挥中心</div> |
||||
|
<div>李一一</div> |
||||
|
<div>2023-11-02 09:23:35</div> |
||||
|
<div>燃气仓6仓</div> |
||||
|
<div>巡检上报</div> |
||||
|
<div>轻微</div> |
||||
|
<div>待制定计划</div> |
||||
|
</div> |
||||
|
<div className='redcordContent'> |
||||
|
<div>指挥中心</div> |
||||
|
<div>李一一</div> |
||||
|
<div>2023-11-02 09:23:35</div> |
||||
|
<div>燃气仓6仓</div> |
||||
|
<div>巡检上报</div> |
||||
|
<div>轻微</div> |
||||
|
<div>待制定计划</div> |
||||
|
</div> |
||||
|
<div className='redcordContent'> |
||||
|
<div>指挥中心</div> |
||||
|
<div>李一一</div> |
||||
|
<div>2023-11-02 09:23:35</div> |
||||
|
<div>燃气仓6仓</div> |
||||
|
<div>巡检上报</div> |
||||
|
<div>轻微</div> |
||||
|
<div>待制定计划</div> |
||||
|
</div> |
||||
|
<div className='redcordContent'> |
||||
|
<div>指挥中心最后</div> |
||||
|
<div>李一一</div> |
||||
|
<div>2023-11-02 09:23:35</div> |
||||
|
<div>燃气仓6仓</div> |
||||
|
<div>巡检上报</div> |
||||
|
<div>轻微</div> |
||||
|
<div>待制定计划</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</> |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
function mapStateToProps(state) { |
||||
|
const { auth, global, device } = state; |
||||
|
return { |
||||
|
clientHeight: global.clientHeight, |
||||
|
clientWidth: global.clientWidth, |
||||
|
actions: global.actions, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(Right) |
||||
|
|
@ -0,0 +1,232 @@ |
|||||
|
.left1Container { |
||||
|
width: 26.3125rem; |
||||
|
height: 17.8125rem; |
||||
|
margin-top: 1.5rem; |
||||
|
.pieChartfs{ |
||||
|
text-align: center; |
||||
|
height: 17.8125rem; |
||||
|
line-height: 17.8125rem |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
.cardHeader { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
height: 2.5rem; |
||||
|
} |
||||
|
|
||||
|
.title { |
||||
|
// width: 122px; |
||||
|
height: 1.3125rem; |
||||
|
font-family: PangMenZhengDao; |
||||
|
font-size: 1.3125rem; |
||||
|
color: #ffffff; |
||||
|
// letter-spacing: 0.95px; |
||||
|
margin-top: 0.4375rem; |
||||
|
margin-left: 2.375rem; |
||||
|
line-height: 1.5rem; |
||||
|
} |
||||
|
|
||||
|
.calendarHeader { |
||||
|
background: url(/assets/bigScreen/cardHeader.png); |
||||
|
background-size: 100% 100%; |
||||
|
background-repeat: no-repeat; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
} |
||||
|
|
||||
|
.ant-row { |
||||
|
background: transparent !important; |
||||
|
// background: url(/assets/bigScreen/cardHeader.png) !important; |
||||
|
// background-size: 100% 100%; |
||||
|
background-repeat: no-repeat; |
||||
|
line-height: 2.5rem; |
||||
|
margin-right: 0.5rem !important; |
||||
|
} |
||||
|
|
||||
|
.ant-picker-calendar { |
||||
|
background: transparent !important; |
||||
|
} |
||||
|
|
||||
|
.ant-picker-calendar { |
||||
|
.ant-picker-panel { |
||||
|
// width: 3.4194rem; |
||||
|
// height: 2.3531rem; |
||||
|
background: #93c6f824 !important; |
||||
|
border-radius: 0 0 5rem 4.75rem 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.ant-picker-content th { |
||||
|
color: #ffffff !important; |
||||
|
} |
||||
|
|
||||
|
.ant-picker-cell { |
||||
|
.ant-picker-cell-inner { |
||||
|
.ant-picker-calendar-date-value { |
||||
|
color: #ffffff !important; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.smallP { |
||||
|
display: flex; |
||||
|
align-items: flex-end; |
||||
|
} |
||||
|
|
||||
|
.describe1 { |
||||
|
width: 6.1875rem; |
||||
|
height: 1.5rem; |
||||
|
font-family: SourceHanSansSC-Regular; |
||||
|
font-weight: 400; |
||||
|
font-size: 1rem; |
||||
|
color: #add7ff; |
||||
|
letter-spacing: 0.0456rem; |
||||
|
margin-left: 0.5rem; |
||||
|
} |
||||
|
|
||||
|
.smallP :nth-child(1) { |
||||
|
|
||||
|
background: url(/assets/bigScreen/ying.png); |
||||
|
background-size: 100% 100%; |
||||
|
background-repeat: no-repeat; |
||||
|
width: 2.0625rem; |
||||
|
height: 2.0625rem; |
||||
|
margin-top: 1rem; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
.row { |
||||
|
display: flex; |
||||
|
justify-content: space-around; |
||||
|
} |
||||
|
|
||||
|
.numbers { |
||||
|
height: 1rem; |
||||
|
font-family: D-DIN-Bold; |
||||
|
font-weight: 700; |
||||
|
font-size: 1rem; |
||||
|
color: #0fffee; |
||||
|
letter-spacing: 0.0456rem; |
||||
|
padding-left: 3.5rem; |
||||
|
} |
||||
|
|
||||
|
.numbers+span { |
||||
|
padding-left: 3.5rem; |
||||
|
} |
||||
|
|
||||
|
.last { |
||||
|
visibility: hidden; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
.runHeader { |
||||
|
display: flex; |
||||
|
justify-content: space-around; |
||||
|
padding-top: 2rem; |
||||
|
padding-left: 2rem; |
||||
|
} |
||||
|
|
||||
|
.bgUnselectedStyle { |
||||
|
background: url(/assets/bigScreen/runHeaderSelect.png); |
||||
|
background-repeat: no-repeat; |
||||
|
background-size: 100% 100%; |
||||
|
width: 10rem; |
||||
|
height: 4rem; |
||||
|
padding-left: 2.4rem; |
||||
|
line-height: 3.5rem; |
||||
|
cursor: pointer; |
||||
|
font-family: SourceHanSansSC-Regular; |
||||
|
font-size: 0.8rem; |
||||
|
color: #ADD7FF; |
||||
|
letter-spacing: .0231rem; |
||||
|
} |
||||
|
|
||||
|
.bgSelectedStyle { |
||||
|
background: url(/assets/bigScreen/runHeaderSelected.png); |
||||
|
background-repeat: no-repeat; |
||||
|
background-size: 100% 100%; |
||||
|
width: 10rem; |
||||
|
height: 4rem; |
||||
|
padding-left: 2.4rem; |
||||
|
line-height: 3.5rem; |
||||
|
cursor: pointer; |
||||
|
font-family: SourceHanSansSC-Regular; |
||||
|
font-size: 0.8rem; |
||||
|
color: #FFFFFF; |
||||
|
letter-spacing: .0231rem; |
||||
|
} |
||||
|
|
||||
|
.bigiImg { |
||||
|
width: 88.6594rem; |
||||
|
height: 33.5rem; |
||||
|
// padding-top: 0.5rem; |
||||
|
margin-left: 2rem; |
||||
|
// color: red; |
||||
|
// background: url(/assets/bigScreen/bigImg.png) no-repeat; |
||||
|
// background-size: 100% 100%; |
||||
|
} |
||||
|
|
||||
|
.recordHeader { |
||||
|
width: 88.6875rem; |
||||
|
height: 2.5rem; |
||||
|
background: url(/assets/bigScreen/cardHeader.png) no-repeat; |
||||
|
background-size: 100% 100%; |
||||
|
margin-top: 1rem; |
||||
|
margin-left: 2rem; |
||||
|
display: flex; |
||||
|
padding-left: 3.375rem; |
||||
|
line-height: 2.5rem; |
||||
|
font-family: PangMenZhengDao-Regular; |
||||
|
font-weight: 400; |
||||
|
font-size: 1rem; |
||||
|
color: #FFFFFF; |
||||
|
letter-spacing: .0594rem; |
||||
|
// background-image: linear-gradient(180deg, #0080ff3d 0%, #0080ff1a 58%, #0080ff3d 100%); |
||||
|
|
||||
|
} |
||||
|
.recordTitle { |
||||
|
text-align: start; |
||||
|
width:calc((100% - 2rem)/7) |
||||
|
} |
||||
|
.redcordContent{ |
||||
|
width: 88.6875rem; |
||||
|
height: 2rem; |
||||
|
line-height: 2rem; |
||||
|
display: flex; |
||||
|
padding-left: 3.375rem; |
||||
|
margin-left: 2rem; |
||||
|
margin-top: .5rem; |
||||
|
|
||||
|
background: url(/assets/bigScreen/blue.png) no-repeat; |
||||
|
background-size: 100% 100%; |
||||
|
// div:first-child{ |
||||
|
// margin-left: 2rem; |
||||
|
|
||||
|
// } |
||||
|
div{ |
||||
|
// flex:1; |
||||
|
text-align: start; |
||||
|
width:calc((100% - 2rem)/7); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
.redcordContent:hover{ |
||||
|
|
||||
|
background: url(/assets/bigScreen/yellow.png) no-repeat; |
||||
|
background-size: 100% 100%; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
.fullStyle{ |
||||
|
height: 19rem; |
||||
|
} |
||||
|
.noFullStyle{ |
||||
|
height: 11rem; |
||||
|
} |
@ -0,0 +1,464 @@ |
|||||
|
//计划巡检数和已完成数字体样式 |
||||
|
|
||||
|
.plan { |
||||
|
|
||||
|
font-family: SourceHanSansCN-Bold; |
||||
|
font-weight: 700; |
||||
|
font-size: .75rem; |
||||
|
color: #dceff9; |
||||
|
letter-spacing: 0; |
||||
|
} |
||||
|
|
||||
|
//数字样式 |
||||
|
.number { |
||||
|
font-family: DIN-Medium; |
||||
|
font-weight: 500; |
||||
|
font-size: 1.125rem; |
||||
|
color: #6eece9; |
||||
|
letter-spacing: 0; |
||||
|
} |
||||
|
|
||||
|
.rate { |
||||
|
width: 2.5rem; |
||||
|
height: 1.5rem; |
||||
|
font-family: DIN-Medium; |
||||
|
font-weight: 500; |
||||
|
font-size: 1.25rem; |
||||
|
color: #f4dba2; |
||||
|
letter-spacing: .0256rem; |
||||
|
position: absolute; |
||||
|
bottom: 5.8125rem; |
||||
|
left: 11.875rem; |
||||
|
} |
||||
|
|
||||
|
.title { |
||||
|
// width: 122px; |
||||
|
height: 1.3125rem; |
||||
|
font-family: PangMenZhengDao; |
||||
|
font-size: 1.3125rem; |
||||
|
color: #ffffff; |
||||
|
// letter-spacing: 0.95px; |
||||
|
margin-top: .4375rem; |
||||
|
margin-left: 2.375rem; |
||||
|
line-height: 1.5rem; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
.monthOrWeek { |
||||
|
height: .875rem; |
||||
|
font-family: SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
font-size: .875rem; |
||||
|
// color: #6EECE9;//选中 |
||||
|
// color: #8FCFFF;//未选中 |
||||
|
letter-spacing: .0181rem; |
||||
|
margin-top: .75rem; |
||||
|
margin-right: 1.875rem; |
||||
|
line-height: .875rem; |
||||
|
cursor: pointer; |
||||
|
// color: #8FCFFF; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.header1 { |
||||
|
width: 24.3125rem; |
||||
|
height: 1.4rem; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
} |
||||
|
|
||||
|
.header1 div:first-child { |
||||
|
margin-left: .5rem; |
||||
|
width: 2.8125rem; |
||||
|
height: .875rem; |
||||
|
} |
||||
|
|
||||
|
.header1> :nth-child(2) { |
||||
|
width: calc((100% - 3.625rem - .5rem - 1.8125rem)/2); |
||||
|
// height: .875rem; |
||||
|
} |
||||
|
|
||||
|
.header1> :nth-child(3) { |
||||
|
width: calc((100% - 3.625rem - .5rem - 1.8125rem)/2); |
||||
|
// width: 3.625rem; |
||||
|
// height: .875rem; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.index { |
||||
|
margin-left: 0.5rem; |
||||
|
width: 2.8125rem; |
||||
|
// width: 33.3%; |
||||
|
padding-left: 0.5rem; |
||||
|
height: 1.1875rem; |
||||
|
// border-radius: 50%; |
||||
|
|
||||
|
// margin-left: .5rem; |
||||
|
} |
||||
|
|
||||
|
.index div { |
||||
|
height: 1.1875rem; |
||||
|
width: 1.1875rem; |
||||
|
border-radius: 50%; |
||||
|
background: rgba(33, 106, 167); |
||||
|
text-align: center; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
.name { |
||||
|
width: calc((100% - 3.625rem - 0.5rem - 1.8125rem)/2); |
||||
|
// height: .875rem; |
||||
|
font-family: SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
font-size: .875rem; |
||||
|
line-height: 1.1875rem; |
||||
|
color: #CCE6FF; |
||||
|
letter-spacing: .0181rem; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.quests { |
||||
|
width: calc((100% - 3.625rem - 1.3rem - 1.8125rem)/2); |
||||
|
text-align: center; |
||||
|
// width: 3.625rem; |
||||
|
// height: .875rem; |
||||
|
line-height: .875rem; |
||||
|
text-align: center; |
||||
|
font-family: DIN-Regular; |
||||
|
font-weight: 400; |
||||
|
font-size: 1rem; |
||||
|
color: rgba(64, 110, 152); |
||||
|
// letter-spacing: .0206rem; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
.header { |
||||
|
width: 23.3125rem; |
||||
|
height: 1.4rem; |
||||
|
|
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
} |
||||
|
|
||||
|
.header div:first-child { |
||||
|
margin-left: .5rem; |
||||
|
width: 2.8125rem; |
||||
|
height: .875rem; |
||||
|
} |
||||
|
|
||||
|
.header> :nth-child(2) { |
||||
|
width: calc((100% - 3.625rem - .5rem - 1.8125rem)/3); |
||||
|
// height: .875rem; |
||||
|
} |
||||
|
|
||||
|
.header> :nth-child(3) { |
||||
|
width: calc((100% - 3.625rem - .5rem - 1.8125rem)/3); |
||||
|
// width: 3.625rem; |
||||
|
// height: .875rem; |
||||
|
} |
||||
|
|
||||
|
.header> :nth-child(4) { |
||||
|
width: calc((100% - 3.625rem - .5rem - 1.8125rem)/3); |
||||
|
// width: 3.625rem; |
||||
|
// height: .875rem; |
||||
|
} |
||||
|
|
||||
|
.index1 { |
||||
|
margin-left: 0.5rem; |
||||
|
width: 2.8125rem; |
||||
|
// width: 33.3%; |
||||
|
padding-left: 0.5rem; |
||||
|
height: 1.1875rem; |
||||
|
// border-radius: 50%; |
||||
|
|
||||
|
// margin-left: .5rem; |
||||
|
} |
||||
|
|
||||
|
.index1 div { |
||||
|
height: 1.1875rem; |
||||
|
width: 1.1875rem; |
||||
|
border-radius: 50%; |
||||
|
background: rgba(33, 106, 167); |
||||
|
text-align: center; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
.name1 { |
||||
|
width: calc((100% - 3.625rem - .5rem - 1.8125rem)/3); |
||||
|
// height: .875rem; |
||||
|
font-family: SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
font-size: .875rem; |
||||
|
line-height: 1.1875rem; |
||||
|
color: #CCE6FF; |
||||
|
letter-spacing: .0181rem; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.num1 { |
||||
|
width: calc((100% - 3.625rem - .5rem - 1.8125rem)/3); |
||||
|
// height: .875rem; |
||||
|
font-family: DIN-Regular; |
||||
|
font-weight: 400; |
||||
|
font-size: 1rem; |
||||
|
text-align: center; |
||||
|
color: #6EECE9; |
||||
|
line-height: .875rem; |
||||
|
letter-spacing: .0206rem; |
||||
|
} |
||||
|
|
||||
|
.quests1 { |
||||
|
width: calc((100% - 3.625rem - .5rem - 1.8125rem)/3); |
||||
|
text-align: center; |
||||
|
// width: 3.625rem; |
||||
|
// height: .875rem; |
||||
|
line-height: .875rem; |
||||
|
text-align: center; |
||||
|
font-family: DIN-Regular; |
||||
|
font-weight: 400; |
||||
|
font-size: 1rem; |
||||
|
color: rgba(64, 110, 152); |
||||
|
// letter-spacing: .0206rem; |
||||
|
} |
||||
|
|
||||
|
.threeHeaderFontStyle { |
||||
|
// width: 33.3%; |
||||
|
height: .875rem; |
||||
|
font-family: SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
font-size: .875rem; |
||||
|
color: #8FCFFF; |
||||
|
letter-spacing: .0181rem; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.thridCardItem { |
||||
|
width: 23.3125rem; |
||||
|
height: 2.1875rem; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
background: rgba(1, 43, 96); |
||||
|
margin-top: .875rem; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
.thirdCardItem>div { |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.thridCardItem:hover { |
||||
|
background: #8f7a49; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
//右边 |
||||
|
.contanier1 { |
||||
|
width: 26.3125rem; |
||||
|
height: 18.8125rem; |
||||
|
margin-top: 2.6875rem; |
||||
|
position: relative; |
||||
|
background-image: linear-gradient(-45deg, #0080ff00 0%, #0080ff1a 58%, #0080ff3d 100%); |
||||
|
// margin-bottom: 0.5rem |
||||
|
} |
||||
|
|
||||
|
; |
||||
|
|
||||
|
.cardHeader { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
height: 2.5rem; |
||||
|
background: url(/assets/bigScreen/cardHeader.png); |
||||
|
background-size: 100% 100%; |
||||
|
background-repeat: no-repeat, |
||||
|
} |
||||
|
|
||||
|
.right1bg { |
||||
|
width: 26.3125rem; |
||||
|
height: 7.1875rem; |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
margin-top: 1rem; |
||||
|
} |
||||
|
|
||||
|
.content { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
} |
||||
|
|
||||
|
.qcNum { |
||||
|
position: absolute; |
||||
|
top: 4.7rem; |
||||
|
left: 5rem; |
||||
|
// width: 1.375rem; |
||||
|
// height: 1.5rem; |
||||
|
} |
||||
|
|
||||
|
.numFontStyle { |
||||
|
width: 3.625rem; |
||||
|
height: 1.5rem; |
||||
|
font-family: DIN-Medium; |
||||
|
font-weight: 500; |
||||
|
font-size: 1.25rem; |
||||
|
color: #6EECE9; |
||||
|
letter-spacing: 0; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.ge { |
||||
|
width: .75rem; |
||||
|
height: .75rem; |
||||
|
font-family: SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
font-size: .75rem; |
||||
|
color: #6EECE9; |
||||
|
letter-spacing: 0; |
||||
|
} |
||||
|
|
||||
|
.qcDescribe { |
||||
|
position: absolute; |
||||
|
top: 7.8rem; |
||||
|
left: 5rem; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
.describeFontStyle { |
||||
|
width: 3.625rem; |
||||
|
height: .875rem; |
||||
|
font-family: SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
font-size: .875rem; |
||||
|
color: #CCE6FF; |
||||
|
letter-spacing: 0; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.deviceNum { |
||||
|
position: absolute; |
||||
|
top: 4.7rem; |
||||
|
right: 5rem; |
||||
|
} |
||||
|
|
||||
|
.deviceDescribe { |
||||
|
position: absolute; |
||||
|
top: 7.8rem; |
||||
|
right: 5rem; |
||||
|
} |
||||
|
|
||||
|
.centerNum { |
||||
|
position: absolute; |
||||
|
top: 5.6rem; |
||||
|
right: 11.3rem; |
||||
|
width: 3.5rem; |
||||
|
height: 31px; |
||||
|
font-family: DIN-Medium; |
||||
|
font-weight: 500; |
||||
|
font-size: 1.625rem; |
||||
|
color: #6EECE9; |
||||
|
letter-spacing: -0.1163rem; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.pDescribe { |
||||
|
width: 3.5rem; |
||||
|
height: .75rem; |
||||
|
font-family: SourceHanSansCN-Medium; |
||||
|
font-weight: 500; |
||||
|
font-size: .75rem; |
||||
|
color: #CCE6FF; |
||||
|
letter-spacing: -0.0537rem; |
||||
|
position: absolute; |
||||
|
top: 7.9rem; |
||||
|
right: 11.3rem; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.percent { |
||||
|
margin-top: 1rem; |
||||
|
width: 23.25rem; |
||||
|
height: 2.875rem; |
||||
|
display: flex; |
||||
|
background: url(/assets/bigScreen/arrow.png); |
||||
|
background-repeat: no-repeat; |
||||
|
background-size: 100% 100%; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.describe { |
||||
|
width: 8rem; |
||||
|
height: .875rem; |
||||
|
font-family: SourceHanSansCN-Regular; |
||||
|
font-weight: 400; |
||||
|
font-size: .875rem; |
||||
|
color: #CCE6FF; |
||||
|
letter-spacing: 0; |
||||
|
margin-left: 2rem; |
||||
|
margin-top: -1rem; |
||||
|
} |
||||
|
|
||||
|
.ant-progress-line { |
||||
|
margin-top: -0.5rem !important; |
||||
|
} |
||||
|
|
||||
|
.ant-progress-text { |
||||
|
color: #6EECE9 !important; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
.contanier { |
||||
|
width: 26.3125rem; |
||||
|
height: 18.8125rem; |
||||
|
margin-top: 2.6875rem; |
||||
|
background-image: linear-gradient(-45deg, #0080ff00 0%, #0080ff1a 58%, #0080ff3d 100%); |
||||
|
} |
||||
|
|
||||
|
.angle_top { |
||||
|
content: ''; |
||||
|
width: 0; |
||||
|
height: 0; |
||||
|
display: block; |
||||
|
border-style: solid; |
||||
|
border-width: 0 .375rem .375rem; |
||||
|
// border-color: transparent transparent #5e5e5e; |
||||
|
position: absolute; |
||||
|
transform: rotate(180deg); |
||||
|
bottom: -0.3187rem; |
||||
|
right: 0.425rem; |
||||
|
} |
||||
|
|
||||
|
.angle_bottom { |
||||
|
content: ''; |
||||
|
width: 0; |
||||
|
height: 0; |
||||
|
display: block; |
||||
|
border-style: solid; |
||||
|
border-width: 0 .375rem .375rem; |
||||
|
// border-color: transparent transparent #5e5e5e; |
||||
|
position: absolute; |
||||
|
top: 0.325rem; |
||||
|
right:0.425rem; |
||||
|
} |
||||
|
.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 |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
@ -0,0 +1,30 @@ |
|||||
|
import React, { useEffect, useState } from 'react' |
||||
|
import { Spin, Popconfirm, message, Button, Input } from 'antd'; |
||||
|
import { connect } from 'react-redux'; |
||||
|
import ProTable from '@ant-design/pro-table'; |
||||
|
import moment from 'moment'; |
||||
|
import HomePage from '../components/homePages'; |
||||
|
const BigScreen=(props)=> { |
||||
|
const {globalTab,}=props |
||||
|
|
||||
|
return ( |
||||
|
|
||||
|
<HomePage globalTab={globalTab}/> |
||||
|
) |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
function mapStateToProps(state) { |
||||
|
const { |
||||
|
auth, global, device |
||||
|
} = state; |
||||
|
return { |
||||
|
clientHeight: global.clientHeight, |
||||
|
actions: global.actions, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(BigScreen); |
||||
|
|
@ -0,0 +1,13 @@ |
|||||
|
'use strict'; |
||||
|
|
||||
|
import reducers from './reducers'; |
||||
|
import routes from './routes'; |
||||
|
import actions from './actions'; |
||||
|
|
||||
|
export default { |
||||
|
key: 'bigScreen', |
||||
|
name: '首页', |
||||
|
reducers: reducers, |
||||
|
routes: routes, |
||||
|
actions: actions, |
||||
|
}; |
@ -0,0 +1,13 @@ |
|||||
|
'use strict'; |
||||
|
import BigScreen from './containers/bigScreen'; |
||||
|
|
||||
|
export default [{ |
||||
|
type: 'inner', |
||||
|
route: { |
||||
|
path: '/bigScreen', |
||||
|
key: 'bigScreen', |
||||
|
// breadcrumb: '首页',
|
||||
|
component: BigScreen, |
||||
|
|
||||
|
} |
||||
|
}]; |
@ -0,0 +1,49 @@ |
|||||
|
(function flexible(window, document) { |
||||
|
var docEl = document.documentElement; |
||||
|
// 获取当前显示设备的物理像素分辨率与CSS像素分辨率之比;
|
||||
|
var dpr = window.devicePixelRatio || 1; |
||||
|
|
||||
|
//根据分辨率调整全局字体大小
|
||||
|
function setBodyFontSize() { |
||||
|
// html已完成加载,则立即调整字体大小,否则等待html加载完成再调整字体大小
|
||||
|
if (document.body) { |
||||
|
document.body.style.fontSize = 12 * dpr + "px"; |
||||
|
} else { |
||||
|
// 监听DOMContentLoaded 事件——当初始的 HTML 文档被完全加载和解析完成之后触发,无需等待样式表
|
||||
|
document.addEventListener("DOMContentLoaded", setBodyFontSize); |
||||
|
} |
||||
|
} |
||||
|
setBodyFontSize(); |
||||
|
|
||||
|
// 根据屏幕宽度,重置1rem的长度为当前屏幕宽度的1/10
|
||||
|
function setRemUnit() { |
||||
|
var rem = docEl.clientWidth / 120 |
||||
|
// 1rem的值永远为根元素的字体大小,所以此处通过调整全局字体大小来重置rem
|
||||
|
docEl.style.fontSize = rem + "px"; |
||||
|
} |
||||
|
|
||||
|
setRemUnit(); |
||||
|
|
||||
|
// 监听resize事件——屏幕大小发生变化时触发
|
||||
|
window.addEventListener("resize", setRemUnit); |
||||
|
// 监听pageshow事件——显示页面时触发
|
||||
|
window.addEventListener("pageshow", function(e) { |
||||
|
// 若是浏览器中点击后退时显示页面,则重置rem
|
||||
|
if (e.persisted) { |
||||
|
setRemUnit(); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// 检测是否支持0.5px
|
||||
|
if (dpr >= 2) { |
||||
|
var fakeBody = document.createElement("body"); |
||||
|
var testElement = document.createElement("div"); |
||||
|
testElement.style.border = ".5px solid transparent"; |
||||
|
fakeBody.appendChild(testElement); |
||||
|
docEl.appendChild(fakeBody); |
||||
|
if (testElement.offsetHeight === 1) { |
||||
|
docEl.classList.add("hairlines"); |
||||
|
} |
||||
|
docEl.removeChild(fakeBody); |
||||
|
} |
||||
|
})(window, document); |
@ -0,0 +1,22 @@ |
|||||
|
|
||||
|
import * as echarts from 'echarts'; |
||||
|
|
||||
|
const TB = Symbol("当前选中的tab"); |
||||
|
|
||||
|
export function setCurrentTab(tab) { |
||||
|
window[TB] = tab |
||||
|
} |
||||
|
|
||||
|
export function getCurrentTab(tab) { |
||||
|
return window[TB] |
||||
|
} |
||||
|
|
||||
|
|
||||
|
const EC = Symbol("echarts symbol"); |
||||
|
if (!window[EC]) { |
||||
|
window[EC] = echarts; |
||||
|
} |
||||
|
|
||||
|
export function getEcharts() { |
||||
|
return window[EC]; |
||||
|
} |
@ -0,0 +1,76 @@ |
|||||
|
const request = require('superagent'); |
||||
|
|
||||
|
let _weatherUrl = ''; |
||||
|
const qweatherUrl = 'https://api.qweather.com/v7/weather/3d' |
||||
|
const qweatherKey = '8f5704332b95425c987dca82b5ea0a5e' |
||||
|
module.exports.entry = function (app, router, opts) { |
||||
|
const { weatherUrl } = opts; |
||||
|
_weatherUrl = weatherUrl; |
||||
|
// _weatherUrl = "https://weatherssj.anxinyun.cn/weatherApp/weather/getImmeData"
|
||||
|
|
||||
|
router.get('/query/weather', weather); |
||||
|
router.get('/query/weather/3d', weather3day); |
||||
|
}; |
||||
|
|
||||
|
async function weather(ctx) { |
||||
|
try { |
||||
|
const { cname } = ctx.query; |
||||
|
const reg = /.+?(省|市|自治区|自治州|县|区)/g; |
||||
|
const arr = cname.match(reg); |
||||
|
if (Array.isArray(arr)) { |
||||
|
let cityName = arr[0]; |
||||
|
if (arr[1]) { |
||||
|
cityName = arr[1]; |
||||
|
} |
||||
|
const weatherRes = await request.post(_weatherUrl).send({ cityName }); |
||||
|
const { body } = weatherRes; |
||||
|
if (body && body.data) { |
||||
|
ctx.status = 200; |
||||
|
ctx.body = { ...body.data, cname, texta: _weatherUrl }; |
||||
|
} else { |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { msg: '获取天气错误' }; |
||||
|
} |
||||
|
} else { |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { msg: '地址解析错误' }; |
||||
|
} |
||||
|
} catch (error) { |
||||
|
console.log('[*err]', error); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = error; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
async function weather3day(ctx) { |
||||
|
try { |
||||
|
const { location } = ctx.query; |
||||
|
const weatherRes = await request.get(`${qweatherUrl}?key=${qweatherKey}&location=${location}`); |
||||
|
const { body } = weatherRes; |
||||
|
if (body) { |
||||
|
ctx.status = 200; |
||||
|
ctx.body = { ...body }; |
||||
|
} else { |
||||
|
ctx.status = 400; |
||||
|
ctx.body = { msg: '获取天气错误' }; |
||||
|
} |
||||
|
} catch (error) { |
||||
|
console.log('[*err]', error); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = error; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// ip地址识别库
|
||||
|
// 淘宝IP地址查询接口:http://ip.taobao.com/service/getIpInfo.php?ip=1.1.35.57
|
||||
|
// 腾讯IP地址查询接口:http://fw.qq.com/ipaddress
|
||||
|
// 新浪的IP地址查询接口:http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js
|
||||
|
// 新浪多地域测试方法:http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js&ip=218.192.3.42
|
||||
|
// 搜狐IP地址查询接口(默认GBK):http://pv.sohu.com/cityjson
|
||||
|
// 搜狐IP地址查询接口(可设置编码):http://pv.sohu.com/cityjson?ie=utf-8
|
||||
|
// 搜狐另外的IP地址查询接口:http://txt.go.sohu.com/ip/soip
|
||||
|
// 谷歌IP地址查询接口:http://j.maxmind.com/app/geoip.js
|
||||
|
// 1616 IP地址查询接口:http://w.1616.net/chaxun/iptolocal.php
|
||||
|
// 126 http://ip.ws.126.net/ipquery hao123
|
||||
|
// http://app.hao123.com/ipquery/getcity.php?rtype=2
|
||||
|
// 太平洋电脑网 http://whois.pconline.com.cn/
|