Browse Source

master 同步分支数据

master
CODE 1 year ago
parent
commit
66aedb8ccd
  1. 2
      .gitignore
  2. 2
      console/client/assets/env.js
  3. 26
      console/client/src/sections/console/actions/index.js
  4. 71
      console/client/src/sections/console/components/videoModal.js
  5. 425
      console/client/src/sections/console/containers/index.js
  6. 123
      console/client/src/sections/console/containers/setUp.js
  7. 3
      console/client/src/utils/webapi.js
  8. 18002
      console/package-lock.json
  9. 207
      console/package.json

2
.gitignore

@ -0,0 +1,2 @@
*development.txt
console/log/development.txt

2
console/client/assets/env.js

@ -1 +1 @@
window.FS_API_ROOT = 'http://10.8.30.183:4100' window.FS_API_ROOT = 'http://127.0.0.1:4100'

26
console/client/src/sections/console/actions/index.js

@ -26,7 +26,33 @@ export function getCrane (params) {
}); });
} }
export function getVideo (params) {
return dispatch => basicAction({
type: 'get',
query: params,
dispatch: dispatch,
actionType: 'GET_VIDEO',
url: ApiTable.videoGet,
msg: { error: '获取视频信息失败' },
reducer: { name: 'video' }
});
}
export function logoutApp (params) {
return dispatch => basicAction({
type: 'post',
query: params,
dispatch: dispatch,
actionType: 'LOGOUT_APP',
url: ApiTable.logoutApp,
msg: { error: '退出应用失败' },
});
}
export default { export default {
editCrane, editCrane,
getCrane, getCrane,
getVideo,
logoutApp,
} }

71
console/client/src/sections/console/components/videoModal.js

@ -0,0 +1,71 @@
import React, { useEffect, useState, useRef } from 'react'
import { push } from 'react-router-redux';
import { connect } from 'react-redux';
import flvjs from 'flv.js'
import { getVideo } from '../actions'
import { Modal } from 'antd'
const VideoModal = ({ dispatch, onCancel }) => {
const [video, setVideo] = useState({})
const flvPlayer = useRef()
useEffect(() => {
dispatch(getVideo()).then(res => {
console.log(res);
if (res.success) {
setVideo(res.payload.data)
const container = document.getElementById('video-play');
const flv = flvjs.createPlayer({
type: 'flv',
url: `${res.payload.data.ws_flv}`,
isLive: true,
hasAudio: false,
hasVideo: true,
}, {
enableWorker: false,
enalleStashBuffer: true,
stashInitialSize: 128,
lazyLoadMaxDuration: 3 * 60,
seekType: 'range',
autoCleanupSourceBuffer: true,
cors: true,
});
flv.attachMediaElement(container);
flv.load();
flv.play();
flvPlayer.current = flv
}
})
}, [])
return (
<Modal
title="监控视频"
open={true}
onOk={() => { }}
onCancel={() => {
onCancel()
}}
width={'64%'}
style={{}}
footer={null}
>
<video
id={'video-play'}
autoPlay muted controls
style={{ height: '100%', width: '100%', }}
>
</video>
</Modal>
)
}
function mapStateToProps (state) {
const { crane } = state;
return {
craneData: crane.data || {}
}
}
export default connect(mapStateToProps)(VideoModal);

425
console/client/src/sections/console/containers/index.js

@ -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,21 +121,92 @@ 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.fill();
xyCtx.stroke(); 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.stroke();
}
}
}
} }
if (type == 'xz') { if (type == 'xz') {
// xz 视图 // xz 视图
@ -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>
) )
} }

123
console/client/src/sections/console/containers/setUp.js

@ -2,20 +2,22 @@ import React, { useEffect, useState, useRef } from 'react'
import { push } from 'react-router-redux'; import { push } from 'react-router-redux';
import request from 'superagent'; import request from 'superagent';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { editCrane } from '../actions' import { editCrane, getCrane } from '../actions'
import { import {
BorderlessTableOutlined, BlockOutlined, RollbackOutlined, SaveOutlined BorderlessTableOutlined, BlockOutlined, RollbackOutlined, SaveOutlined, AimOutlined
} from '@ant-design/icons'; } from '@ant-design/icons';
import { Col, Row, Button, Modal, Form, Input, InputNumber, message } from 'antd'; import { Col, Row, Button, Modal, Form, Input, InputNumber, message, Switch } from 'antd';
import '../style.less' import '../style.less'
function SetUp ({ dispatch }) { function SetUp ({ dispatch, craneData }) {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [renderMenu, setRenderMenu] = useState([]) const [renderMenu, setRenderMenu] = useState([])
const [renderForm, setRenderForm] = useState(false) const [renderForm, setRenderForm] = useState(false)
const [formItems, setFormItems] = useState([]) const [formItems, setFormItems] = useState([])
const [formIndex, setFormIndex] = useState(0) const [formIndex, setFormIndex] = useState(0)
const craneDataRef = useRef(craneData)
const [levelOneMenu] = useState([{ const [levelOneMenu] = useState([{
n: '参数标定', n: '参数标定',
ic: <BlockOutlined className='setup-icon' />, ic: <BlockOutlined className='setup-icon' />,
@ -24,7 +26,40 @@ function SetUp ({ dispatch }) {
} }
}, { }, {
n: '限位告警参数', n: '限位告警参数',
ic: <BorderlessTableOutlined className='setup-icon' /> ic: <BorderlessTableOutlined className='setup-icon' />,
click: () => {
setRenderForm(true)
setFormIndex(1)
setFormItems([
{
label: '设备编号',
name: 'device_no',
type: 'string',
disabled: true,
},
{
label: '1级碰撞距离',
name: 'dis_level_1',
type: 'number',
},
{
label: '3级碰撞距离',
name: 'dis_level_3',
type: 'number',
},
{
label: '是否静音',
name: 'mute',
type: 'boolean',
},
{
label: '2级碰撞距离',
name: 'dis_level_2',
type: 'number',
},
])
initData()
}
}, { }, {
n: '返回', n: '返回',
ic: <RollbackOutlined className='setup-icon' />, ic: <RollbackOutlined className='setup-icon' />,
@ -48,6 +83,7 @@ function SetUp ({ dispatch }) {
label: '设备编号', label: '设备编号',
name: 'device_no', name: 'device_no',
type: 'string', type: 'string',
disabled: true,
}, },
{ {
label: '经度', label: '经度',
@ -115,6 +151,38 @@ function SetUp ({ dispatch }) {
type: 'number', type: 'number',
}, },
]) ])
initData()
}
}, {
n: '传感器参数',
ic: <AimOutlined className='setup-icon' />,
click: () => {
setRenderForm(true)
setFormIndex(1)
setFormItems([
{
label: '设备编号',
name: 'device_no',
type: 'string',
disabled: true,
},
{
label: '测斜仪模块号',
name: 'hgc_module',
type: 'string',
},
{
label: '串口配置1',
name: 'serial_port',
type: 'string',
},
{
label: '串口配置2',
name: 'serial_port2',
type: 'string',
},
])
initData()
} }
}, { }, {
n: '返回', n: '返回',
@ -141,8 +209,21 @@ function SetUp ({ dispatch }) {
) )
} }
const initData = (craneData_) => {
setTimeout(() => {
form.setFieldsValue({
...(craneData_ || craneDataRef.current || craneData)
})
}, 300)
}
useEffect(() => {
craneDataRef.current = craneData
initData(craneData)
}, [craneData])
return ( return (
<div style={{ height: '100vh' }}> <div style={{ height: '100vh', background: '#000' }}>
{ {
!renderForm ? !renderForm ?
<div style={{ display: 'flex', height: '100%', justifyContent: 'center', alignItems: 'center' }}> <div style={{ display: 'flex', height: '100%', justifyContent: 'center', alignItems: 'center' }}>
@ -162,7 +243,7 @@ function SetUp ({ dispatch }) {
wrapperCol: { wrapperCol: {
span: 18, span: 18,
}, },
}} name="control-hooks" size='large'> }} name="control-hooks" size='large' style={{ display: 'flex', flexDirection: 'column', height: '95%', justifyContent: 'space-between', }}>
<Row style={{ padding: '8% 12% 0' }}> <Row style={{ padding: '8% 12% 0' }}>
{ {
(() => { (() => {
@ -176,15 +257,21 @@ function SetUp ({ dispatch }) {
key={index} key={index}
name={item.name} name={item.name}
label={item.label} label={item.label}
// rules={[{ // rules={[{
// // required: true, // // required: true,
// // message: '请输入' + item.label // // message: '请输入' + item.label
// }]} // }]}
valuePropName={item.type == 'boolean' ? "checked" : undefined}
> >
{ {
item.type === 'number' ? item.type === 'number' ?
<InputNumber style={{ width: '100%' }} /> : <InputNumber style={{ width: '100%' }} disabled={item.disabled} />
<Input /> :
item.type == 'boolean' ?
<Switch checkedChildren="开启" unCheckedChildren="关闭" defaultChecked size={'large'} disabled={item.disabled} />
:
<Input disabled={item.disabled} />
} }
</Form.Item> </Form.Item>
@ -210,10 +297,11 @@ function SetUp ({ dispatch }) {
ic: <SaveOutlined className='setup-icon' />, ic: <SaveOutlined className='setup-icon' />,
click: () => { click: () => {
if (formIndex == 1) { if (formIndex == 1) {
const values = form.getFieldsValue() let values = form.getFieldsValue()
dispatch(editCrane(values)).then(res => { dispatch(editCrane({ ...craneData, ...values })).then(res => {
if (res.success) { if (res.success) {
message.success('修改配置信息成功') message.success('修改配置信息成功')
dispatch(getCrane())
} else { } else {
message.error('修改配置信息失败') message.error('修改配置信息失败')
} }
@ -238,15 +326,14 @@ function SetUp ({ dispatch }) {
<div> <div>
</div> </div>
</div> </div>
) )
} }
function mapStateToProps (state) { function mapStateToProps (state) {
const { auth } = state; const { crane } = state;
return { return {
craneData: crane.data || {}
} }
} }

3
console/client/src/utils/webapi.js

@ -10,6 +10,9 @@ export const ApiTable = {
dataLatest: 'v1/data/latest', dataLatest: 'v1/data/latest',
craneSetting: 'v1/settings', craneSetting: 'v1/settings',
dataLive: 'v1/data/live', dataLive: 'v1/data/live',
lidarLive: 'v1/lidar/live',
videoGet: 'v1/video/get',
logoutApp: 'v1/shutdown',
}; };
export const RouteTable = { export const RouteTable = {

18002
console/package-lock.json

File diff suppressed because it is too large

207
console/package.json

@ -1,105 +1,106 @@
{ {
"name": "fs-anxincloud-4.0", "name": "fs-anxincloud-4.0",
"version": "1.0.0", "version": "1.0.0",
"description": "anxincloud-4.0", "description": "anxincloud-4.0",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
"elctr": "electron .", "elctr": "electron .",
"test": "mocha", "test": "mocha",
"start-elctr-forge": "electron-forge start", "start-elctr-forge": "electron-forge start",
"start": "cross-env NODE_ENV=development npm run start-params", "start": "cross-env NODE_ENV=development npm run start-params",
"start-params": "node server -p 5400 -u http://10.8.30.183:4100", "start-params": "node server -p 5400 -u http://127.0.0.1:4100",
"deploy": "export NODE_ENV=production && npm run build && node server", "deploy": "export NODE_ENV=production && npm run build && node server",
"build-dev": "set NODE_ENV=development&&webpack --config webpack.config.js", "build-dev": "set NODE_ENV=development&&webpack --config webpack.config.js",
"build": "set NODE_ENV=production&&webpack --config webpack.config.prod.js", "build": "set NODE_ENV=production&&webpack --config webpack.config.prod.js",
"package": "electron-forge package", "package": "electron-forge package",
"make": "electron-forge make" "make": "electron-forge make"
}, },
"keywords": [ "keywords": [
"app" "app"
], ],
"author": "fs", "author": "fs",
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@babel/core": "^7.14.6", "@babel/core": "^7.14.6",
"@babel/plugin-proposal-class-properties": "^7.14.5", "@babel/plugin-proposal-class-properties": "^7.14.5",
"@babel/plugin-proposal-object-rest-spread": "^7.14.7", "@babel/plugin-proposal-object-rest-spread": "^7.14.7",
"@babel/plugin-transform-runtime": "^7.14.5", "@babel/plugin-transform-runtime": "^7.14.5",
"@babel/polyfill": "^7.12.1", "@babel/polyfill": "^7.12.1",
"@babel/preset-env": "^7.14.7", "@babel/preset-env": "^7.14.7",
"@babel/preset-react": "^7.14.5", "@babel/preset-react": "^7.14.5",
"@electron-forge/cli": "^6.0.5", "@electron-forge/cli": "^6.0.5",
"@electron-forge/maker-deb": "^6.0.5", "@electron-forge/maker-deb": "^6.0.5",
"@electron-forge/maker-rpm": "^6.0.5", "@electron-forge/maker-rpm": "^6.0.5",
"@electron-forge/maker-squirrel": "^6.0.5", "@electron-forge/maker-squirrel": "^6.0.5",
"@electron-forge/maker-zip": "^6.0.5", "@electron-forge/maker-zip": "^6.0.5",
"babel-loader": "^8.2.2", "babel-loader": "^8.2.2",
"babel-plugin-import": "^1.13.3", "babel-plugin-import": "^1.13.3",
"babel-polyfill": "^6.26.0", "babel-polyfill": "^6.26.0",
"connected-react-router": "^6.8.0", "connected-react-router": "^6.8.0",
"css-loader": "^3.5.0", "css-loader": "^3.5.0",
"electron": "^23.1.3", "electron": "^23.1.3",
"electron-reloader": "^1.2.3", "electron-reloader": "^1.2.3",
"express": "^4.17.1", "express": "^4.17.1",
"file-loader": "^6.0.0", "file-loader": "^6.0.0",
"html-webpack-plugin": "^4.5.0", "html-webpack-plugin": "^4.5.0",
"immutable": "^4.0.0-rc.12", "immutable": "^4.0.0-rc.12",
"less": "^3.12.2", "less": "^3.12.2",
"less-loader": "^7.0.2", "less-loader": "^7.0.2",
"natty-fetch": "^2.5.3", "natty-fetch": "^2.5.3",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"path-to-regexp": "^2.4.0", "path-to-regexp": "^2.4.0",
"perfect-scrollbar": "^1.5.5", "perfect-scrollbar": "^1.5.5",
"react": "^17.0.0", "react": "^17.0.0",
"react-copy-to-clipboard": "^5.0.1", "react-copy-to-clipboard": "^5.0.1",
"react-dnd": "^10.0.2", "react-dnd": "^10.0.2",
"react-dnd-html5-backend": "^10.0.2", "react-dnd-html5-backend": "^10.0.2",
"react-dom": "^17.0.0", "react-dom": "^17.0.0",
"react-if": "^2.2.1", "react-if": "^2.2.1",
"react-jsonschema-form": "^1.8.1", "react-jsonschema-form": "^1.8.1",
"react-quill": "^1.3.5", "react-quill": "^1.3.5",
"react-redux": "^7.2.1", "react-redux": "^7.2.1",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-router-redux": "^4.0.8", "react-router-redux": "^4.0.8",
"redux": "^4.0.5", "redux": "^4.0.5",
"redux-thunk": "^2.3.0", "redux-thunk": "^2.3.0",
"redux-undo": "^1.0.1", "redux-undo": "^1.0.1",
"style-loader": "^2.0.0", "style-loader": "^2.0.0",
"webpack": "^5.3.2", "webpack": "^5.3.2",
"webpack-bundle-analyzer": "^4.1.0", "webpack-bundle-analyzer": "^4.1.0",
"webpack-cli": "^4.2.0", "webpack-cli": "^4.2.0",
"webpack-dev-middleware": "^4.0.2", "webpack-dev-middleware": "^4.0.2",
"webpack-hot-middleware": "^2.25.0" "webpack-hot-middleware": "^2.25.0"
}, },
"dependencies": { "dependencies": {
"@ant-design/icons": "^4.6.2", "@ant-design/icons": "^4.6.2",
"@ant-design/pro-form": "^1.34.0", "@ant-design/pro-form": "^1.34.0",
"@ant-design/pro-table": "^2.48.0", "@ant-design/pro-table": "^2.48.0",
"@antv/g6": "^4.2.5", "@antv/g6": "^4.2.5",
"@fs/attachment": "^1.0.0", "@fs/attachment": "^1.0.0",
"@peace/components": "0.0.35", "@peace/components": "0.0.35",
"@peace/utils": "0.0.37", "@peace/utils": "0.0.37",
"ahooks": "^3.7.4", "ahooks": "^3.7.4",
"ali-oss": "^6.17.1", "ali-oss": "^6.17.1",
"antd": "^4.24.5", "antd": "^4.24.5",
"args": "^5.0.1", "args": "^5.0.1",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"echarts": "^5.4.1", "echarts": "^5.4.1",
"echarts-for-react": "^3.0.2", "echarts-for-react": "^3.0.2",
"electron-squirrel-startup": "^1.0.0", "electron-squirrel-startup": "^1.0.0",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"fs-attachment": "^1.0.0", "flv.js": "^1.6.2",
"fs-web-server-scaffold": "^1.0.6", "fs-attachment": "^1.0.0",
"koa-better-http-proxy": "^0.2.5", "fs-web-server-scaffold": "^1.0.6",
"koa-proxy": "^1.0.0-alpha.3", "koa-better-http-proxy": "^0.2.5",
"koa-view": "^2.1.4", "koa-proxy": "^1.0.0-alpha.3",
"moment": "^2.22.0", "koa-view": "^2.1.4",
"npm": "^7.20.6", "moment": "^2.22.0",
"react-router-breadcrumbs-hoc": "^4.0.1", "npm": "^7.20.6",
"superagent": "^6.1.0", "react-router-breadcrumbs-hoc": "^4.0.1",
"uuid": "^8.3.1", "superagent": "^6.1.0",
"webpack-dev-server": "^3.11.2", "uuid": "^8.3.1",
"xlsx": "^0.16.9" "webpack-dev-server": "^3.11.2",
} "xlsx": "^0.16.9"
}
} }

Loading…
Cancel
Save