web-map/src/services/auto-door-simulation.service.ts

389 lines
10 KiB
TypeScript
Raw Normal View History

/**
*
* WebSocket数据处理功能
* WebSocket推送数据
*/
import { type MapPen, MapPointType } from '@api/map';
import type { EditorService } from './editor.service';
/**
*
*/
export interface AutoDoorSimulationConfig {
/** 设备ID需要与地图中自动门点的deviceId匹配 */
deviceId: string;
/** 设备标签 */
label?: string;
/** 状态切换间隔毫秒默认3000ms */
interval?: number;
/** 初始状态0=关门1=开门默认0 */
initialStatus?: 0 | 1;
/** 是否启用控制台日志 */
enableLogging?: boolean;
}
/**
* WebSocket推送的数据格式
*/
interface AutoDoorStatusData {
gid: string;
id: string;
label: string;
brand: null;
type: 99; // 自动门点类型标识
ip: null;
battery: number;
isConnected: boolean;
state: number;
canOrder: boolean;
canStop: null;
canControl: boolean;
targetPoint: null;
deviceStatus: 0 | 1; // 设备状态0=关门1=开门
x: number;
y: number;
active: boolean;
angle: number;
isWaring: null;
isFault: null;
isLoading: null;
path: [];
}
/**
* WebSocket推送的自动门点数据接口
*/
export interface AutoDoorWebSocketData {
gid: string;
id: string; // 设备ID
label: string;
brand: null;
type: 99; // 自动门点类型标识
ip: null;
battery: number;
isConnected: boolean;
state: number;
canOrder: boolean;
canStop: null;
canControl: boolean;
targetPoint: null;
deviceStatus: 0 | 1; // 设备状态0=关门1=开门
x: number;
y: number;
active: boolean;
angle: number;
isWaring: null;
isFault: null;
isLoading: null;
path: [];
}
/**
*
* WebSocket数据处理使
*/
export class AutoDoorService {
private timers = new Map<string, NodeJS.Timeout>();
private statusMap = new Map<string, 0 | 1>();
private editorService: EditorService | null = null;
private latestAutoDoorData = new Map<string, { deviceId: string; deviceStatus: number; active: boolean }>();
// 设备ID到自动门点ID的映射缓存避免每次都遍历查找
private deviceIdToPointIdMap = new Map<string, string>();
/**
*
* @param editor
*/
setEditorService(editor: EditorService): void {
this.editorService = editor;
// 初始化设备ID到点位ID的映射关系
this.initializeDeviceMapping();
}
/**
* ID到自动门点ID的映射关系
*
*/
private initializeDeviceMapping(): void {
if (!this.editorService) {
console.warn('⚠️ 编辑器服务未设置,无法初始化自动门点映射');
return;
}
// 清空现有映射
this.deviceIdToPointIdMap.clear();
// 遍历所有点位,找出自动门点并建立映射
const pens = this.editorService.data().pens;
let autoDoorCount = 0;
pens.forEach((pen) => {
if (pen.name === 'point' && (pen as MapPen).point?.type === MapPointType.) {
const deviceId = (pen as MapPen).point?.deviceId;
if (deviceId && pen.id) {
this.deviceIdToPointIdMap.set(deviceId, pen.id);
autoDoorCount++;
}
}
});
console.log(`🚪 自动门点映射初始化完成: 共找到 ${autoDoorCount} 个自动门点`);
}
/**
*
*/
refreshDeviceMapping(): void {
this.initializeDeviceMapping();
}
/**
*
* 使WebSocket数据
* @param config
*/
startSimulation(config: AutoDoorSimulationConfig): void {
const { deviceId, interval = 3000, initialStatus = 0, enableLogging = true } = config;
// 如果已经存在相同设备ID的模拟先停止它
this.stopSimulation(deviceId);
if (enableLogging) {
console.log(`🚪 启动自动门点模拟: ${deviceId}`);
}
// 设置初始状态
this.statusMap.set(deviceId, initialStatus);
// 创建定时器
const timer = setInterval(() => {
const currentStatus = this.statusMap.get(deviceId) ?? 0;
const newStatus = currentStatus === 0 ? 1 : 0;
// 更新状态
this.statusMap.set(deviceId, newStatus);
// 注意:这里不需要创建完整的模拟数据对象,只需要更新状态
if (enableLogging) {
console.log(`🚪 自动门点状态更新: ${newStatus === 0 ? '关门(红色)' : '开门(蓝色)'} (deviceId: ${deviceId})`);
}
// 更新编辑器中的自动门点状态
if (this.editorService) {
this.editorService.updateAutoDoorByDeviceId(deviceId, newStatus, true);
} else {
console.warn('⚠️ 编辑器服务未设置,无法更新自动门点状态');
}
}, interval);
// 保存定时器引用
this.timers.set(deviceId, timer);
}
/**
*
* @param deviceId ID
*/
stopSimulation(deviceId: string): void {
const timer = this.timers.get(deviceId);
if (timer) {
clearInterval(timer);
this.timers.delete(deviceId);
this.statusMap.delete(deviceId);
console.log(`🚪 停止自动门点模拟: ${deviceId}`);
}
}
/**
*
*/
stopAllSimulations(): void {
for (const deviceId of this.timers.keys()) {
this.stopSimulation(deviceId);
}
console.log('🚪 停止所有自动门点模拟');
}
/**
*
*/
getActiveSimulations(): string[] {
return Array.from(this.timers.keys());
}
/**
*
* @param deviceId ID
*/
getCurrentStatus(deviceId: string): 0 | 1 | undefined {
return this.statusMap.get(deviceId);
}
/**
*
* @param deviceId ID
* @param status
*/
setDeviceStatus(deviceId: string, status: 0 | 1): void {
this.statusMap.set(deviceId, status);
if (this.editorService) {
this.editorService.updateAutoDoorByDeviceId(deviceId, status, true);
console.log(`🚪 手动设置自动门点状态: ${status === 0 ? '关门(红色)' : '开门(蓝色)'} (deviceId: ${deviceId})`);
}
}
/**
*
* @param configs
*/
startMultipleSimulations(configs: AutoDoorSimulationConfig[]): void {
configs.forEach((config) => this.startSimulation(config));
}
/**
* WebSocket推送的自动门点数据
* @param data WebSocket推送的数据
*/
handleWebSocketData(data: AutoDoorWebSocketData): void {
const { label: deviceId, deviceStatus, active = true } = data;
if (!deviceId || deviceStatus === undefined) {
console.warn('⚠️ 自动门点数据格式不正确', data);
return;
}
// 缓存最新数据
this.latestAutoDoorData.set(deviceId, { deviceId, deviceStatus, active });
console.log(
`🚪 收到自动门点WebSocket数据: ${deviceStatus === 0 ? '关门(红色)' : '开门(蓝色)'} (deviceId: ${deviceId})`,
);
}
/**
*
* @param frameBudget
* @param startTime
* @returns
*/
processBufferedData(frameBudget: number, startTime: number): boolean {
// 在时间预算内,持续处理自动门点数据
while (performance.now() - startTime < frameBudget && this.latestAutoDoorData.size > 0) {
// 获取并移除 Map 中的第一条自动门点数据
const entry = this.latestAutoDoorData.entries().next().value;
if (!entry) break;
const [deviceId, data] = entry;
this.latestAutoDoorData.delete(deviceId);
// 使用映射缓存快速查找点位ID
const pointId = this.deviceIdToPointIdMap.get(data.deviceId);
if (!pointId) {
console.warn(`⚠️ 未找到设备ID ${data.deviceId} 对应的自动门点,可能需要刷新映射`);
continue;
}
// 更新自动门点状态使用pointId直接更新避免查找
if (this.editorService) {
this.editorService.updateAutoDoorByDeviceId(data.deviceId, data.deviceStatus, data.active, pointId);
}
}
// 返回是否还有待处理的数据
return this.latestAutoDoorData.size > 0;
}
/**
*
*/
getBufferedDataCount(): number {
return this.latestAutoDoorData.size;
}
/**
*
*/
clearBufferedData(): void {
this.latestAutoDoorData.clear();
}
/**
*
*/
getMappingCount(): number {
return this.deviceIdToPointIdMap.size;
}
/**
* ID是否有对应的自动门点
*/
hasDeviceMapping(deviceId: string): boolean {
return this.deviceIdToPointIdMap.has(deviceId);
}
/**
* ID列表
*/
getMappedDeviceIds(): string[] {
return Array.from(this.deviceIdToPointIdMap.keys());
}
/**
*
* @param deviceId ID
* @param label
* @param deviceStatus
*/
private createMockData(deviceId: string, label: string, deviceStatus: 0 | 1): AutoDoorStatusData {
return {
gid: '',
id: deviceId,
label,
brand: null,
type: 99,
ip: null,
battery: 0,
isConnected: true,
state: 0,
canOrder: false,
canStop: null,
canControl: false,
targetPoint: null,
deviceStatus,
x: 0,
y: 0,
active: true,
angle: 0,
isWaring: null,
isFault: null,
isLoading: null,
path: [],
};
}
/**
*
*/
destroy(): void {
this.stopAllSimulations();
this.clearBufferedData();
this.deviceIdToPointIdMap.clear();
this.editorService = null;
console.log('🚪 自动门点服务已销毁');
}
}
/**
*
*/
export const autoDoorService = new AutoDoorService();
// 保持向后兼容
export const autoDoorSimulationService = autoDoorService;