Browse Source

周边路况信息

master
wenlele 1 year ago
parent
commit
460afa8c21
  1. 2
      api/.vscode/launch.json
  2. 135
      api/app/lib/controllers/superScreen/fire.js
  3. 2
      api/app/lib/middlewares/authenticator.js
  4. 6
      api/app/lib/routes/superScreen/fire.js
  5. 18
      api/config.js
  6. BIN
      super-screen/client/assets/images/homepage/bigscreen/background_n.png
  7. BIN
      super-screen/client/assets/images/homepage/bigscreen/blue.png
  8. BIN
      super-screen/client/assets/images/homepage/bigscreen/dateDook.png
  9. BIN
      super-screen/client/assets/images/homepage/bigscreen/green.png
  10. BIN
      super-screen/client/assets/images/homepage/bigscreen/red.png
  11. BIN
      super-screen/client/assets/images/homepage/bigscreen/seniority.png
  12. 2
      super-screen/client/src/components/index.js
  13. 27
      super-screen/client/src/components/public/index.less
  14. 52
      super-screen/client/src/components/ysPlayerIframe.js
  15. 24
      super-screen/client/src/sections/fire-control/actions/fire.js
  16. 209
      super-screen/client/src/sections/fire-control/components/Right-top2.js
  17. 74
      super-screen/client/src/sections/fire-control/components/right-bottom.js
  18. 36
      super-screen/client/src/sections/fire-control/components/style.less
  19. 11
      super-screen/client/src/sections/fire-control/containers/gis.js
  20. 13
      super-screen/client/src/sections/fire-control/containers/homePage.js
  21. 5
      super-screen/client/src/utils/webapi.js
  22. 2
      super-screen/config.js
  23. 1
      super-screen/routes/attachment/index.js

2
api/.vscode/launch.json

@ -22,6 +22,8 @@
"-d postgres/example/10.8.30.160/30432", "-d postgres/example/10.8.30.160/30432",
"-w https://smartwater.anxinyun.cn", "-w https://smartwater.anxinyun.cn",
"-a https://smartworksafety.anxinyun.cn", "-a https://smartworksafety.anxinyun.cn",
"--yingshiKey 5d16a667e1c2423d9d0d634f781810b4",
"--yingshiSecret 0cc4e1ec4e6a53ea3dabeb09cd5f468b",
] ]
}, },
{ {

135
api/app/lib/controllers/superScreen/fire.js

@ -1,6 +1,7 @@
'use strict'; 'use strict';
const request = require('superagent');
function getFireAlarmList(opts) { function getFireAlarmList (opts) {
return async function (ctx, next) { return async function (ctx, next) {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
let errMsg = { message: '获取消防告警失败' } let errMsg = { message: '获取消防告警失败' }
@ -17,7 +18,7 @@ function getFireAlarmList(opts) {
} }
// 新增消防告警 // 新增消防告警
function addAlarm(opts) { function addAlarm (opts) {
return async function (ctx, next) { return async function (ctx, next) {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
try { try {
@ -35,7 +36,7 @@ function addAlarm(opts) {
} }
// 修改消防告警 // 修改消防告警
function updateAlarm(opts) { function updateAlarm (opts) {
return async function (ctx, next) { return async function (ctx, next) {
try { try {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
@ -56,8 +57,134 @@ function updateAlarm(opts) {
} }
} }
function videoList (opts) {
return async function (ctx) {
try {
const { models, } = ctx.fs.dc;
const { app, yingshiTokenRes } = ctx
let yingshiToken = ''
if (yingshiTokenRes && yingshiTokenRes.token && yingshiTokenRes.expire && moment().isBefore(moment(yingshiTokenRes.expire))) {
yingshiToken = yingshiTokenRes.token
} else {
const tokenRes = await app.fs.yingshiRequest.post(`lapp/token/get`, {
query: {
appKey: opts.yingshiKey,
appSecret: opts.yingshiSecret
}
})
if (tokenRes.code == 200 && tokenRes.data) {
const { accessToken, expireTime } = tokenRes.data
ctx.yingshiTokenRes = {
token: accessToken,
expire: expireTime
}
yingshiToken = accessToken
} else {
throw '未能获取进行萤石鉴权'
}
}
// const deviceRes = await app.fs.yingshiRequest.post(`lapp/device/list`, {
// query: {
// accessToken: yingshiToken,
// }
// })
ctx.status = 200;
let deviceRes_ = [{
deviceName: '楼前大桥',
deviceSerial: 'L48947105',
}, {
deviceName: '滁北大桥',
deviceSerial: 'L48947108',
}, {
deviceName: '新联桥',
deviceSerial: 'L48947110',
}, {
deviceName: '湾庄线',
deviceSerial: 'L48947112',
}, {
deviceName: '新土线',
deviceSerial: 'AA9943808',
}, {
deviceName: '东文大桥',
deviceSerial: 'L48947087',
}, {
deviceName: '莲姚线',
deviceSerial: 'L48947082',
}, {
deviceName: '荷漳公路',
deviceSerial: 'L48947109',
}, {
deviceName: '新武大桥',
deviceSerial: 'L48947086',
},]
const deviceState = await Promise.all(deviceRes_.map(d => {
return app.fs.yingshiRequest.post(`lapp/device/info`, {
query: {
accessToken: yingshiToken,
deviceSerial: d.deviceSerial
}
})
}))
for (let d of deviceRes_) {
let corState = deviceState.find(item => item.code == 200 && item.data && item.data.deviceSerial == d.deviceSerial)
if (corState) {
d.status = corState.data.status
} else {
d.status = 0
}
d.token = yingshiToken
}
ctx.body = deviceRes_
// ||
// (deviceRes.data || []).map(item => {
// return {
// ...item,
// token: yingshiToken,
// }
// })
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: error`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
}
function getDetails (opts) {
return async function (ctx) {
try {
const res = await request.get('https://jiaotong.baidu.com/trafficindex/city/details/?cityCode=163')
ctx.status = 200
ctx.body = res.body || {}
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: error`);
ctx.status = 400;
ctx.body = {
message: '获取南昌市道路数据失败'
}
}
}
}
module.exports = { module.exports = {
addAlarm, addAlarm,
updateAlarm, updateAlarm,
getFireAlarmList getFireAlarmList,
videoList,
getDetails
} }

2
api/app/lib/middlewares/authenticator.js

@ -61,6 +61,8 @@ let isPathExcluded = function (opts, path, method) {
excludeOpts.push({ p: '/logout', o: 'PUT' }); excludeOpts.push({ p: '/logout', o: 'PUT' });
excludeOpts.push({ p: '/water/realstate', o: 'GET' }); excludeOpts.push({ p: '/water/realstate', o: 'GET' });
excludeOpts.push({ p: '/water/emergency', o: 'GET' }); excludeOpts.push({ p: '/water/emergency', o: 'GET' });
excludeOpts.push({ p: '/videoCenter/list', o: 'GET' });
excludeOpts.push({ p: '/trafficindex/city/details', o: 'GET' });
excludeOpts.push({ p: '/fire/alarm', o: 'GET' }); excludeOpts.push({ p: '/fire/alarm', o: 'GET' });
excludeOpts.push({ p: '/fire/alarm', o: 'POST' }); excludeOpts.push({ p: '/fire/alarm', o: 'POST' });
excludeOpts.push({ p: '/fire/alarm/:id', o: 'PUT' }); excludeOpts.push({ p: '/fire/alarm/:id', o: 'PUT' });

6
api/app/lib/routes/superScreen/fire.js

@ -15,4 +15,10 @@ module.exports = function (app, router, opts, AuthCode) {
//修改消防告警状态 //修改消防告警状态
app.fs.api.logAttr['PUT/fire/alarm/:id'] = { content: '修改消防告警状态', visible: true }; app.fs.api.logAttr['PUT/fire/alarm/:id'] = { content: '修改消防告警状态', visible: true };
router.put('/fire/alarm/:id', fire.updateAlarm(opts)); router.put('/fire/alarm/:id', fire.updateAlarm(opts));
app.fs.api.logAttr['GET/videoCenter/list'] = { content: '获取萤石设备列表', visible: true };
router.get('/videoCenter/list', fire.videoList(opts));
app.fs.api.logAttr['GET/trafficindex/city/detailst'] = { content: '获取南昌市道路数据', visible: true };
router.get('/trafficindex/city/details', fire.getDetails(opts));
}; };

18
api/config.js

@ -16,6 +16,9 @@ args.option(['d', 'dbconfig'], '后台同步数据库host示例:postgres/example
args.option(['w', 'water'], '水环境api地址'); args.option(['w', 'water'], '水环境api地址');
args.option(['a', 'worksafety'], '安监api地址'); args.option(['a', 'worksafety'], '安监api地址');
args.option('yingshiKey', '萤石 KEY')
args.option('yingshiSecret', '萤石 SECRET')
const flags = args.parse(process.argv); const flags = args.parse(process.argv);
const DB = process.env.GDRC_DB || flags.pg; const DB = process.env.GDRC_DB || flags.pg;
@ -33,6 +36,11 @@ const DATABASE_CONFIG = process.env.DATABASE_HOST || flags.dbconfig;//同步数
const WATER_URL = process.env.WATER_URL || flags.water; const WATER_URL = process.env.WATER_URL || flags.water;
const WORKSAFETY_URL = process.env.WORKSAFETY_URL || flags.worksafety; const WORKSAFETY_URL = process.env.WORKSAFETY_URL || flags.worksafety;
const YINGSHI_KEY = process.env.YINGSHI_KEY || flags.yingshiKey;
const YINGSHI_SECRET = process.env.YINGSHI_SECRET || flags.yingshiSecret;
// 萤石服务的地址
const YINGSHI_URL = process.env.YINGSHI_URL || flags.yingshiUrl || 'https://open.ys7.com/api';
if (!DB || !BACKUPS_URL || !KUBESPHERE_URL || !DATABASE_CONFIG || !WATER_URL || !WORKSAFETY_URL) { if (!DB || !BACKUPS_URL || !KUBESPHERE_URL || !DATABASE_CONFIG || !WATER_URL || !WORKSAFETY_URL) {
console.log('缺少启动参数,异常退出'); console.log('缺少启动参数,异常退出');
args.showHelp(); args.showHelp();
@ -58,6 +66,8 @@ const product = {
entry: require('./app').entry, entry: require('./app').entry,
opts: { opts: {
dev, dev,
yingshiKey: YINGSHI_KEY,
yingshiSecret: YINGSHI_SECRET,
exclude: [ exclude: [
// "*" // "*"
], // 不做认证的路由,也可以使用 exclude: ["*"] 跳过所有路由 ], // 不做认证的路由,也可以使用 exclude: ["*"] 跳过所有路由
@ -77,7 +87,13 @@ const product = {
password: 'Fs2689' password: 'Fs2689'
} }
}, },
pssaRequest: [], pssaRequest: [
{
name: 'yingshiRequest',
root: YINGSHI_URL,
params: {}
},
],
backupsUrl: BACKUPS_URL, backupsUrl: BACKUPS_URL,
k8s: KUBESPHERE_URL, k8s: KUBESPHERE_URL,
dbConfig: DATABASE_CONFIG, dbConfig: DATABASE_CONFIG,

BIN
super-screen/client/assets/images/homepage/bigscreen/background_n.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
super-screen/client/assets/images/homepage/bigscreen/blue.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

BIN
super-screen/client/assets/images/homepage/bigscreen/dateDook.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
super-screen/client/assets/images/homepage/bigscreen/green.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

BIN
super-screen/client/assets/images/homepage/bigscreen/red.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
super-screen/client/assets/images/homepage/bigscreen/seniority.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

2
super-screen/client/src/components/index.js

@ -6,6 +6,7 @@ import Uploads from './Uploads';
import NoResource from './no-resource'; import NoResource from './no-resource';
import ExportAndImport from './export'; import ExportAndImport from './export';
import ButtonGroup from './buttonGroup'; import ButtonGroup from './buttonGroup';
import YSIframePlayer from './ysPlayerIframe';
import UploadLocal from './UploadLocal'; import UploadLocal from './UploadLocal';
import Box from './public/table-card'; import Box from './public/table-card';
import CarouselList from './public/carousel-list'; import CarouselList from './public/carousel-list';
@ -19,6 +20,7 @@ export {
ExportAndImport, ExportAndImport,
ButtonGroup, ButtonGroup,
UploadLocal, UploadLocal,
YSIframePlayer,
Box, Box,
CarouselList, CarouselList,
NoData, NoData,

27
super-screen/client/src/components/public/index.less

@ -6,7 +6,7 @@
height: 31px; height: 31px;
font-family: YouSheBiaoTiHei; font-family: YouSheBiaoTiHei;
font-size: 24px; font-size: 24px;
color: #FFFFFF; color: #ffffff;
letter-spacing: 2px; letter-spacing: 2px;
padding-left: 15px; padding-left: 15px;
} }
@ -35,7 +35,11 @@
} }
.row-item:hover { .row-item:hover {
background: linear-gradient(270deg, rgba(17, 183, 247, 0) 0%, rgba(17, 183, 247, 0.85) 100%); background: linear-gradient(
270deg,
rgba(17, 183, 247, 0) 0%,
rgba(17, 183, 247, 0.85) 100%
);
color: #9ac8fc; color: #9ac8fc;
} }
} }
@ -57,11 +61,15 @@
color: rgba(204, 228, 255, 1) !important; color: rgba(204, 228, 255, 1) !important;
.row-item { .row-item {
border-bottom: 1px solid #124C79 !important; border-bottom: 1px solid #124c79 !important;
} }
.row-item:hover { .row-item:hover {
background: linear-gradient(270deg, rgba(17, 183, 247, 0) 0%, rgba(17, 183, 247, 0.85) 100%); background: linear-gradient(
270deg,
rgba(17, 183, 247, 0) 0%,
rgba(17, 183, 247, 0.85) 100%
);
color: #9ac8fc; color: #9ac8fc;
} }
} }
@ -71,7 +79,7 @@
display: inline-block; display: inline-block;
width: 15px; width: 15px;
height: 15px; height: 15px;
background: url('/assets/images/homepage/bigscreen/sorrow.png'); background: url("/assets/images/homepage/bigscreen/sorrow.png");
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
margin-left: 13px; margin-left: 13px;
@ -89,8 +97,8 @@
height: 20px; height: 20px;
display: inline-block; display: inline-block;
font-size: 14px; font-size: 14px;
color: #24DCF7; color: #24dcf7;
border: 1px solid #12B2E5; border: 1px solid #12b2e5;
background-color: rgba(91, 193, 255, 0.2); background-color: rgba(91, 193, 255, 0.2);
margin-right: 3px; margin-right: 3px;
cursor: pointer; cursor: pointer;
@ -101,8 +109,8 @@
height: 20px; height: 20px;
display: inline-block; display: inline-block;
font-size: 14px; font-size: 14px;
color: #4C9FFF; color: #4c9fff;
border: 1px solid #0B6AEA; border: 1px solid #0b6aea;
background-color: rgba(35, 108, 254, 0.3); background-color: rgba(35, 108, 254, 0.3);
margin-right: 3px; margin-right: 3px;
cursor: pointer; cursor: pointer;
@ -111,6 +119,7 @@
.children-container { .children-container {
height: calc(100% - 42px); height: calc(100% - 42px);
// background-image: linear-gradient(180deg, #04377ecc 1%, #001241 100%);
background-image: linear-gradient(180deg, #04377ecc 1%, #001241 100%); background-image: linear-gradient(180deg, #04377ecc 1%, #001241 100%);
} }

52
super-screen/client/src/components/ysPlayerIframe.js

@ -0,0 +1,52 @@
/**
* 萤石视频直播基于萤石云iframe模式使用方式简单
* 官方参考https://open.ys7.com/console/ezopenIframe.html
*/
'use strict';
import React from 'react';
import { connect } from 'react-redux';
const YSIframePlayer = props => {
const { containerId, height, width, url, autoplay, audio, videoState, ysToken } = props;
const at = ysToken
if (!url || !at) return null;
const src = `https://open.ys7.com/ezopen/h5/iframe?audio=${audio ? '1' : '0'}&url=${url}&autoplay=${autoplay || 1}&accessToken=${at}`
// const src = `https://open.ys7.com/ezopen/h5/iframe?audio=1&url=${url}&autoplay=${autoplay || 1}&accessToken=${at}`
return (
<div
style={{ position: 'relative', height: '100%', width: '100%' }}>
<iframe
frameBorder="0"
id={containerId || 'myPlayer'}
src={src}
// https://open.ys7.com/doc/zh/book/index/live_proto.html 单个播放器的长宽比例限制最小为{width: 400px;height: 300px;}
width={width || 400}
height={height || 300}
allowFullScreen
wmode="transparent"
>
</iframe>
{
videoState && videoState.status == 0 ?
<div style={{
height: width || 300, width: width || 400, position: 'absolute', top: 0, background: '#000',
display: 'flex', justifyContent: 'center', alignItems: 'center', color: '#fff'
}}>
设备中断正在处理中...
</div>
: ''
}
</div>
)
}
function mapStateToProps (state) {
const { auth, } = state;
return {
user: auth.user,
};
}
export default connect(mapStateToProps)(YSIframePlayer);

24
super-screen/client/src/sections/fire-control/actions/fire.js

@ -40,3 +40,27 @@ export function modifyFireAlarm(id, params) {
}, },
}); });
} }
export function getVideoCenterList () {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_VIDEO_CENTER_LIST',
url: ApiTable.videoCenterList,
msg: { error: '获取视频中心列表失败' },
reducer: { name: 'videoCenterList' }
});
}
export function getDetails () {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_DETAILS',
url: ApiTable.details,
msg: { error: '获取南昌市道路数据失败' },
// reducer: { name: 'videoCenterList' }
});
}

209
super-screen/client/src/sections/fire-control/components/Right-top2.js

@ -0,0 +1,209 @@
import React, { useEffect, useState } from 'react'
import { connect } from 'react-redux';
import { Box, YSIframePlayer } from '$components';
import { Select } from 'antd';
import { ArrowDownOutlined, ArrowUpOutlined } from '@ant-design/icons';
import './style.less';
const DataTop5 = ({ dispatch, actions, longitudeLatitude }) => {
const [videoList, setVideoList] = useState([])
const [options, setOptions] = useState([])
const [traffic, setTraffic] = useState({})
let weeks = { 1: '周一', 2: '周二', 3: '周三', 4: '周四', 5: '周五', 6: '周六', 7: '周日' }
useEffect(() => {
dispatch(actions.firecontrol.getDetails()).then(res => {
if (res.success) {
setTraffic(res.payload.data?.data?.detail || {});
}
})
}, [])
useEffect(() => {
dispatch(actions.firecontrol.getDetails()).then(res => {
if (res.success) {
setTraffic(res.payload.data?.data?.detail || {});
}
})
}, [longitudeLatitude])
console.log(longitudeLatitude);
return <div style={{ height: '100%', width: '100%', margin: "0px 0px 28px" }}>
<div style={{
height: "100%", listStyle: 'none',
}}>
<div className='box_header_bg' >
<span className='card-title'>周边路况实时数据</span>
</div>
<div className='children-container' style={{ padding: '20px' }}>
{longitudeLatitude?.longitude ?
<>
{/* <div style={{
height: "23%", display: "flex",
background: 'linear-gradient(180deg, #04377ecc 1%, #001241 100%)'
}}>
<div style={{ width: "34%", display: 'flex', flexDirection: "column", justifyContent: "center", alignItems: "center" }}>
<div style={{
fontFamily: "YouSheBiaoTiHei", fontSize: 28, letterSpacing: 2,
color: (traffic?.index >= 1 && traffic?.index < 1.5) ?
"#00FF87" : (traffic?.index >= 1.5 && traffic?.index < 1.8) ?
"#FFCC00;" : (traffic?.index >= 1.8 && traffic?.index < 2) ?
"#DE0102;" : (traffic?.index >= 2) ? "#8E0E0B;" : ""
}}>畅通</div>
<div style={{ fontSize: 14, color: "#C0E2FF;" }}>路况整体评价</div>
</div>
<div style={{ width: "62%", display: 'flex', }}>
<div style={{ width: "50%", display: 'flex', flexDirection: "column", justifyContent: "space-evenly", alignItems: "center" }}>
<div style={{ height: 22, background: "rgb(0 88 204 / 50%)", width: '90%', textAlign: 'center' }}>平均通行速度</div>
<div ><div style={{ display: 'inline-block', transform: 'skewX(-8deg)', fontSize: 20, fontFamily: "D-DINExp-Italic", }}>{traffic?.road_network_speed || '--'}</div> <span style={{ color: '#00FF87', marginLeft: 6 }}>km/h</span></div>
</div>
<div style={{ width: "50%", display: 'flex', flexDirection: "column", justifyContent: "space-evenly", alignItems: "center" }}>
<div style={{ height: 22, background: "rgb(0 88 204 / 50%)", width: '90%', textAlign: 'center' }}>拥堵距离</div>
<div ><div style={{ display: 'inline-block', transform: 'skewX(-8deg)', fontSize: 20, fontFamily: "D-DINExp-Italic", }}>{traffic?.yongdu_length_4 || '--'}</div><span style={{ color: '#00FF87', marginLeft: 6 }}>km</span> </div>
</div>
</div>
</div>
<div style={{ display: 'flex' }}>
<div style={{ fontFamily: 'SourceHanSansCN-Bold', fontWeight: 700, fontSize: 18, width: 190 }}>较10分钟前拥堵趋势</div>
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start', width: "calc(100% - 200px)" }}>
<div style={{
display: 'flex', alignItems: 'center', justifyContent: 'space-around'
}}>
<div style={{ fontSize: 28, transform: 'skewX(-8deg)', color: '#00FF87', fontFamily: "YouSheBiaoTiHei", }}>
持平
</div>
<img src="/assets/images/homepage/bigscreen/red.png" style={{ width: 30, height: 30 }} />
</div>
<div>与1设法厕任务v</div>
</div>
</div>
<div style={{}}>
<div style={{ fontFamily: 'SourceHanSansCN-Bold', fontWeight: 700, fontSize: 18, }}>路况描述</div>
<div>dewbfdhuihseacf dsjhcf ewdcjaiopsdc op sadc jwe dcfp weopdcf ujew fdc </div>
</div> */}
</>
: <>
<div style={{
background: 'url(/assets/images/homepage/bigscreen/background_n.png)',
backgroundSize: '100% 20px', backgroundPosition: '0 14px', backgroundRepeat: 'no-repeat',
display: 'flex', alignItems: 'center', justifyContent: "space-between", padding: '0 6px',
}}>
<div style={{
fontFamily: 'YouSheBiaoTiHei', fontSize: 20
}}
>
南昌市</div>
<div style={{
fontFamily: 'YouSheBiaoTiHei', fontSize: 14
}}
>NANCHANG CITY</div>
</div>
<div style={{
height: "calc(100% - 38px)", marginTop: 20, display: 'flex', flexDirection: 'column', justifyContent: 'space-around',
}}>
<div style={{
height: "23%", display: "flex",
background: 'linear-gradient(180deg, #04377ecc 1%, #001241 100%)'
}}>
<div style={{ width: "34%", display: 'flex', flexDirection: "column", justifyContent: "center", alignItems: "center" }}>
<div style={{
fontFamily: "YouSheBiaoTiHei", fontSize: 28, letterSpacing: 2,
color: (traffic?.index >= 1 && traffic?.index < 1.5) ?
"#00FF87" : (traffic?.index >= 1.5 && traffic?.index < 1.8) ?
"#FFCC00;" : (traffic?.index >= 1.8 && traffic?.index < 2) ?
"#DE0102;" : (traffic?.index >= 2) ? "#8E0E0B;" : ""
}}>{
(traffic?.index >= 1 && traffic?.index < 1.5) ?
"畅通" : (traffic?.index >= 1.5 && traffic?.index < 1.8) ?
"缓行" : (traffic?.index >= 1.8 && traffic?.index < 2) ?
"拥堵" : (traffic?.index >= 2) ? "严重拥堵" : ""
}</div>
<div style={{ fontSize: 14, color: "#C0E2FF;" }}>路况整体评价</div>
</div>
<div style={{ width: "62%", display: 'flex', flexDirection: "column", justifyContent: "space-evenly", }}>
<div style={{ height: 22, background: "rgb(0 88 204 / 50%)", textIndent: 20 }}>实时拥堵指数</div>
<div style={{ display: "flex", alignItems: 'center' }}>
<div style={{ fontSize: 28, transform: 'skewX(-8deg)', fontFamily: "D-DINExp-Italic", fontWeight: 'Italic', color: '#ECF7FF', marginRight: 4 }}>{traffic?.index || '--'}</div>
<div style={{ color: '#C3E6FF' }}>
较上周同期{traffic?.last_index > traffic?.index ? "下降" : '上升'}
{((traffic?.last_index > traffic?.index ? (traffic?.last_index - traffic?.index) / traffic?.last_index : (traffic?.index - traffic?.last_index) / traffic?.last_index) * 100).toFixed(2)}%
</div>
{traffic?.last_index > traffic?.index ?
<ArrowDownOutlined style={{ color: '#06FF07', fontSize: 18 }} />
: <ArrowUpOutlined style={{ color: '#06FF07', fontSize: 18 }} />}
</div>
</div>
</div>
<div style={{
height: "23%", display: "flex",
background: 'linear-gradient(180deg, #04377ecc 1%, #001241 100%)'
}}>
<div style={{ width: "34%", display: 'flex', flexDirection: "column", justifyContent: "center", alignItems: "center" }}>
<img src='/assets/images/homepage/bigscreen/seniority.png' style={{ width: "80%" }} />
</div>
<div style={{ width: "62%", display: 'flex', flexDirection: "column", justifyContent: "space-evenly", }}>
<div style={{ height: 22, background: "rgb(0 88 204 / 50%)", textIndent: 20 }}>实时拥堵排行</div>
<div style={{ display: "flex", alignItems: 'center' }}>
<div style={{ fontSize: 28, fontFamily: "D-DINExp-Italic", transform: 'skewX(-8deg)', fontWeight: 'Italic', color: '#ECF7FF', marginRight: 4 }}>{traffic?.rank || '--'}</div>
<div style={{ marginRight: 16, fontSize: 20, transform: 'skewX(-8deg)' }}>/{traffic?.count || '--'}</div>
<div style={{ color: '#C3E6FF' }}>全国重点城市拥堵排行</div>
</div>
</div>
</div>
<div style={{
height: "23%", display: "flex",
background: 'linear-gradient(180deg, #04377ecc 1%, #001241 100%)'
}}>
<div style={{ width: "50%", display: 'flex', flexDirection: "column", justifyContent: "space-evenly", alignItems: "center" }}>
<div style={{ height: 22, background: "rgb(0 88 204 / 50%)", width: '90%', textAlign: 'center' }}>实时平均速度</div>
<div ><div style={{ display: 'inline-block', transform: 'skewX(-8deg)', fontSize: 28, fontFamily: "D-DINExp-Italic", }}>{traffic?.road_network_speed || '--'}</div> <span style={{ color: '#00FF87', marginLeft: 20 }}>km/h</span></div>
</div>
<div style={{ width: "50%", display: 'flex', flexDirection: "column", justifyContent: "space-evenly", alignItems: "center" }}>
<div style={{ height: 22, background: "rgb(0 88 204 / 50%)", width: '90%', textAlign: 'center' }}>实时严重拥堵里程</div>
<div ><div style={{ display: 'inline-block', transform: 'skewX(-8deg)', fontSize: 28, fontFamily: "D-DINExp-Italic", }}>{traffic?.yongdu_length_4 || '--'}</div><span style={{ color: '#00FF87', marginLeft: 20 }}>km</span> </div>
</div>
</div>
<div style={{
height: "23%", display: "flex",
background: 'linear-gradient(180deg, #04377ecc 1%, #001241 100%)'
}}>
<div style={{ width: "34%", display: 'flex', flexDirection: "column", justifyContent: "center", alignItems: "center" }}>
<img src='/assets/images/homepage/bigscreen/dateDook.png' style={{ width: "80%" }} />
</div>
<div style={{ width: "62%", display: 'flex', flexDirection: "column", justifyContent: "space-evenly", }}>
<div style={{ height: 22, background: "rgb(0 88 204 / 50%)", textIndent: 20 }}>近30日最高拥堵指数</div>
<div style={{ display: "flex", alignItems: 'center' }}>
<div style={{ fontSize: 28, fontFamily: "D-DINExp-Italic", fontWeight: 'Italic', color: '#ECF7FF', marginRight: 38 }}>{traffic?.month_max_yongdu_index || '--'}</div>
<div style={{ color: '#C3E6FF' }}>{traffic?.month_max_congest_time} {weeks[traffic?.month_max_week_day]}</div>
</div>
</div>
</div>
</div></>
}
</div>
</div>
</div >
}
function mapStateToProps (state) {
const { auth, global } = state
return {
user: auth.user,
actions: global.actions,
}
}
export default connect(mapStateToProps)(DataTop5);

74
super-screen/client/src/sections/fire-control/components/right-bottom.js

@ -1,29 +1,71 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { Box } from '$components'; import { connect } from 'react-redux';
import { Box, YSIframePlayer } from '$components';
import { Select } from 'antd';
import './style.less'; import './style.less';
function DataTop5(props) { const DataTop5 = ({ dispatch, actions }) => {
const [videoList, setVideoList] = useState([])
const [options, setOptions] = useState([])
const [videoData, setVideoData] = useState({})
return <Box title={"视频监控"} bodyPaddingTop={1} > useEffect(() => {
<div className='video_container'> dispatch(actions.firecontrol.getVideoCenterList()).then(res => {
<div className='_item'> if (res.success) {
<div className='video_bottom'><span>南昌大道</span><span>14:12:32</span></div> setVideoList(res.payload.data || [])
</div> setOptions(res.payload.data?.map(v => ({ value: v.deviceSerial, label: v.deviceName })) || [])
<div className='_item'> setVideoData(res.payload.data[0] || {})
<div className='video_bottom'><span>南昌大道</span><span>11:34:12</span></div> }
})
}, [])
return <div style={{ height: '100%', width: '100%', margin: "0px 0px 28px" }}>
<div style={{
height: "100%", listStyle: 'none',
}}>
<div className='box_header_bg' >
<span className='card-title'>视频监控</span>
<Select
className='bigscreen-select'
style={{
width: 100,
float: 'right',
margin: '18px 20px 0 0 '
}}
value={videoData?.deviceSerial}
onChange={v => {
setVideoData(videoList?.find(s => s.deviceSerial == v) ||{})
}}
options={options}
/>
</div> </div>
<div className='_item'> <div className='children-container'>
<div className='video_bottom'><span>南昌大道</span><span>08:34:12</span></div> <YSIframePlayer
containerId={`yingshiPlay_lu_${videoData?.deviceSerial}`}
height='100%'
width="100%"
url={`ezopen://open.ys7.com/${videoData?.deviceSerial}/${'1'}.hd.live`}
audio="0"
ysToken={videoData?.token}
videoState={{
status: videoData?.status
}}
/>
</div> </div>
<div className='_item'>
<div className='video_bottom'><span>南昌大道</span><span>09:12:34</span></div>
</div> </div>
</div> </div>
</Box>
} }
function mapStateToProps (state) {
export default DataTop5; const { auth, global } = state
return {
user: auth.user,
actions: global.actions,
}
}
export default connect(mapStateToProps)(DataTop5);

36
super-screen/client/src/sections/fire-control/components/style.less

@ -455,3 +455,39 @@
} }
} }
} }
.bigscreen-select {
.ant-select-selector {
background-color: #24dcf74d !important;
height: 18px !important;
}
.ant-select-focused {
border: 0px;
}
.ant-select-selection-item {
color: #fff;
font-family: YouSheBiaoTiHei;
height: 16px !important;
line-height: 17px !important;
text-align: right;
}
.ant-select-selection-search {
color: #fff;
}
.ant-select-arrow {
color: #fff;
}
.ant-select-selection-item {
background: transparent;
border: 0;
}
.ant-select-multiple,
.ant-select-selection-item-remove {
color: #fff;
}
}

11
super-screen/client/src/sections/fire-control/containers/gis.js

@ -17,8 +17,8 @@ const tabs = [
{ name: '应急避难场所', tab: 'yjbns', className: 'emergency_button' }, { name: '应急避难场所', tab: 'yjbns', className: 'emergency_button' },
] ]
function Map(props) { function Map (props) {
const { dispatch, actions, emergencyList, propTab } = props; const { dispatch, actions, emergencyList, propTab,setLongitudeLatitude } = props;
const [delay, setDelay] = useState(true) const [delay, setDelay] = useState(true)
const [tab, setTab] = useState('xfyjwz') const [tab, setTab] = useState('xfyjwz')
const [visible, setVisible] = useState(false) const [visible, setVisible] = useState(false)
@ -204,6 +204,7 @@ function Map(props) {
renderAlarmInfowindow(x) renderAlarmInfowindow(x)
} }
}, 50) }, 50)
setLongitudeLatitude({ longitude: x.longitude, latitude: x.latitude })
}) })
}) })
} }
@ -230,7 +231,7 @@ function Map(props) {
// driving.clear() //清除路线 // driving.clear() //清除路线
} }
function drawRoute(route) { function drawRoute (route) {
var path = parseRouteToPath(route) var path = parseRouteToPath(route)
var routeLine = new AMap.Polyline({ var routeLine = new AMap.Polyline({
@ -255,13 +256,13 @@ function Map(props) {
} }
//计算两点距离 //计算两点距离
function computeDis(p1, p2) { function computeDis (p1, p2) {
return Math.round(p1.distance(p2)); return Math.round(p1.distance(p2));
} }
// 解析DrivingRoute对象,构造成AMap.Polyline的path参数需要的格式 // 解析DrivingRoute对象,构造成AMap.Polyline的path参数需要的格式
// DrivingResult对象结构参考文档 https://lbs.amap.com/api/javascript-api/reference/route-search#m_DriveRoute // DrivingResult对象结构参考文档 https://lbs.amap.com/api/javascript-api/reference/route-search#m_DriveRoute
function parseRouteToPath(route) { function parseRouteToPath (route) {
var path = [] var path = []
for (var i = 0, l = route.steps.length; i < l; i++) { for (var i = 0, l = route.steps.length; i < l; i++) {
var step = route.steps[i] var step = route.steps[i]

13
super-screen/client/src/sections/fire-control/containers/homePage.js

@ -8,6 +8,7 @@ import LeftMiddle from '../components/left-middle'
import LeftBottom from '../components/left-bottom' import LeftBottom from '../components/left-bottom'
import RightTop from '../components/right-top' import RightTop from '../components/right-top'
import RightMiddle from '../components/right-middle' import RightMiddle from '../components/right-middle'
import RightTop2 from '../components/Right-top2'
import RightBottom from '../components/right-bottom' import RightBottom from '../components/right-bottom'
import Gis from './gis'; import Gis from './gis';
import './style.less' import './style.less'
@ -15,7 +16,7 @@ import Weather from '../../water-prevention/components/weather';
import { FullScreenContainer } from '$components' import { FullScreenContainer } from '$components'
import { useFsRequest } from '$utils'; import { useFsRequest } from '$utils';
function homePage(props) { function homePage (props) {
const { dispatch, actions } = props; const { dispatch, actions } = props;
const childStyle = { height: '32%', color: '#fff', marginBottom: 17 } const childStyle = { height: '32%', color: '#fff', marginBottom: 17 }
const cardHeight = document.body.clientHeight * 0.896 * 0.32 const cardHeight = document.body.clientHeight * 0.896 * 0.32
@ -23,6 +24,8 @@ function homePage(props) {
const [tab, setTab] = useState('overview') const [tab, setTab] = useState('overview')
const [emengencyTab, setEmengencyTab] = useState('xfyjwz'); const [emengencyTab, setEmengencyTab] = useState('xfyjwz');
const [alarmInfo, setAlarmInfo] = useState({}) const [alarmInfo, setAlarmInfo] = useState({})
const [longitudeLatitude, setLongitudeLatitude] = useState({})
const { data: emergencyList = {} } = useFsRequest({ url: 'water/emergency' }); const { data: emergencyList = {} } = useFsRequest({ url: 'water/emergency' });
const endEvent = () => { const endEvent = () => {
@ -74,6 +77,7 @@ function homePage(props) {
emergencyList={emergencyList} emergencyList={emergencyList}
dispatch={dispatch} dispatch={dispatch}
actions={actions} actions={actions}
setLongitudeLatitude={setLongitudeLatitude}
propTab={tab} propTab={tab}
alarmOk={(info) => { alarmOk={(info) => {
setTab('item') setTab('item')
@ -86,11 +90,14 @@ function homePage(props) {
</div> </div>
<div className='homepage-left homepage-left-right'> <div className='homepage-left homepage-left-right'>
{tab == 'overview' ? <div className="list"> {tab == 'overview' ? <div className="list">
<div className='child-right' style={childStyle}> {/* <div className='child-right' style={childStyle}>
<RightTop /> <RightTop />
</div> </div>
<div className='child-right' style={childStyle}> <div className='child-right' style={childStyle}>
<RightMiddle cardContentHeight={cardContentHeight} /> <RightMiddle cardContentHeight={cardContentHeight} />
</div> */}
<div className='child-right' style={{ height: 'calc(64% + 17px)', color: '#fff', marginBottom: 17 }}>
<RightTop2 longitudeLatitude={longitudeLatitude} />
</div> </div>
<div className='child-right' style={childStyle}> <div className='child-right' style={childStyle}>
<RightBottom /> <RightBottom />
@ -110,7 +117,7 @@ function homePage(props) {
} }
function mapStateToProps(state) { function mapStateToProps (state) {
const { const {
auth, global auth, global
} = state; } = state;

5
super-screen/client/src/utils/webapi.js

@ -134,6 +134,11 @@ export const ApiTable = {
//消防 //消防
getFireAlarmList: 'fire/alarm', getFireAlarmList: 'fire/alarm',
modifyFireAlarm: 'fire/alarm/{id}', modifyFireAlarm: 'fire/alarm/{id}',
//获取摄像头数据
videoCenterList:'videoCenter/list',
details: '/trafficindex/city/details'
}; };
export const RouteTable = { export const RouteTable = {

2
super-screen/config.js

@ -27,6 +27,7 @@ const ANXINCLOUD_QINIU_SECRETKEY = process.env.ANXINCLOUD_QINIU_SECRETKEY || fla
const ANXINCLOUD_QINIU_BUCKET_RESOURCE = process.env.ANXINCLOUD_QINIU_BUCKET_RESOURCE || flags.qnbkt; const ANXINCLOUD_QINIU_BUCKET_RESOURCE = process.env.ANXINCLOUD_QINIU_BUCKET_RESOURCE || flags.qnbkt;
const ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE = process.env.ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE || flags.qndmn; const ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE = process.env.ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE || flags.qndmn;
const weatherUrl = process.env.ANXINCLOUD_WEATHERAPP_API || "https://weatherssj.anxinyun.cn/weatherApp/weather/getImmeData" const weatherUrl = process.env.ANXINCLOUD_WEATHERAPP_API || "https://weatherssj.anxinyun.cn/weatherApp/weather/getImmeData"
const BAIDU_API = process.env.BAIDU_API || "https://jiaotong.baidu.com"
//阿里OSS //阿里OSS
const ALI_OSS_ACCESSKEY = process.env.ALI_OSS_ACCESSKEY || flags.aliOssAccessKey; const ALI_OSS_ACCESSKEY = process.env.ALI_OSS_ACCESSKEY || flags.aliOssAccessKey;
@ -87,6 +88,7 @@ const product = {
region: ALI_OSS_REGION region: ALI_OSS_REGION
}, },
weatherUrl, weatherUrl,
baiDuAPi: BAIDU_API
} }
}, },
{ {

1
super-screen/routes/attachment/index.js

@ -229,7 +229,6 @@ module.exports = {
} }
} }
router.use(download_); router.use(download_);
router.post('/_upload/new', upload); router.post('/_upload/new', upload);
router.delete('/_upload/cleanup', remove); router.delete('/_upload/cleanup', remove);

Loading…
Cancel
Save