2026-05-20 15:12:51 +08:00
|
|
|
import throttle from 'lodash/throttle';
|
2026-05-20 09:25:58 +08:00
|
|
|
import { wsManager } from '../WebSocketManager.ts';
|
2026-05-20 15:12:51 +08:00
|
|
|
import {
|
|
|
|
|
getJurisdiction,
|
2026-08-20 17:24:35 +08:00
|
|
|
releaseControl
|
2026-05-20 15:12:51 +08:00
|
|
|
} from '../../api/device.ts';
|
|
|
|
|
|
2026-05-20 09:25:58 +08:00
|
|
|
import envConfig from '../../../env';
|
2026-08-14 09:02:52 +08:00
|
|
|
import i18n from '../../i18n';
|
2026-05-20 09:25:58 +08:00
|
|
|
|
|
|
|
|
export default class DeviceController {
|
|
|
|
|
constructor(userInfo, messageApi) {
|
|
|
|
|
this.userInfo = userInfo;
|
|
|
|
|
this.messageApi = messageApi;
|
|
|
|
|
|
2026-05-20 15:12:51 +08:00
|
|
|
this.wsUrl =
|
|
|
|
|
envConfig.WS_URL || 'wss://ri.satabot.com/ws/';
|
|
|
|
|
|
2026-05-20 09:25:58 +08:00
|
|
|
this.connectedDeviceSn = null;
|
2026-08-20 17:24:35 +08:00
|
|
|
this.currentDevice = null;
|
2026-05-20 15:12:51 +08:00
|
|
|
|
2026-05-20 09:25:58 +08:00
|
|
|
this.requestDeviceId = '';
|
2026-05-20 15:12:51 +08:00
|
|
|
|
2026-05-20 09:25:58 +08:00
|
|
|
this.isControlled = false;
|
|
|
|
|
this.isRequestControl = false;
|
|
|
|
|
this.hasControlRight = false;
|
2026-05-20 15:12:51 +08:00
|
|
|
|
2026-05-20 09:25:58 +08:00
|
|
|
this.wsStatus = 'disconnected';
|
2026-05-20 15:12:51 +08:00
|
|
|
this.wsDeviceInfo = {};
|
2026-08-19 17:00:07 +08:00
|
|
|
this.locationInfo = {};
|
2026-05-20 15:12:51 +08:00
|
|
|
|
|
|
|
|
this.controlTimeout = null;
|
2026-08-20 17:24:35 +08:00
|
|
|
this.keepAliveInterval = null;
|
2026-05-20 09:25:58 +08:00
|
|
|
|
|
|
|
|
this.onDeviceInfoUpdate = null;
|
2026-08-19 17:00:07 +08:00
|
|
|
this.onLocationInfoUpdate = null;
|
|
|
|
|
|
2026-05-20 09:25:58 +08:00
|
|
|
this.onControlStatusChange = null;
|
|
|
|
|
this.onWsStatusChange = null;
|
2026-05-20 15:12:51 +08:00
|
|
|
this.onHasControlRightChange = null;
|
|
|
|
|
this.onRequestControlStatusChange = null;
|
2026-05-20 09:25:58 +08:00
|
|
|
this.onPermissionRequest = null;
|
2026-08-28 10:03:08 +08:00
|
|
|
this.onRoutePost = null;
|
2026-06-10 17:22:55 +08:00
|
|
|
this.onIsFinished = null;
|
2026-06-11 17:02:23 +08:00
|
|
|
this.handleArrivedPoint = null;
|
2026-05-20 09:25:58 +08:00
|
|
|
|
|
|
|
|
this.handleWsMessage = this.handleWsMessage.bind(this);
|
2026-05-20 15:12:51 +08:00
|
|
|
this.handleWsStatus = this.handleWsStatus.bind(this);
|
2026-06-02 10:48:27 +08:00
|
|
|
this.handleVisibilityChange = this.handleVisibilityChange.bind(this);
|
2026-08-20 17:24:35 +08:00
|
|
|
this.handleBeforeUnload = this.handleBeforeUnload.bind(this);
|
2026-05-20 15:12:51 +08:00
|
|
|
|
|
|
|
|
this.sendGamepad = throttle(
|
|
|
|
|
this.sendGamepad.bind(this),
|
|
|
|
|
50,
|
2026-06-02 10:48:27 +08:00
|
|
|
{ leading: true, trailing: true }
|
2026-05-20 15:12:51 +08:00
|
|
|
);
|
2026-05-20 09:25:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
init() {
|
2026-06-02 10:48:27 +08:00
|
|
|
this.unSubMessage = wsManager.onMessage(this.handleWsMessage);
|
|
|
|
|
this.unSubStatus = wsManager.onStatusChange(this.handleWsStatus);
|
2026-05-20 15:12:51 +08:00
|
|
|
|
2026-06-02 10:48:27 +08:00
|
|
|
document.addEventListener('visibilitychange', this.handleVisibilityChange);
|
2026-08-20 17:24:35 +08:00
|
|
|
document.addEventListener('beforeunload', this.handleBeforeUnload);
|
2026-06-02 10:48:27 +08:00
|
|
|
}
|
2026-08-25 11:11:29 +08:00
|
|
|
levae() {
|
|
|
|
|
wsManager.close();
|
|
|
|
|
|
|
|
|
|
}
|
2026-06-02 10:48:27 +08:00
|
|
|
|
|
|
|
|
handleVisibilityChange() {
|
2026-06-04 11:49:20 +08:00
|
|
|
if (document.visibilityState === 'hidden') {
|
2026-08-25 11:11:29 +08:00
|
|
|
console.log('Page hidden, release control');
|
|
|
|
|
//this.release();
|
2026-06-04 11:49:20 +08:00
|
|
|
wsManager.close();
|
2026-06-04 15:39:46 +08:00
|
|
|
this.connectedDeviceSn = null;
|
|
|
|
|
|
2026-06-04 11:49:20 +08:00
|
|
|
this.isControlled = false;
|
|
|
|
|
this.onControlStatusChange?.(false);
|
|
|
|
|
}
|
2026-06-02 10:48:27 +08:00
|
|
|
if (document.visibilityState === 'visible' && this.currentDevice) {
|
2026-06-02 13:03:40 +08:00
|
|
|
if (!this.currentDevice?.serialNumber) return;
|
2026-08-25 11:11:29 +08:00
|
|
|
console.log('Page visible, reconnect WebSocket');
|
2026-06-02 10:48:27 +08:00
|
|
|
setTimeout(() => {
|
|
|
|
|
this.connectDevice(this.currentDevice);
|
|
|
|
|
}, 500);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-20 17:24:35 +08:00
|
|
|
handleBeforeUnload() {
|
2026-08-25 11:11:29 +08:00
|
|
|
console.log('Browser closing/refreshing, release control');
|
2026-08-20 17:24:35 +08:00
|
|
|
this.release();
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-02 10:48:27 +08:00
|
|
|
startKeepAlive() {
|
|
|
|
|
this.keepAliveInterval = setInterval(() => {
|
|
|
|
|
if (
|
|
|
|
|
this.connectedDeviceSn &&
|
|
|
|
|
this.wsStatus !== 'connected' &&
|
2026-06-02 13:03:40 +08:00
|
|
|
this.currentDevice?.serialNumber
|
2026-06-02 10:48:27 +08:00
|
|
|
) {
|
2026-08-25 11:11:29 +08:00
|
|
|
console.log('Keep alive: reconnect WebSocket');
|
2026-06-02 10:48:27 +08:00
|
|
|
this.connectDevice(this.currentDevice);
|
|
|
|
|
}
|
|
|
|
|
}, 8000);
|
2026-05-20 09:25:58 +08:00
|
|
|
}
|
2026-08-20 17:24:35 +08:00
|
|
|
|
|
|
|
|
async release() {
|
2026-08-25 11:11:29 +08:00
|
|
|
if (!this.connectedDeviceSn) return;
|
2026-08-20 17:24:35 +08:00
|
|
|
const data = {
|
|
|
|
|
platform: 'web',
|
|
|
|
|
type: 1,
|
|
|
|
|
deviceId: this.connectedDeviceSn,
|
2026-08-25 11:11:29 +08:00
|
|
|
token: this.userInfo.token,
|
2026-08-20 17:24:35 +08:00
|
|
|
};
|
|
|
|
|
const url = `${envConfig.baseURL}/forward/device/releaseControl`;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await releaseControl(data);
|
|
|
|
|
const blob = new Blob([JSON.stringify(data)], { type: 'application/json' });
|
|
|
|
|
navigator.sendBeacon(url, blob);
|
2026-08-25 11:11:29 +08:00
|
|
|
console.log('releaseControl sent');
|
2026-08-20 17:24:35 +08:00
|
|
|
} catch (e) {
|
2026-08-25 11:11:29 +08:00
|
|
|
console.error('Failed to send releaseControl:', e);
|
2026-06-04 15:39:46 +08:00
|
|
|
}
|
|
|
|
|
}
|
2026-05-20 09:25:58 +08:00
|
|
|
|
|
|
|
|
destroy() {
|
2026-05-20 15:12:51 +08:00
|
|
|
this.clearControlTimeout();
|
|
|
|
|
|
2026-06-02 10:48:27 +08:00
|
|
|
if (this.keepAliveInterval) {
|
|
|
|
|
clearInterval(this.keepAliveInterval);
|
|
|
|
|
this.keepAliveInterval = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
document.removeEventListener('visibilitychange', this.handleVisibilityChange);
|
2026-08-20 17:24:35 +08:00
|
|
|
document.removeEventListener('beforeunload', this.handleBeforeUnload);
|
|
|
|
|
|
|
|
|
|
this.release();
|
2026-08-25 11:11:29 +08:00
|
|
|
this.levae();
|
2026-06-02 10:48:27 +08:00
|
|
|
|
2026-05-20 15:12:51 +08:00
|
|
|
this.unSubMessage?.();
|
|
|
|
|
this.unSubStatus?.();
|
|
|
|
|
|
2026-06-04 15:39:46 +08:00
|
|
|
this.connectedDeviceSn = null;
|
2026-05-20 09:25:58 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-20 15:12:51 +08:00
|
|
|
handleWsStatus(status) {
|
|
|
|
|
this.wsStatus = status;
|
|
|
|
|
this.onWsStatusChange?.(status);
|
|
|
|
|
|
|
|
|
|
if (status === 'disconnected') {
|
2026-05-20 09:25:58 +08:00
|
|
|
this.isControlled = false;
|
2026-05-20 15:12:51 +08:00
|
|
|
this.onControlStatusChange?.(false);
|
2026-05-20 09:25:58 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async connectDevice(device) {
|
|
|
|
|
if (!device) return;
|
|
|
|
|
|
2026-06-02 10:48:27 +08:00
|
|
|
this.currentDevice = device;
|
2026-06-02 13:03:40 +08:00
|
|
|
if (!device.serialNumber) return;
|
2026-05-20 15:12:51 +08:00
|
|
|
|
2026-06-02 13:03:40 +08:00
|
|
|
const sn = device.serialNumber;
|
2026-05-20 09:25:58 +08:00
|
|
|
|
2026-06-02 10:48:27 +08:00
|
|
|
this.connectedDeviceSn = null;
|
|
|
|
|
this.wsDeviceInfo = {};
|
2026-08-19 17:00:07 +08:00
|
|
|
this.locationInfo = {};
|
2026-05-20 15:12:51 +08:00
|
|
|
this.isControlled = false;
|
|
|
|
|
this.onControlStatusChange?.(false);
|
|
|
|
|
|
2026-06-12 11:03:38 +08:00
|
|
|
wsManager.close();
|
2026-05-20 15:12:51 +08:00
|
|
|
|
2026-05-20 09:25:58 +08:00
|
|
|
try {
|
2026-08-25 11:11:29 +08:00
|
|
|
console.log('Connecting to', this.wsUrl);
|
2026-06-05 15:57:36 +08:00
|
|
|
wsManager.connect(sn, this.wsUrl);
|
|
|
|
|
this.connectedDeviceSn = sn;
|
|
|
|
|
|
2026-05-20 15:12:51 +08:00
|
|
|
await this.getControl(sn);
|
2026-05-20 09:25:58 +08:00
|
|
|
} catch (err) {
|
2026-05-20 15:12:51 +08:00
|
|
|
console.error(err);
|
2026-08-14 09:02:52 +08:00
|
|
|
this.messageApi.error(i18n.t('devices.failedFixed22'));
|
2026-05-20 09:25:58 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-25 11:11:29 +08:00
|
|
|
async switchDevice(device) {
|
|
|
|
|
if (!device) return;
|
|
|
|
|
if (!device.serialNumber) return;
|
|
|
|
|
|
|
|
|
|
const newSn = device.serialNumber;
|
|
|
|
|
|
|
|
|
|
if (this.connectedDeviceSn === newSn && this.wsStatus === 'connected') {
|
|
|
|
|
console.log('switchDevice: same device, skip');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log('Connecting to switchDevice: switching to', newSn);
|
|
|
|
|
|
|
|
|
|
this.currentDevice = device;
|
|
|
|
|
this.connectedDeviceSn = newSn;
|
|
|
|
|
this.wsDeviceInfo = {};
|
|
|
|
|
this.locationInfo = {};
|
|
|
|
|
this.isControlled = false;
|
|
|
|
|
this.onControlStatusChange?.(false);
|
|
|
|
|
|
|
|
|
|
wsManager.send({
|
|
|
|
|
type: 'AUTH',
|
|
|
|
|
token: this.userInfo.token,
|
|
|
|
|
userName: this.userInfo.username,
|
|
|
|
|
deviceId: newSn,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await this.getControl(newSn);
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-20 15:12:51 +08:00
|
|
|
async getControl(serialnum) {
|
|
|
|
|
try {
|
|
|
|
|
const res = await getJurisdiction({
|
|
|
|
|
platform: 'web',
|
|
|
|
|
deviceId: serialnum,
|
2026-08-25 11:11:29 +08:00
|
|
|
token: this.userInfo.token,
|
2026-05-20 15:12:51 +08:00
|
|
|
});
|
|
|
|
|
|
2026-06-02 10:48:27 +08:00
|
|
|
this.isControlled = res?.code === 200 && res?.data?.remoteControl === true;
|
|
|
|
|
this.onControlStatusChange?.(this.isControlled);
|
2026-05-20 15:12:51 +08:00
|
|
|
} catch (err) {
|
|
|
|
|
console.error(err);
|
|
|
|
|
this.isControlled = false;
|
|
|
|
|
this.onControlStatusChange?.(false);
|
|
|
|
|
}
|
2026-05-20 09:25:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
requestControl() {
|
2026-06-02 10:48:27 +08:00
|
|
|
if (this.isRequestControl) return;
|
2026-08-25 11:11:29 +08:00
|
|
|
|
2026-05-20 15:12:51 +08:00
|
|
|
|
2026-05-20 09:25:58 +08:00
|
|
|
this.isRequestControl = true;
|
2026-05-20 15:12:51 +08:00
|
|
|
this.onRequestControlStatusChange?.(true);
|
|
|
|
|
|
2026-05-20 09:25:58 +08:00
|
|
|
this.messageApi.loading({
|
|
|
|
|
key: 'control',
|
2026-08-14 09:02:52 +08:00
|
|
|
content: i18n.t('devices.control2'),
|
2026-05-20 09:25:58 +08:00
|
|
|
duration: 0,
|
|
|
|
|
});
|
2026-05-20 15:12:51 +08:00
|
|
|
|
2026-06-02 10:48:27 +08:00
|
|
|
this.sendPermissionRequest(true, 'switchPermission');
|
2026-05-20 15:12:51 +08:00
|
|
|
this.clearControlTimeout();
|
|
|
|
|
|
|
|
|
|
this.controlTimeout = setTimeout(() => {
|
|
|
|
|
if (!this.isRequestControl) return;
|
|
|
|
|
this.isRequestControl = false;
|
|
|
|
|
this.onRequestControlStatusChange?.(false);
|
|
|
|
|
this.messageApi.destroy('control');
|
2026-08-14 09:02:52 +08:00
|
|
|
this.messageApi.error(i18n.t('devices.fixed2ControlFixed2'));
|
2026-06-10 17:22:55 +08:00
|
|
|
this.clearControlTimeout();
|
|
|
|
|
|
2026-06-05 15:57:36 +08:00
|
|
|
}, 20000);
|
2026-05-20 15:12:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clearControlTimeout() {
|
|
|
|
|
if (this.controlTimeout) {
|
|
|
|
|
clearTimeout(this.controlTimeout);
|
|
|
|
|
this.controlTimeout = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sendPermissionRequest(data, type) {
|
|
|
|
|
wsManager.send({
|
|
|
|
|
type,
|
|
|
|
|
switchResult: data,
|
|
|
|
|
token: this.userInfo.token,
|
2026-06-02 10:48:27 +08:00
|
|
|
deviceId: type === 'switchPermission' ? this.connectedDeviceSn : this.requestDeviceId,
|
2026-05-20 15:12:51 +08:00
|
|
|
userName: this.userInfo.username,
|
|
|
|
|
});
|
2026-05-20 09:25:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleWsMessage(msg) {
|
2026-08-25 11:11:29 +08:00
|
|
|
console.log('WS message:', msg);
|
2026-05-20 09:25:58 +08:00
|
|
|
switch (msg.type) {
|
2026-05-20 15:12:51 +08:00
|
|
|
case 'deviceInfo': {
|
2026-05-20 09:25:58 +08:00
|
|
|
const data = {};
|
2026-05-20 15:12:51 +08:00
|
|
|
msg.data.forEach((item) => {
|
|
|
|
|
data[item.name] = item.value;
|
|
|
|
|
});
|
2026-05-20 09:25:58 +08:00
|
|
|
this.wsDeviceInfo = data;
|
2026-05-20 15:12:51 +08:00
|
|
|
this.onDeviceInfoUpdate?.(data);
|
2026-05-20 09:25:58 +08:00
|
|
|
break;
|
2026-05-20 15:12:51 +08:00
|
|
|
}
|
2026-08-19 17:00:07 +08:00
|
|
|
case 'locationInfo': {
|
|
|
|
|
const data = {};
|
|
|
|
|
msg.data.forEach((item) => {
|
|
|
|
|
data[item.name] = item.value;
|
|
|
|
|
});
|
|
|
|
|
this.locationInfo = data;
|
|
|
|
|
this.onLocationInfoUpdate?.(data);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2026-05-20 15:12:51 +08:00
|
|
|
|
|
|
|
|
case 'AUTH': {
|
|
|
|
|
if (msg.isAuth) {
|
|
|
|
|
this.getControl(this.connectedDeviceSn);
|
|
|
|
|
}
|
2026-05-20 09:25:58 +08:00
|
|
|
break;
|
2026-05-20 15:12:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case 'switchResult': {
|
2026-06-05 15:57:36 +08:00
|
|
|
|
2026-05-20 15:12:51 +08:00
|
|
|
this.clearControlTimeout();
|
|
|
|
|
this.isRequestControl = false;
|
|
|
|
|
this.onRequestControlStatusChange?.(false);
|
|
|
|
|
|
2026-08-25 11:11:29 +08:00
|
|
|
if (msg?.success === false || msg?.respond?.switchResult === false) {
|
2026-05-20 15:12:51 +08:00
|
|
|
this.isControlled = false;
|
|
|
|
|
this.onControlStatusChange?.(false);
|
2026-08-14 09:02:52 +08:00
|
|
|
this.messageApi.error({ key: 'control', content: msg.message || i18n.t('devices.controlFailed') });
|
2026-05-20 15:12:51 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this.isControlled = true;
|
|
|
|
|
this.onControlStatusChange?.(true);
|
2026-08-14 09:02:52 +08:00
|
|
|
this.messageApi.success({ key: 'control', content: i18n.t('devices.fixed2ControlFixed2SuccessFixed2') });
|
2026-05-20 09:25:58 +08:00
|
|
|
break;
|
2026-05-20 15:12:51 +08:00
|
|
|
}
|
2026-06-10 17:22:55 +08:00
|
|
|
case "device_task_change": {
|
2026-06-11 17:02:23 +08:00
|
|
|
if (msg.deviceId != this.connectedDeviceSn) return;
|
2026-06-10 17:22:55 +08:00
|
|
|
this.onIsFinished?.(true);
|
2026-08-25 11:11:29 +08:00
|
|
|
console.log('task change:', msg);
|
|
|
|
|
break;
|
2026-06-10 17:22:55 +08:00
|
|
|
}
|
2026-06-11 17:02:23 +08:00
|
|
|
case "device_task_arrive_point": {
|
|
|
|
|
if (msg.deviceId != this.connectedDeviceSn) return;
|
|
|
|
|
this.handleArrivedPoint?.(msg.entity);
|
2026-08-25 11:11:29 +08:00
|
|
|
console.log('arrive point:', msg);
|
|
|
|
|
break;
|
2026-06-11 17:02:23 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-20 15:12:51 +08:00
|
|
|
case 'switchPermission': {
|
2026-06-02 10:48:27 +08:00
|
|
|
const platform = (msg.platform || '').toLowerCase();
|
2026-06-05 15:57:36 +08:00
|
|
|
if (!platform || platform === 'null') return;
|
2026-05-20 15:12:51 +08:00
|
|
|
|
|
|
|
|
this.requestDeviceId = msg.deviceId;
|
|
|
|
|
this.onPermissionRequest?.({
|
2026-08-14 09:02:52 +08:00
|
|
|
title: i18n.t('devices.s2'),
|
|
|
|
|
content: i18n.t('devices.platformRequestControl', { platform: msg.platform }),
|
2026-05-20 15:12:51 +08:00
|
|
|
});
|
2026-05-20 09:25:58 +08:00
|
|
|
break;
|
2026-05-20 15:12:51 +08:00
|
|
|
}
|
2026-05-20 09:25:58 +08:00
|
|
|
|
|
|
|
|
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);
|
2026-08-14 09:02:52 +08:00
|
|
|
const types = { 0: i18n.t('constants.locationUnknown'), 1: i18n.t('devices.obstaclePerson'), 2: i18n.t('devices.obstacleVehicle'), 3: i18n.t('devices.obstacleFence'), 4: i18n.t('devices.obstaclePothole'), 5: i18n.t('devices.obstacleGrass') };
|
2026-05-20 09:25:58 +08:00
|
|
|
this.messageApi.warning({
|
|
|
|
|
key: 'obstacle-warning',
|
2026-08-14 09:02:52 +08:00
|
|
|
content: i18n.t('devices.obstacleDetectedReport', { obstacle: types[type] ?? i18n.t('devices.unknownObject'), distance }),
|
2026-05-20 09:25:58 +08:00
|
|
|
duration: 3,
|
|
|
|
|
});
|
|
|
|
|
break;
|
2026-05-20 15:12:51 +08:00
|
|
|
|
2026-08-28 10:03:08 +08:00
|
|
|
case 'route_post':
|
|
|
|
|
console.log('route post:', msg);
|
|
|
|
|
if (msg.deviceId) {
|
2026-09-08 17:17:59 +08:00
|
|
|
this.onRoutePost?.(msg);
|
2026-08-28 10:03:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2026-05-20 15:12:51 +08:00
|
|
|
default:
|
|
|
|
|
break;
|
2026-05-20 09:25:58 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sendGamepad(state) {
|
2026-06-02 10:48:27 +08:00
|
|
|
if (!this.isControlled || !this.connectedDeviceSn) return;
|
2026-05-20 09:25:58 +08:00
|
|
|
wsManager.send({
|
2026-05-20 15:12:51 +08:00
|
|
|
type: 'remoteControl',
|
2026-05-21 09:47:24 +08:00
|
|
|
remoteData: state,
|
|
|
|
|
token: this.userInfo.token,
|
|
|
|
|
userName: this.userInfo.username,
|
2026-05-20 09:25:58 +08:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|