@ -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'; |
|||
import React from 'react'; |
|||
import { Menu } from 'antd'; |
|||
import { Link } from 'react-router-dom'; |
|||
import { connect } from 'react-redux'; |
|||
import styles from './style.css'; |
|||
import { |
|||
MenuFoldOutlined, MenuUnfoldOutlined, UserOutlined, LogoutOutlined |
|||
} from '@ant-design/icons'; |
|||
'use strict' |
|||
import React, { useState, useEffect, useMemo } from 'react' |
|||
import { Menu } from 'antd' |
|||
import { Link } from 'react-router-dom' |
|||
import { connect } from 'react-redux' |
|||
import styles from './style.css' |
|||
import { setCurrentTab } from '$utils/someStores' |
|||
import { WEATHERMARGIN, ICONSMAP } from '../../constants/weather' |
|||
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 { 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 => { |
|||
if (item.key == 'logout') { |
|||
dispatch(actions.auth.logout(user)); |
|||
dispatch({ type: 'CLEAR_GLOBAL_SITE_LIST' });//清空用户关注工地列表
|
|||
history.push(`/signin`); |
|||
dispatch(actions.auth.logout(user)) |
|||
dispatch({ type: 'CLEAR_GLOBAL_SITE_LIST' }) //清空用户关注工地列表
|
|||
history.push(`/signin`) |
|||
} |
|||
} |
|||
|
|||
let current = pathname; |
|||
if (pathname == '/' || pathname == '') { |
|||
current = 'default'; |
|||
} else if (pathname.charAt(0) == '/') { |
|||
current = pathname.substring(1); |
|||
const onClick1 = tab => { |
|||
setTab(tab) |
|||
if (tab == 'patrolManage') { |
|||
setPatrolManageVisible(true) |
|||
setDeviceManageTabsVisible(false) |
|||
} else if (tab == 'device') { |
|||
setDeviceManageTabsVisible(true) |
|||
setPatrolManageVisible(false) |
|||
} else { |
|||
setPatrolManageVisible(false) |
|||
setDeviceManageTabsVisible(false) |
|||
setCurrentSubMenuTab('') |
|||
// dispatch({ type: 'TAB-CHANGE', data: tab })
|
|||
} |
|||
|
|||
if (current.indexOf('/') != -1) { |
|||
current = current.substring(0, current.indexOf('/')); |
|||
tabChange(tab) |
|||
} |
|||
|
|||
|
|||
return ( |
|||
<div className={styles.header}> |
|||
<div className={styles.header} > |
|||
<div className={styles['header-fold']}> |
|||
{/* <span onClick={toggleCollapsed} style={{ marginRight: 20 }}> |
|||
{collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />} |
|||
</span> */} |
|||
<img src='/assets/images/logo.svg' style={{ margin: '-14px 12px 0 0', height: 24 }} /> |
|||
{/* <img src='/assets/images/logo.svg' style={{ margin: '-14px 12px 0 0', height: 24 }} /> */} |
|||
<div className={styles['header-title']} style={{}}> |
|||
<div className={styles['title-cn']}>运维巡检平台</div> |
|||
<div className={styles['title-en']}>RUNNING MANAGEMENT SYSTEM</div> |
|||
<span style={headerTitleStyle}>河州路河州路河州路河州路河州路</span> |
|||
</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 |
|||
mode='horizontal' |
|||
selectedKeys={[current]} |
|||
style={{ border: 0, background: '#004093' }} |
|||
style={{ border: 0 }} |
|||
onClick={handelClick} |
|||
theme={'light'} |
|||
items={[{ |
|||
items={[ |
|||
{ |
|||
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`} />, |
|||
children: [{ |
|||
label: '退出', key: 'logout' |
|||
}], |
|||
}]} |
|||
children: [ |
|||
{ |
|||
label: '退出', |
|||
key: 'logout', |
|||
}, |
|||
], |
|||
}, |
|||
]} |
|||
/> |
|||
</div> |
|||
</div> |
|||
); |
|||
}; |
|||
) |
|||
} |
|||
|
|||
function mapStateToProps (state) { |
|||
const { global, auth } = state; |
|||
function mapStateToProps(state) { |
|||
const { global, auth, globalTab } = state |
|||
return { |
|||
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 { |
|||
position: relative; |
|||
height: 65px; |
|||
min-width: 520px; |
|||
background-color: #004093; |
|||
height: 5.75rem; |
|||
min-width: 32.5rem; |
|||
/* background-color: #004093; */ |
|||
background-image: url('/assets/bigScreen/top.png'); |
|||
} |
|||
|
|||
.header-fold { |
|||
float: left; |
|||
padding-left: 32px; |
|||
font-size: 16px; |
|||
padding-left: 2rem; |
|||
font-size: 1rem; |
|||
} |
|||
|
|||
.header-title { |
|||
margin-top: 19px; |
|||
height: 60px; |
|||
margin-top: 1.1875rem; |
|||
height: 3.75rem; |
|||
display: inline-block; |
|||
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 { |
|||
font-family: YouSheBiaoTiHei; |
|||
font-size: 18px; |
|||
line-height: 18px; |
|||
letter-spacing: 3px; |
|||
font-size: 1.125rem; |
|||
line-height: 1.125rem; |
|||
letter-spacing: .1875rem; |
|||
} |
|||
|
|||
.header-title .title-en { |
|||
font-family: D-DINExp-Italic; |
|||
line-height: 8px; |
|||
font-size: 8px; |
|||
line-height: .5rem; |
|||
font-size: .5rem; |
|||
} |
|||
|
|||
.header-nav { |
|||
float: right; |
|||
margin-top:.4375rem; |
|||
margin-right:0px; |
|||
} |
|||
|
|||
.header-nav-notification { |
|||
/* color : #666; */ |
|||
font-size: 16px; |
|||
color : #666; |
|||
font-size: 1rem; |
|||
} |
|||
|
|||
.header-nav-user-img-wrapper { |
|||
display: inline; |
|||
margin: 14px 8px; |
|||
margin: .875rem .5rem; |
|||
} |
|||
|
|||
.header-nav-user-img { |
|||
width: 36px; |
|||
height: 36px; |
|||
width: 2.25rem; |
|||
height: 2.25rem; |
|||
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/
|