|
@ -2,14 +2,16 @@ import React, { useEffect, useState, useRef } from 'react' |
|
|
import { push } from 'react-router-redux'; |
|
|
import { push } from 'react-router-redux'; |
|
|
import { connect } from 'react-redux'; |
|
|
import { connect } from 'react-redux'; |
|
|
import request from 'superagent'; |
|
|
import request from 'superagent'; |
|
|
import { getCrane } from '../actions' |
|
|
import { getCrane, logoutApp, getVideo } from '../actions' |
|
|
import { ApiTable } from '$utils' |
|
|
import { ApiTable } from '$utils' |
|
|
import { Colors } from '@peace/utils' |
|
|
import { Colors } from '@peace/utils' |
|
|
import { |
|
|
import { |
|
|
SettingOutlined, VideoCameraOutlined |
|
|
SettingOutlined, VideoCameraOutlined, LogoutOutlined |
|
|
} from '@ant-design/icons'; |
|
|
} from '@ant-design/icons'; |
|
|
|
|
|
import VideoModal from '../components/videoModal' |
|
|
import { Col, Row, Button, Modal, Input, Space } from 'antd'; |
|
|
import { Col, Row, Button, Modal, Input, Space } from 'antd'; |
|
|
import '../style.less' |
|
|
import '../style.less' |
|
|
|
|
|
import flvjs from 'flv.js' |
|
|
|
|
|
|
|
|
function calculateIntersection (cx, cy, d, angle) { |
|
|
function calculateIntersection (cx, cy, d, angle) { |
|
|
// 将角度转换为弧度
|
|
|
// 将角度转换为弧度
|
|
@ -40,8 +42,12 @@ function calculateIntersection (cx, cy, d, angle) { |
|
|
return [intersection_x, intersection_y]; |
|
|
return [intersection_x, intersection_y]; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
let ws; |
|
|
let dataLiveWs; |
|
|
let interval; |
|
|
let lidarLiveWs; |
|
|
|
|
|
let dataLiveWsInterval; |
|
|
|
|
|
let lidarLiveWsInterval; |
|
|
|
|
|
let flvPlayerInterval; |
|
|
|
|
|
let jessibucasInterval; |
|
|
function Index (props) { |
|
|
function Index (props) { |
|
|
const { dispatch, craneData } = props |
|
|
const { dispatch, craneData } = props |
|
|
const xyCvs = useRef() |
|
|
const xyCvs = useRef() |
|
@ -55,12 +61,32 @@ function Index (props) { |
|
|
shadow: '#303030' |
|
|
shadow: '#303030' |
|
|
}) |
|
|
}) |
|
|
const [isModalOpen, setIsModalOpen] = useState(false); |
|
|
const [isModalOpen, setIsModalOpen] = useState(false); |
|
|
|
|
|
const [videoVis, setVideoVis] = useState(false) |
|
|
|
|
|
const [isOutModalOpen, setIsOutModalOpen] = useState(false) |
|
|
|
|
|
const [video, setVideo] = useState({}) |
|
|
|
|
|
const flvPlayer = useRef(null) |
|
|
|
|
|
const jessibucas = useRef(null) |
|
|
|
|
|
|
|
|
const draw = (type, params = {}) => { |
|
|
const draw = ( |
|
|
|
|
|
type, |
|
|
|
|
|
params = { |
|
|
|
|
|
|
|
|
|
|
|
}, |
|
|
|
|
|
) => { |
|
|
|
|
|
|
|
|
|
|
|
// params = {
|
|
|
|
|
|
// from: 'lidarLive',
|
|
|
|
|
|
// rotation: 78,
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
if (type == 'xz') { |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
const canvasArea = document.getElementById('canvasArea') |
|
|
const canvasArea = document.getElementById('canvasArea') |
|
|
const canvasHeight = canvasArea.clientHeight - 12 * 2 - 6 |
|
|
const canvasHeight = canvasArea.clientHeight - 12 * 2 - 6 |
|
|
const canvasWidth = canvasArea.clientWidth - 12 * 2 |
|
|
const canvasWidth = canvasArea.clientWidth / 14 * 10 - 12 * 2 |
|
|
const mainColor = "rgb(249,179,45)" |
|
|
const mainColor = "rgb(249,179,45)" |
|
|
|
|
|
const dangerColor = "red" |
|
|
if (type == 'xy') { |
|
|
if (type == 'xy') { |
|
|
// xy 视图
|
|
|
// xy 视图
|
|
|
const xyCtx = xyCvs.current.getContext("2d"); |
|
|
const xyCtx = xyCvs.current.getContext("2d"); |
|
@ -69,9 +95,20 @@ function Index (props) { |
|
|
const center = [canvasWidth / 2, canvasHeight / 2] |
|
|
const center = [canvasWidth / 2, canvasHeight / 2] |
|
|
// 直径
|
|
|
// 直径
|
|
|
const diameter = Math.min(canvasWidth, canvasHeight) |
|
|
const diameter = Math.min(canvasWidth, canvasHeight) |
|
|
|
|
|
// 半径
|
|
|
|
|
|
const radius = diameter / 2 |
|
|
|
|
|
console.log(radius); |
|
|
|
|
|
// 参数半径和绘制半径的比值
|
|
|
|
|
|
const radiusRate = (params.radius || radius) / radius |
|
|
|
|
|
console.log(radiusRate); |
|
|
|
|
|
// 当前旋转角度
|
|
|
|
|
|
let curRotation = |
|
|
|
|
|
params.from == 'lidarLive' ? |
|
|
|
|
|
params?.rotation || 0 : |
|
|
|
|
|
params?.rotation?.Value || 0; |
|
|
// 画圆
|
|
|
// 画圆
|
|
|
xyCtx.beginPath(); |
|
|
xyCtx.beginPath(); |
|
|
xyCtx.arc(...center, diameter / 2, 0, 2 * Math.PI); |
|
|
xyCtx.arc(...center, radius, 0, 2 * Math.PI); |
|
|
if (darkModde) { |
|
|
if (darkModde) { |
|
|
xyCtx.strokeStyle = darkColor.subTextColor; |
|
|
xyCtx.strokeStyle = darkColor.subTextColor; |
|
|
// xyCtx.fill();
|
|
|
// xyCtx.fill();
|
|
@ -84,22 +121,93 @@ function Index (props) { |
|
|
xyCtx.fillStyle = mainColor; |
|
|
xyCtx.fillStyle = mainColor; |
|
|
xyCtx.fill(); |
|
|
xyCtx.fill(); |
|
|
xyCtx.stroke(); |
|
|
xyCtx.stroke(); |
|
|
// 吊臂
|
|
|
// 吊臂 - 长~
|
|
|
let curRotation = params?.rotation?.Value || 42 |
|
|
let armLength = ((params.boom || radius) / radiusRate) * 2; |
|
|
|
|
|
if (armLength <= (radius / 5)) { |
|
|
|
|
|
armLength = radius / 5 |
|
|
|
|
|
} |
|
|
xyCtx.moveTo(...center); |
|
|
xyCtx.moveTo(...center); |
|
|
xyCtx.lineTo(...calculateIntersection(...center, diameter, curRotation)); |
|
|
xyCtx.lineTo( |
|
|
// 配重臂
|
|
|
...calculateIntersection( |
|
|
|
|
|
...center, |
|
|
|
|
|
armLength, // 臂长
|
|
|
|
|
|
curRotation |
|
|
|
|
|
) |
|
|
|
|
|
); |
|
|
|
|
|
// 配重臂 - 尾巴
|
|
|
xyCtx.moveTo(...center); |
|
|
xyCtx.moveTo(...center); |
|
|
xyCtx.lineTo(...calculateIntersection(...center, diameter / 8, curRotation + 180)); |
|
|
xyCtx.lineTo(...calculateIntersection(...center, diameter / 8, curRotation + 180)); |
|
|
xyCtx.strokeStyle = mainColor; |
|
|
xyCtx.strokeStyle = mainColor; |
|
|
xyCtx.stroke(); |
|
|
xyCtx.stroke(); |
|
|
// 索
|
|
|
// 索 - 激光雷达 小点儿
|
|
|
xyCtx.beginPath(); |
|
|
xyCtx.beginPath(); |
|
|
xyCtx.arc(...calculateIntersection(...center, 168, curRotation), diameter / 48, 0, 2 * Math.PI); |
|
|
xyCtx.arc( |
|
|
xyCtx.fillStyle = mainColor; |
|
|
...calculateIntersection( |
|
|
|
|
|
...center, |
|
|
|
|
|
(params.lidar / radiusRate) * 2, // 绘制的离圆心的距离
|
|
|
|
|
|
curRotation |
|
|
|
|
|
), |
|
|
|
|
|
diameter / 128, // 点的大小
|
|
|
|
|
|
0, |
|
|
|
|
|
2 * Math.PI |
|
|
|
|
|
); |
|
|
|
|
|
xyCtx.fillStyle = dangerColor; |
|
|
|
|
|
xyCtx.fill(); |
|
|
|
|
|
xyCtx.stroke(); |
|
|
|
|
|
// 障碍物
|
|
|
|
|
|
// 测试数据
|
|
|
|
|
|
// params.blocks = [
|
|
|
|
|
|
// [
|
|
|
|
|
|
// {
|
|
|
|
|
|
// "X": 324,
|
|
|
|
|
|
// "Y": 231
|
|
|
|
|
|
// },
|
|
|
|
|
|
// {
|
|
|
|
|
|
// "X": 654,
|
|
|
|
|
|
// "Y": 234
|
|
|
|
|
|
// },
|
|
|
|
|
|
// {
|
|
|
|
|
|
// "X": 453,
|
|
|
|
|
|
// "Y": 231
|
|
|
|
|
|
// },
|
|
|
|
|
|
// {
|
|
|
|
|
|
// "X": 452,
|
|
|
|
|
|
// "Y": 34
|
|
|
|
|
|
// },
|
|
|
|
|
|
// {
|
|
|
|
|
|
// "X": 453,
|
|
|
|
|
|
// "Y": 34
|
|
|
|
|
|
// },
|
|
|
|
|
|
// {
|
|
|
|
|
|
// "X": 45,
|
|
|
|
|
|
// "Y": 67
|
|
|
|
|
|
// }
|
|
|
|
|
|
// ]
|
|
|
|
|
|
// ]
|
|
|
|
|
|
if (params.blocks && params.blocks.length) { |
|
|
|
|
|
for (let block of params.blocks) { |
|
|
|
|
|
if (block && block.length) { |
|
|
|
|
|
for (let i = 0; i < block.length; i++) { |
|
|
|
|
|
let point = block[i] |
|
|
|
|
|
const x = point.X / radiusRate + center[0]; |
|
|
|
|
|
const y = point.Y / radiusRate + center[1]; |
|
|
|
|
|
if (i == 0) { |
|
|
|
|
|
xyCtx.beginPath(); |
|
|
|
|
|
xyCtx.moveTo(x, y); |
|
|
|
|
|
} else { |
|
|
|
|
|
xyCtx.lineTo(x, y); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
xyCtx.closePath(); |
|
|
|
|
|
xyCtx.lineWidth = 1; |
|
|
|
|
|
xyCtx.strokeStyle = dangerColor; |
|
|
|
|
|
xyCtx.fillStyle = dangerColor; |
|
|
xyCtx.fill(); |
|
|
xyCtx.fill(); |
|
|
xyCtx.stroke(); |
|
|
xyCtx.stroke(); |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
if (type == 'xz') { |
|
|
if (type == 'xz') { |
|
|
// xz 视图
|
|
|
// xz 视图
|
|
|
const xzCtx = xzCvs.current.getContext("2d"); |
|
|
const xzCtx = xzCvs.current.getContext("2d"); |
|
@ -433,31 +541,183 @@ function Index (props) { |
|
|
dispatch(getCrane()) |
|
|
dispatch(getCrane()) |
|
|
|
|
|
|
|
|
//
|
|
|
//
|
|
|
|
|
|
|
|
|
const root = window.FS_API_ROOT |
|
|
const root = window.FS_API_ROOT |
|
|
ws = new WebSocket(`${root.replace('http', 'ws')}/${ApiTable.dataLive}`); //建立websocket连接
|
|
|
|
|
|
ws.onopen = function (e) { |
|
|
dataLiveWs = new WebSocket(`${root.replace('http', 'ws')}/${ApiTable.dataLive}`); //建立websocket连接
|
|
|
interval = setInterval(() => { |
|
|
dataLiveWs.onopen = function (e) { |
|
|
|
|
|
dataLiveWsInterval = setInterval(() => { |
|
|
// console.log("发送心跳保持长连接不超时断开");
|
|
|
// console.log("发送心跳保持长连接不超时断开");
|
|
|
this.send(JSON.stringify({ "act": "long_live" })); |
|
|
this.send(JSON.stringify({ "act": "long_live" })); |
|
|
}, 20000);//20秒一次
|
|
|
}, 20000);//20秒一次
|
|
|
} |
|
|
} |
|
|
ws.onerror = e => { |
|
|
dataLiveWs.onerror = e => { |
|
|
console.log("websocket 发生错误:" + e) |
|
|
console.log("websocket dataLiveWs 发生错误:" + e) |
|
|
} |
|
|
} |
|
|
ws.onmessage = evt => { |
|
|
dataLiveWs.onmessage = evt => { |
|
|
let msg = JSON.parse(evt.data); |
|
|
let msg = JSON.parse(evt.data); |
|
|
|
|
|
|
|
|
if (msg) { |
|
|
if (msg) { |
|
|
setCraneParams(msg) |
|
|
setCraneParams(msg) |
|
|
draw('xy', msg) |
|
|
// draw('xy', msg)
|
|
|
draw('xz', msg) |
|
|
// draw('xz', msg)
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
lidarLiveWs = new WebSocket(`${root.replace('http', 'ws')}/${ApiTable.lidarLive}`); //建立websocket连接
|
|
|
|
|
|
lidarLiveWs.onopen = function (e) { |
|
|
|
|
|
lidarLiveWsInterval = setInterval(() => { |
|
|
|
|
|
// console.log("发送心跳保持长连接不超时断开");
|
|
|
|
|
|
this.send(JSON.stringify({ "act": "long_live" })); |
|
|
|
|
|
}, 20000);//20秒一次
|
|
|
|
|
|
} |
|
|
|
|
|
lidarLiveWs.onerror = e => { |
|
|
|
|
|
console.log("websocket lidarLiveWs 发生错误:" + e) |
|
|
|
|
|
} |
|
|
|
|
|
lidarLiveWs.onmessage = evt => { |
|
|
|
|
|
let msg = JSON.parse(evt.data); |
|
|
|
|
|
|
|
|
|
|
|
if (msg) { |
|
|
|
|
|
// console.log(msg);
|
|
|
|
|
|
draw('xy', { |
|
|
|
|
|
...msg, |
|
|
|
|
|
from: 'lidarLive', |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
dispatch(getVideo()).then(res => { |
|
|
|
|
|
if ( |
|
|
|
|
|
res.success |
|
|
|
|
|
) { |
|
|
|
|
|
try { |
|
|
|
|
|
setVideo(res.payload.data) |
|
|
|
|
|
const container = document.getElementById('video-play'); |
|
|
|
|
|
console.log(`准备播放`, res.payload.data.ws_flv); |
|
|
|
|
|
// 播放方式 1
|
|
|
|
|
|
const playJessibuca = () => { |
|
|
|
|
|
const jessibuca = new window.Jessibuca({ |
|
|
|
|
|
container: container, |
|
|
|
|
|
videoBuffer: 0.2, // 缓存时长
|
|
|
|
|
|
isResize: false, |
|
|
|
|
|
text: "", |
|
|
|
|
|
loadingText: "加载中", |
|
|
|
|
|
debug: true, |
|
|
|
|
|
showBandwidth: false, // 显示网速
|
|
|
|
|
|
showBandwidth: false, |
|
|
|
|
|
operateBtns: { |
|
|
|
|
|
fullscreen: false, |
|
|
|
|
|
screenshot: false, |
|
|
|
|
|
play: false, |
|
|
|
|
|
audio: false, |
|
|
|
|
|
|
|
|
|
|
|
fullscreen: true, |
|
|
|
|
|
screenshot: true, |
|
|
|
|
|
play: true, |
|
|
|
|
|
audio: true, |
|
|
|
|
|
}, |
|
|
|
|
|
forceNoOffscreen: false, |
|
|
|
|
|
controlAutoHide: true, |
|
|
|
|
|
isNotMute: false, |
|
|
|
|
|
|
|
|
|
|
|
// useMSE:true,
|
|
|
|
|
|
// autoWasm:true
|
|
|
|
|
|
}); |
|
|
|
|
|
jessibucas.current = jessibuca |
|
|
|
|
|
jessibuca.play( |
|
|
|
|
|
// `http://flv.bdplay.nodemedia.cn/live/bbb.flv`
|
|
|
|
|
|
// `ws://localhost:8081/jessica/34020000001320000001/34020000001320000001.flv`
|
|
|
|
|
|
`${res.payload.data.ws_flv}` |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
playJessibuca() |
|
|
|
|
|
|
|
|
|
|
|
jessibucasInterval = setInterval(() => { |
|
|
|
|
|
jessibucas.current.destroy() |
|
|
|
|
|
playJessibuca() |
|
|
|
|
|
}, |
|
|
|
|
|
1000 * 60 * 30 |
|
|
|
|
|
// 1000 * 10
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 播放方式 2
|
|
|
|
|
|
// const flv = flvjs.createPlayer({
|
|
|
|
|
|
// type: 'flv',
|
|
|
|
|
|
// url: `${res.payload.data.ws_flv}`,
|
|
|
|
|
|
// isLive: true,
|
|
|
|
|
|
// hasAudio: false,
|
|
|
|
|
|
// hasVideo: true,
|
|
|
|
|
|
// }, {
|
|
|
|
|
|
// enableWorker: false,//分离线程
|
|
|
|
|
|
// enalleStashBuffer: false, //IO隐藏缓冲区
|
|
|
|
|
|
// stashInitialSize: 128,
|
|
|
|
|
|
// isLive: true,
|
|
|
|
|
|
// lazyLoad: false,
|
|
|
|
|
|
// // lazyLoadMaxDuration: 3 * 60,
|
|
|
|
|
|
// lazyLoadMaxDuration: 1,
|
|
|
|
|
|
// seekType: 'range',
|
|
|
|
|
|
// autoCleanupSourceBuffer: true,
|
|
|
|
|
|
// // cors: true,
|
|
|
|
|
|
// // stashInitialSize: 1024
|
|
|
|
|
|
// });
|
|
|
|
|
|
// flv.attachMediaElement(container);
|
|
|
|
|
|
// flv.load();
|
|
|
|
|
|
|
|
|
|
|
|
// try {
|
|
|
|
|
|
// // 初始化 _remuxer
|
|
|
|
|
|
// let controller = flv?._transmuxer?._controller
|
|
|
|
|
|
// controller._remuxer = {
|
|
|
|
|
|
// flushStashedSamples: function () {
|
|
|
|
|
|
// console.log("flushStashedSamples")
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// } catch (error) {
|
|
|
|
|
|
// console.error(error);
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// flv.play();
|
|
|
|
|
|
// flvPlayer.current = flv
|
|
|
|
|
|
|
|
|
|
|
|
/** 尝试解决播放延迟问题 */ |
|
|
|
|
|
if (flvPlayerInterval) { |
|
|
|
|
|
clearInterval(flvPlayerInterval) |
|
|
|
|
|
} |
|
|
|
|
|
// flvPlayerInterval = setInterval(() => {
|
|
|
|
|
|
// console.log(flv.buffered);
|
|
|
|
|
|
// if (flv.buffered.length) {
|
|
|
|
|
|
// let end = flv.buffered.end(0);//获取当前buffered值
|
|
|
|
|
|
// let diff = end - flv.currentTime;//获取buffered与currentTime的差值
|
|
|
|
|
|
// if (diff >= 3) {//如果差值大于等于0.5 手动跳帧 这里可根据自身需求来定
|
|
|
|
|
|
// console.log(222222222);
|
|
|
|
|
|
// flv.currentTime = flv.buffered.end(0);//手动跳帧
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }, 1000 * 10);
|
|
|
|
|
|
/** 尝试 END */ |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error(error); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
return () => { |
|
|
return () => { |
|
|
if (ws) { |
|
|
if (dataLiveWs) { |
|
|
ws.close();//关闭连接
|
|
|
window.clearInterval(dataLiveWsInterval); |
|
|
window.clearInterval(interval); |
|
|
dataLiveWs.close();//关闭连接
|
|
|
|
|
|
} |
|
|
|
|
|
if (lidarLiveWs) { |
|
|
|
|
|
window.clearInterval(lidarLiveWsInterval); |
|
|
|
|
|
lidarLiveWs.close();//关闭连接
|
|
|
|
|
|
} |
|
|
|
|
|
if (jessibucas.current) { |
|
|
|
|
|
jessibucas.current.destroy() |
|
|
|
|
|
} |
|
|
|
|
|
if (jessibucasInterval.current) { |
|
|
|
|
|
clearInterval(jessibucasInterval.current) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}, []) |
|
|
}, []) |
|
@ -473,11 +733,16 @@ function Index (props) { |
|
|
color: darkModde ? darkColor.textColor : 'auto', |
|
|
color: darkModde ? darkColor.textColor : 'auto', |
|
|
background: darkModde ? darkColor.background : 'auto' |
|
|
background: darkModde ? darkColor.background : 'auto' |
|
|
}}> |
|
|
}}> |
|
|
<div style={{ padding: '0 8px 8px', textAlign: 'right' }}> |
|
|
<div style={{ padding: '0 8px 8px', }}> |
|
|
<Space> |
|
|
<Space> |
|
|
<Button type="primary" size={'large'} style={{}} icon={<VideoCameraOutlined />} onClick={() => { }}> |
|
|
<Button type="danger" size={'large'} style={{}} icon={<LogoutOutlined />} onClick={() => { setIsOutModalOpen(true) }}> |
|
|
监控视频 |
|
|
退出 |
|
|
</Button> |
|
|
</Button> |
|
|
|
|
|
</Space> |
|
|
|
|
|
<Space style={{ float: 'right' }}> |
|
|
|
|
|
{/* <Button type="primary" size={'large'} style={{}} icon={<VideoCameraOutlined />} onClick={() => { setVideoVis(true) }}> |
|
|
|
|
|
监控视频 |
|
|
|
|
|
</Button> */} |
|
|
<Button type="primary" size={'large'} style={{}} icon={<SettingOutlined />} onClick={() => setIsModalOpen(true)}> |
|
|
<Button type="primary" size={'large'} style={{}} icon={<SettingOutlined />} onClick={() => setIsModalOpen(true)}> |
|
|
设置 |
|
|
设置 |
|
|
</Button> |
|
|
</Button> |
|
@ -485,15 +750,37 @@ function Index (props) { |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div style={{ height: 'calc(80% - 40px)', padding: 8 }}> |
|
|
<div style={{ height: 'calc(80% - 40px)', padding: 8 }}> |
|
|
<Row style={{ height: '100%' }}> |
|
|
<Row style={{ |
|
|
<Col span={12} id="canvasArea" style={{ paddingRight: 8, maxHeight: '100%' }}> |
|
|
height: '100%', |
|
|
|
|
|
}}> |
|
|
|
|
|
<Col span={14} id="canvasArea" style={{ paddingRight: 8, maxHeight: '100%' }}> |
|
|
<div className='card' style={cardStyle}> |
|
|
<div className='card' style={cardStyle}> |
|
|
<canvas ref={xzCvs} id='xzCvs' height={120} width={120} style={{}}> |
|
|
<canvas ref={xzCvs} id='xzCvs' height={120} width={120} style={{ display: 'none' }}> |
|
|
您的浏览器不支持canvas,请更换浏览器. |
|
|
您的浏览器不支持canvas,请更换浏览器. |
|
|
</canvas> |
|
|
</canvas> |
|
|
|
|
|
{/* video 配合 flvjs 使用 */} |
|
|
|
|
|
{/* <video |
|
|
|
|
|
className='card' |
|
|
|
|
|
id={'video-play'} |
|
|
|
|
|
autoPlay |
|
|
|
|
|
// muted
|
|
|
|
|
|
controls |
|
|
|
|
|
style={{ height: '100%', width: '100%', }} |
|
|
|
|
|
> |
|
|
|
|
|
|
|
|
|
|
|
</video> */} |
|
|
|
|
|
|
|
|
|
|
|
{/* 这个 div 配合 解析不卡使用 */} |
|
|
|
|
|
<div |
|
|
|
|
|
className='card' |
|
|
|
|
|
id={'video-play'} |
|
|
|
|
|
style={{ height: '100%', width: '100%', }} |
|
|
|
|
|
> |
|
|
|
|
|
|
|
|
|
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</Col> |
|
|
</Col> |
|
|
<Col span={12} style={{ paddingLeft: 8, }}> |
|
|
<Col span={10} style={{ paddingLeft: 8, }}> |
|
|
<div className='card' style={cardStyle}> |
|
|
<div className='card' style={cardStyle}> |
|
|
<canvas ref={xyCvs} id='xyCvs' height={120} width={120} style={{}}> |
|
|
<canvas ref={xyCvs} id='xyCvs' height={120} width={120} style={{}}> |
|
|
您的浏览器不支持canvas,请更换浏览器. |
|
|
您的浏览器不支持canvas,请更换浏览器. |
|
@ -501,34 +788,18 @@ function Index (props) { |
|
|
</div> |
|
|
</div> |
|
|
</Col> |
|
|
</Col> |
|
|
</Row> |
|
|
</Row> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</div> |
|
|
</div> |
|
|
<div style={{ height: '20%' }}> |
|
|
<div style={{ height: '20%' }}> |
|
|
<Row style={{ height: '100%' }}> |
|
|
<Row style={{ height: '100%' }}> |
|
|
{ |
|
|
{ |
|
|
[{ |
|
|
[{ |
|
|
k: '高度', |
|
|
|
|
|
v: 'tower_height', |
|
|
|
|
|
s: '-', |
|
|
|
|
|
unit: 'm' |
|
|
|
|
|
}, { |
|
|
|
|
|
k: '幅度', |
|
|
|
|
|
v: 'max_amp', |
|
|
|
|
|
s: '-', |
|
|
|
|
|
}, { |
|
|
|
|
|
k: '回转角', |
|
|
k: '回转角', |
|
|
v: 'rotation', |
|
|
v: 'rotation', |
|
|
s: '-', |
|
|
s: '-', |
|
|
unit: '°', |
|
|
unit: '°', |
|
|
dataFrom: 'live', |
|
|
dataFrom: 'live', |
|
|
}, { |
|
|
|
|
|
k: '重量', |
|
|
|
|
|
v: 'x', |
|
|
|
|
|
s: '-', |
|
|
|
|
|
}, { |
|
|
|
|
|
k: '力矩', |
|
|
|
|
|
v: 'max_torque', |
|
|
|
|
|
s: '-', |
|
|
|
|
|
unit: 'KN*m' |
|
|
|
|
|
}, { |
|
|
}, { |
|
|
k: '俯仰角', |
|
|
k: '俯仰角', |
|
|
v: 'pitch', |
|
|
v: 'pitch', |
|
@ -536,15 +807,35 @@ function Index (props) { |
|
|
unit: '°', |
|
|
unit: '°', |
|
|
dataFrom: 'live', |
|
|
dataFrom: 'live', |
|
|
}, { |
|
|
}, { |
|
|
k: '倾斜角', |
|
|
k: '碰撞距离', |
|
|
v: 'inclination', |
|
|
v: 'lidar', |
|
|
s: '-', |
|
|
s: '-', |
|
|
unit: '°', |
|
|
unit: 'm', |
|
|
dataFrom: 'live', |
|
|
dataFrom: 'live', |
|
|
}, { |
|
|
}, { |
|
|
k: '', |
|
|
// k: '高度',
|
|
|
v: '', |
|
|
// v: 'tower_height',
|
|
|
s: '', |
|
|
// s: '-',
|
|
|
|
|
|
// unit: 'm'
|
|
|
|
|
|
}, { |
|
|
|
|
|
// k: '幅度',
|
|
|
|
|
|
// v: 'max_amp',
|
|
|
|
|
|
// s: '-',
|
|
|
|
|
|
}, { |
|
|
|
|
|
// k: '重量',
|
|
|
|
|
|
// v: 'x',
|
|
|
|
|
|
// s: '-',
|
|
|
|
|
|
}, { |
|
|
|
|
|
// k: '力矩',
|
|
|
|
|
|
// v: 'max_torque',
|
|
|
|
|
|
// s: '-',
|
|
|
|
|
|
// unit: 'KN*m'
|
|
|
|
|
|
}, { |
|
|
|
|
|
// k: '倾斜角',
|
|
|
|
|
|
// v: 'inclination',
|
|
|
|
|
|
// s: '-',
|
|
|
|
|
|
// unit: '°',
|
|
|
|
|
|
// dataFrom: 'live',
|
|
|
},].map(s => { |
|
|
},].map(s => { |
|
|
return ( |
|
|
return ( |
|
|
<Col span={3} style={{ |
|
|
<Col span={3} style={{ |
|
@ -552,7 +843,9 @@ function Index (props) { |
|
|
background: |
|
|
background: |
|
|
darkModde ? darkColor.background : 'auto' |
|
|
darkModde ? darkColor.background : 'auto' |
|
|
}}> |
|
|
}}> |
|
|
<div className="card" style={cardStyle}> |
|
|
<div className="card" style={Object.assign({}, cardStyle, { |
|
|
|
|
|
boxShadow: `0 0 10px ${s.dataFrom === 'live' && craneParams[s.v]?.Warn ? Colors.pickColorWithAlarmLevel(craneParams[s.v]?.Warn) : darkModde ? darkColor.shadow : 'rgba(0, 0, 0, 0.2)'}`, |
|
|
|
|
|
})}> |
|
|
{ |
|
|
{ |
|
|
s.k ? |
|
|
s.k ? |
|
|
<> |
|
|
<> |
|
@ -563,7 +856,7 @@ function Index (props) { |
|
|
{ |
|
|
{ |
|
|
s.dataFrom === 'live' ? |
|
|
s.dataFrom === 'live' ? |
|
|
( |
|
|
( |
|
|
craneParams[s.v]?.Value || '-' |
|
|
craneParams[s.v]?.Value || craneParams[s.v]?.Value == 0 ? craneParams[s.v]?.Value : '-' |
|
|
) + ( |
|
|
) + ( |
|
|
craneParams[s.v] && s.unit ? s.unit : '' |
|
|
craneParams[s.v] && s.unit ? s.unit : '' |
|
|
) |
|
|
) |
|
@ -576,7 +869,7 @@ function Index (props) { |
|
|
} |
|
|
} |
|
|
</p> |
|
|
</p> |
|
|
<span className="status" style={{ |
|
|
<span className="status" style={{ |
|
|
backgroundColor: s.dataFrom === 'live' && craneParams[s.v]?.Warn ? Colors.getAlarmLevelColors(craneParams[s.v]?.Warn) : undefined |
|
|
backgroundColor: s.dataFrom === 'live' && craneParams[s.v]?.Warn ? Colors.pickColorWithAlarmLevel(craneParams[s.v]?.Warn) : undefined |
|
|
}}> |
|
|
}}> |
|
|
{ |
|
|
{ |
|
|
s.dataFrom === 'live' ? |
|
|
s.dataFrom === 'live' ? |
|
@ -605,6 +898,20 @@ function Index (props) { |
|
|
> |
|
|
> |
|
|
<Input.Password size="large" placeholder="请输入密码" /> |
|
|
<Input.Password size="large" placeholder="请输入密码" /> |
|
|
</Modal> |
|
|
</Modal> |
|
|
|
|
|
<Modal title="退出应用" open={isOutModalOpen} |
|
|
|
|
|
onOk={() => { |
|
|
|
|
|
dispatch(logoutApp()); |
|
|
|
|
|
}} |
|
|
|
|
|
onCancel={() => { |
|
|
|
|
|
setIsOutModalOpen(false) |
|
|
|
|
|
}} |
|
|
|
|
|
> |
|
|
|
|
|
<span style={{ fontSize: 'large', fontWeight: 'bolder' }}>确定退出应用吗?</span> |
|
|
|
|
|
</Modal> |
|
|
|
|
|
{ |
|
|
|
|
|
videoVis ? |
|
|
|
|
|
<VideoModal onCancel={() => { setVideoVis(false) }} /> : '' |
|
|
|
|
|
} |
|
|
</div> |
|
|
</div> |
|
|
) |
|
|
) |
|
|
} |
|
|
} |
|
|