web-map/src/services/context-menu/event-parser.ts

319 lines
8.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 事件解析器 - 纯函数,无副作用
* 负责解析鼠标事件和pen数据提取事件信息
*/
export interface ParsedEventData {
type: 'robot' | 'point' | 'area' | 'storage' | 'storage-background' | 'default';
id?: string;
name?: string;
pointId?: string; // 关联的点ID
storageId?: string; // 库位ID
tags?: string[]; // 标签信息
target: HTMLElement;
position: { x: number; y: number };
pen?: Record<string, unknown>; // 原始pen对象数据
}
/**
* 解析penData - 纯函数,无副作用
* @param penData EditorService传递的pen数据
* @returns 解析后的事件数据
*/
export function parsePenData(penData: Record<string, unknown>): ParsedEventData {
// 从penData中提取pen数据和事件信息
const pen = penData.pen as Record<string, unknown>;
const eventInfo = penData.e as { clientX: number; clientY: number };
const position = {
x: eventInfo?.clientX || 0,
y: eventInfo?.clientY || 0
};
// 如果有pen数据优先使用pen信息进行解析
if (pen) {
console.log('解析pen数据:', pen);
const { id, name, tags = [], storageLocation } = pen as {
id?: string;
name?: string;
tags?: string[];
storageLocation?: {
pointId: string;
locationName: string;
index: number;
occupied: boolean;
locked: boolean;
};
};
console.log('解析后的数据:', { id, name, tags, storageLocation });
// 根据tags判断类型 - 统一处理库位相关区域
if (tags.includes('storage-background') || tags.includes('storage-location')) {
const isBackground = tags.includes('storage-background');
console.log(`识别为库位相关类型: ${isBackground ? 'storage-background' : 'storage-location'}`);
// 库位背景区域或单个库位区域 - 都查找该点关联的所有库位
const pointId = tags.find((tag: string) => tag.startsWith('point-'))?.replace('point-', '');
return {
type: 'storage-background', // 统一使用storage-background类型
id,
name,
pointId,
storageId: id,
tags,
target: document.elementFromPoint(position.x, position.y) as HTMLElement,
position,
pen,
};
}
if (tags.includes('point')) {
// 点区域
return {
type: 'point',
id,
name,
pointId: id,
tags,
target: document.elementFromPoint(position.x, position.y) as HTMLElement,
position,
pen,
};
}
if (tags.includes('robot')) {
// 机器人区域
// 机器人的真实名称存储在text字段中而不是name字段
const robotName = (pen?.text as string) || name || `机器人-${id}`;
console.log('解析pen数据中的机器人信息:', {
id,
originalName: name,
penText: pen?.text,
finalName: robotName
});
return {
type: 'robot',
id,
name: robotName,
tags,
target: document.elementFromPoint(position.x, position.y) as HTMLElement,
position,
pen,
};
}
if (tags.includes('area')) {
// 区域
return {
type: 'area',
id,
name,
tags,
target: document.elementFromPoint(position.x, position.y) as HTMLElement,
position,
pen,
};
}
}
// 默认情况
console.log('未识别到特定类型,使用默认类型');
return {
type: 'default',
target: document.elementFromPoint(position.x, position.y) as HTMLElement,
position,
};
}
/**
* 解析事件数据 - 纯函数,无副作用
* @param event 鼠标事件或指针事件
* @returns 解析后的事件数据
*/
export function parseEventData(event: MouseEvent | PointerEvent): ParsedEventData {
const target = event.target as HTMLElement;
const position = { x: event.clientX, y: event.clientY };
// 从事件对象中获取pen数据如果存在
const pen = (event as MouseEvent & { pen?: Record<string, unknown> }).pen;
// 如果有pen数据优先使用pen信息进行解析
if (pen) {
console.log('解析pen数据:', pen);
const { id, name, tags = [], storageLocation } = pen as {
id?: string;
name?: string;
tags?: string[];
storageLocation?: {
pointId: string;
locationName: string;
index: number;
occupied: boolean;
locked: boolean;
};
};
console.log('解析后的数据:', { id, name, tags, storageLocation });
// 根据tags判断类型
if (tags.includes('storage-background')) {
console.log('识别为storage-background类型');
// 库位背景区域
const pointId = tags.find((tag: string) => tag.startsWith('point-'))?.replace('point-', '');
return {
type: 'storage-background',
id,
name,
pointId,
storageId: id,
tags,
target,
position,
pen,
};
}
if (tags.includes('storage-location')) {
console.log('识别为storage-location类型');
// 库位区域 - 使用storageLocation中的详细信息
const pointId = tags.find((tag: string) => tag.startsWith('point-'))?.replace('point-', '');
return {
type: 'storage',
id,
name: storageLocation?.locationName || name,
pointId,
storageId: id,
tags,
target,
position,
pen,
};
}
if (tags.includes('point')) {
// 点区域
return {
type: 'point',
id,
name,
pointId: id,
tags,
target,
position,
pen,
};
}
if (tags.includes('robot')) {
// 机器人区域
// 机器人的真实名称存储在text字段中而不是name字段
const robotName = (pen?.text as string) || name || `机器人-${id}`;
console.log('解析机器人信息:', {
id,
originalName: name,
penText: pen?.text,
finalName: robotName
});
return {
type: 'robot',
id,
name: robotName,
tags,
target,
position,
pen,
};
}
if (tags.includes('area')) {
// 区域
return {
type: 'area',
id,
name,
tags,
target,
position,
pen,
};
}
}
// 回退到DOM元素检查
if (target?.closest('.robot-item')) {
return {
type: 'robot',
id: target.dataset.robotId || target.id,
name: target.dataset.robotName || target.textContent?.trim(),
target,
position,
};
}
if (target?.closest('.point-item')) {
return {
type: 'point',
id: target.dataset.pointId || target.id,
name: target.dataset.pointName || target.textContent?.trim(),
target,
position,
};
}
if (target?.closest('.area-item')) {
return {
type: 'area',
id: target.dataset.areaId || target.id,
name: target.dataset.areaName || target.textContent?.trim(),
target,
position,
};
}
if (target?.closest('.storage-location')) {
return {
type: 'storage',
id: target.dataset.storageId || target.id,
name: target.dataset.storageName || target.textContent?.trim(),
target,
position,
};
}
// 默认情况
console.log('未识别到特定类型,使用默认类型');
return {
type: 'default',
target,
position,
};
}
/**
* 检查点击是否在菜单区域内 - 纯函数
* @param event 点击事件
* @param isMenuVisible 菜单是否可见
* @returns 是否在菜单区域内
*/
export function isClickInsideMenu(event: MouseEvent, isMenuVisible: boolean): boolean {
if (!isMenuVisible) return false;
// 查找右键菜单元素,支持多种可能的类名
const menuElement = document.querySelector('.context-menu-overlay') ||
document.querySelector('.context-menu') ||
document.querySelector('[class*="context-menu"]');
if (!menuElement) return false;
const rect = menuElement.getBoundingClientRect();
const x = event.clientX;
const y = event.clientY;
return (
x >= rect.left &&
x <= rect.right &&
y >= rect.top &&
y <= rect.bottom
);
}