封装控制设备 初始哈 xbox显示 优化
This commit is contained in:
4
env.js
4
env.js
@@ -15,8 +15,8 @@ const envConfig = {
|
||||
},
|
||||
[ENV.PROD]: {
|
||||
// baseURL: 'http://192.168.2.56:8081',
|
||||
baseURL: 'http://1.95.137.212:59015',//http://192.168.2.56:8081
|
||||
//baseURL: 'https://serviceri.satabot.com',
|
||||
//baseURL: 'http://1.95.137.212:59015',//http://192.168.2.56:8081
|
||||
baseURL: 'https://serviceri.satabot.com',
|
||||
WS_URL: 'wss://ri.satabot.com/ws/'
|
||||
},
|
||||
};
|
||||
|
||||
@@ -86,6 +86,7 @@ const RobotControlCenter = ({ setView }) => {
|
||||
const [selectedRoute, setSelectedRoute] = useState(null); // ✅ 新增
|
||||
const [activeTab, setActiveTab] = useState<'remote' | 'gps' | 'vizanti'>('remote');
|
||||
const [waypoints, setWaypoints] = useState(INITIAL_WAYPOINTS);
|
||||
const [isConnecting, setIsConnecting] = useState(false); // 连接中状态
|
||||
const [newWaypoint, setNewWaypoint] = useState({ id: 0, lon: '', lat: '' });
|
||||
const [taskIssued, setTaskIssued] = useState(false);
|
||||
const [taskRunning, setTaskRunning] = useState(false);
|
||||
@@ -456,6 +457,8 @@ const RobotControlCenter = ({ setView }) => {
|
||||
|
||||
}
|
||||
const getControl = (serialnum) => {
|
||||
setIsConnecting(true);
|
||||
|
||||
const data = { platform: "web", deviceId: serialnum };
|
||||
getJurisdiction(data).then(res => {
|
||||
if (res?.data?.code === 200 && res?.data?.data?.remoteControl == true) {
|
||||
@@ -470,7 +473,9 @@ const RobotControlCenter = ({ setView }) => {
|
||||
}).catch(err => {
|
||||
controlRef.current = false;
|
||||
setIsControlled(false);
|
||||
})
|
||||
}).finally(() => {
|
||||
setIsConnecting(false);
|
||||
});
|
||||
|
||||
};
|
||||
const handleSelectRobot = async (robot) => {
|
||||
@@ -1541,6 +1546,7 @@ const RobotControlCenter = ({ setView }) => {
|
||||
onGamepadUpdate={handleGamepad}
|
||||
handleControlModal={handleControlModal}
|
||||
isControlled={isControlled}
|
||||
isConnecting={isConnecting}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
|
||||
const XboxController = ({ onGamepadUpdate, handleControlModal, isControlled }) => {
|
||||
const XboxController = ({ onGamepadUpdate, handleControlModal, isControlled, isConnecting }) => {
|
||||
const [gamepadState, setGamepadState] = useState<{
|
||||
buttons: boolean[];
|
||||
axes: number[];
|
||||
@@ -123,15 +123,24 @@ const XboxController = ({ onGamepadUpdate, handleControlModal, isControlled }) =
|
||||
{/* Gamepad Status Badge */}
|
||||
<div
|
||||
className={`absolute top-0 right-0 px-2 py-0.5 rounded text-[8px] font-bold tracking-widest border
|
||||
${connected
|
||||
? (isControlled
|
||||
? 'bg-cyan-500/20 text-cyan-400 border-cyan-500/30' // 控制中:青色样式
|
||||
: 'bg-red-500/20 text-red-400 border-red-500/30') // 无控制权限:红色样式
|
||||
: 'bg-slate-800 text-slate-500 border-white/5'}`} // 无控制器连接:灰色样式
|
||||
|
||||
|
||||
${connected
|
||||
? isConnecting
|
||||
? 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30'
|
||||
: isControlled
|
||||
? 'bg-cyan-500/20 text-cyan-400 border-cyan-500/30'
|
||||
: 'bg-red-500/20 text-red-400 border-red-500/30'
|
||||
: 'bg-slate-800 text-slate-500 border-white/5'
|
||||
}
|
||||
`}
|
||||
>
|
||||
{connected ? isControlled ? '控制中' : '重新选中设备获取控制权限' : '无控制器连接'}
|
||||
{connected
|
||||
? isConnecting
|
||||
? '连接中...'
|
||||
: isControlled
|
||||
? '控制中'
|
||||
: '无控制权限'
|
||||
: '未连接设备'
|
||||
}
|
||||
</div>
|
||||
|
||||
<svg viewBox="0 0 400 300" className="w-full h-full drop-shadow-[0_0_20px_rgba(34,211,238,0.15)]">
|
||||
|
||||
185
src/components/devices/deviceController.js
Normal file
185
src/components/devices/deviceController.js
Normal file
@@ -0,0 +1,185 @@
|
||||
// src/components/device/deviceController.js
|
||||
import { message } from 'antd';
|
||||
import { wsManager } from '../WebSocketManager.ts';
|
||||
import { getControlRight, getJurisdiction } from '../../api/device.ts';
|
||||
import envConfig from '../../../env';
|
||||
|
||||
export default class DeviceController {
|
||||
constructor(userInfo, messageApi) {
|
||||
this.userInfo = userInfo;
|
||||
this.messageApi = messageApi;
|
||||
this.wsUrl = envConfig.WS_URL || 'wss://ri.satabot.com/ws/';
|
||||
|
||||
// 状态
|
||||
this.connectedDeviceSn = null;
|
||||
this.requestDeviceId = '';
|
||||
this.isControlled = false;
|
||||
this.isRequestControl = false;
|
||||
this.hasControlRight = false;
|
||||
this.wsDeviceInfo = {};
|
||||
this.wsStatus = 'disconnected';
|
||||
|
||||
// 回调
|
||||
this.onDeviceInfoUpdate = null;
|
||||
this.onControlStatusChange = null;
|
||||
this.onWsStatusChange = null;
|
||||
this.onPermissionRequest = null;
|
||||
|
||||
// 绑定 this
|
||||
this.handleWsMessage = this.handleWsMessage.bind(this);
|
||||
this.getControl = this.getControl.bind(this);
|
||||
this.connectDevice = this.connectDevice.bind(this);
|
||||
this.sendPermissionRequest = this.sendPermissionRequest.bind(this);
|
||||
}
|
||||
|
||||
// 初始化监听
|
||||
init() {
|
||||
wsManager.onMessage(this.handleWsMessage);
|
||||
wsManager.onStatusChange((status) => {
|
||||
this.wsStatus = status;
|
||||
if (this.onWsStatusChange) this.onWsStatusChange(status);
|
||||
});
|
||||
}
|
||||
|
||||
// 销毁
|
||||
destroy() {
|
||||
wsManager.close();
|
||||
}
|
||||
|
||||
// 获取设备控制权限
|
||||
async getControl(serialnum) {
|
||||
try {
|
||||
const data = { platform: 'web', deviceId: serialnum };
|
||||
const res = await getJurisdiction(data);
|
||||
const ok = res?.code === 200 && res?.data?.remoteControl === true;
|
||||
this.isControlled = ok;
|
||||
if (this.onControlStatusChange) this.onControlStatusChange(ok);
|
||||
} catch (err) {
|
||||
this.isControlled = false;
|
||||
if (this.onControlStatusChange) this.onControlStatusChange(false);
|
||||
}
|
||||
}
|
||||
|
||||
// 连接设备 WebSocket
|
||||
async connectDevice(device) {
|
||||
if (!device) return;
|
||||
const sn = device.serialNumber || device.device_sn;
|
||||
|
||||
wsManager.close();
|
||||
this.connectedDeviceSn = null;
|
||||
this.wsDeviceInfo = {};
|
||||
|
||||
try {
|
||||
const res = await getControlRight({
|
||||
userName: this.userInfo.username,
|
||||
sourceType: 1,
|
||||
token: this.userInfo.token,
|
||||
});
|
||||
|
||||
if (res?.code === 200) {
|
||||
this.hasControlRight = true;
|
||||
wsManager.connect(sn, this.wsUrl);
|
||||
this.connectedDeviceSn = sn;
|
||||
await this.getControl(sn);
|
||||
} else {
|
||||
this.hasControlRight = false;
|
||||
this.messageApi.warning('其他端正在控制');
|
||||
}
|
||||
} catch (err) {
|
||||
this.messageApi.error('权限校验失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 发送权限请求
|
||||
sendPermissionRequest(data, type) {
|
||||
const wsData = {
|
||||
type,
|
||||
switchResult: data,
|
||||
token: this.userInfo.token,
|
||||
deviceId:
|
||||
type === 'switchPermission'
|
||||
? this.connectedDeviceSn
|
||||
: this.requestDeviceId,
|
||||
userName: this.userInfo.username,
|
||||
};
|
||||
wsManager.send(wsData);
|
||||
}
|
||||
|
||||
// 处理外部请求控制
|
||||
requestControl() {
|
||||
if (this.isRequestControl || !this.hasControlRight) {
|
||||
if (!this.hasControlRight) this.messageApi.warning('当前网页端无控制权限');
|
||||
return;
|
||||
}
|
||||
this.isRequestControl = true;
|
||||
this.messageApi.loading({
|
||||
key: 'control',
|
||||
content: '权限请求中...',
|
||||
duration: 0,
|
||||
});
|
||||
this.sendPermissionRequest(true, 'switchPermission');
|
||||
}
|
||||
|
||||
// 处理 WebSocket 消息
|
||||
handleWsMessage(msg) {
|
||||
switch (msg.type) {
|
||||
case 'deviceInfo':
|
||||
const data = {};
|
||||
msg.data.forEach((item) => (data[item.name] = item.value));
|
||||
this.wsDeviceInfo = data;
|
||||
if (this.onDeviceInfoUpdate) this.onDeviceInfoUpdate(data);
|
||||
break;
|
||||
|
||||
case 'AUTH':
|
||||
if (msg.isAuth) this.getControl(this.connectedDeviceSn);
|
||||
break;
|
||||
|
||||
case 'switchResult':
|
||||
this.messageApi.success({
|
||||
content: '权限获取成功',
|
||||
key: 'control',
|
||||
duration: 2,
|
||||
});
|
||||
this.isRequestControl = false;
|
||||
this.isControlled = true;
|
||||
if (this.onControlStatusChange) this.onControlStatusChange(true);
|
||||
break;
|
||||
|
||||
case 'switchPermission':
|
||||
const platform = (msg.platform || '').toLowerCase().trim();
|
||||
if (!msg.platform || platform === 'web') return;
|
||||
this.requestDeviceId = msg.deviceId;
|
||||
if (this.onPermissionRequest) {
|
||||
this.onPermissionRequest({
|
||||
title: '权限请求',
|
||||
content: `${msg.platform} 请求控制 ${msg.deviceId}`,
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case 'detectionReport':
|
||||
if (msg.data?.deviceId !== this.connectedDeviceSn) return;
|
||||
const { isSecure, obstacle } = msg.data;
|
||||
if (isSecure) return;
|
||||
const type = obstacle?.type;
|
||||
const distance = (obstacle?.distance || 0).toFixed(2);
|
||||
const types = { 0: '未知', 1: '人', 2: '车辆', 3: '围栏', 4: '坑洞', 5: '草丛' };
|
||||
this.messageApi.warning({
|
||||
key: 'obstacle-warning',
|
||||
content: `检测到 ${types[type] ?? '未知物'},距离 ${distance}m`,
|
||||
duration: 3,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 发送游戏手柄指令
|
||||
sendGamepad(state) {
|
||||
if (!this.isControlled || !this.connectedDeviceSn) return;
|
||||
wsManager.send({
|
||||
type: 'gamepad',
|
||||
deviceId: this.connectedDeviceSn,
|
||||
data: { axes: state.axes, buttons: state.buttons },
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user