fix(playback): 增加库位数据支持,优化回放模式下的数据处理逻辑

This commit is contained in:
xudan 2025-10-28 15:39:40 +08:00
parent 85f7b94313
commit 1fbdb5efcb
3 changed files with 117 additions and 1 deletions

View File

@ -8,7 +8,7 @@ import ws from '../services/ws';
// Define the structure of WebSocket messages for playback
type PlaybackMessage = {
type: 'AMR' | 'SCENE';
type: 'AMR' | 'SCENE' | 'LOCATION';
timestamp: number;
data: any;
};
@ -18,6 +18,7 @@ type PlaybackSceneData = {
totalDuration: number;
};
// Hook's return type definition
// Hook's return type definition
export interface UsePlaybackWebSocketReturn {
// Connection status
@ -31,6 +32,7 @@ export interface UsePlaybackWebSocketReturn {
// Data for rendering
currentSceneId: Ref<string | null>;
sceneJson: Ref<string | null>;
locationData: Ref<any[]>; // 新增:用于存储库位数据
// Methods
connect: (historySceneId: string) => void;
@ -50,6 +52,7 @@ export function usePlaybackWebSocket(editorService: ShallowRef<EditorService | u
const totalDuration = ref(0);
const currentSceneId = ref<string | null>(null);
const sceneJson = ref<string | null>(null);
const locationData = ref<any[]>([]); // 新增:库位数据的响应式引用
const { calculateCenterPoint, jumpToPosition } = useViewState();
@ -100,6 +103,9 @@ export function usePlaybackWebSocket(editorService: ShallowRef<EditorService | u
(msg.data as RobotRealtimeInfo[]).forEach((robot) => {
latestRobotData.set(robot.id, robot);
});
} else if (msg.type === 'LOCATION') {
// 新增:处理库位数据
locationData.value = msg.data;
}
};
@ -230,6 +236,7 @@ export function usePlaybackWebSocket(editorService: ShallowRef<EditorService | u
totalDuration,
currentSceneId,
sceneJson,
locationData, // 新增
connect,
disconnect,
play,

View File

@ -112,9 +112,12 @@ const playback = usePlaybackWebSocket(editor);
watch(mode, async (newMode) => {
if (newMode === 'live') {
playback.disconnect();
storageLocationService.value?.setPlaybackMode(false);
await monitorScene();
storageLocationService.value?.startMonitoring({ interval: 1 });
} else {
client.value?.close();
storageLocationService.value?.setPlaybackMode(true);
playback.connect(props.sid); // Connect once using props.sid
}
});
@ -127,6 +130,44 @@ watch(playback.sceneJson, async (newJson) => {
}
});
watch(playback.locationData, (newData) => {
if (newData) {
storageLocationService.value?.handlePlaybackData(newData);
}
});
let mockLocationInterval: NodeJS.Timeout;
onMounted(() => {
//
if (isPlaybackMode.value) {
let occupied = false;
mockLocationInterval = setInterval(() => {
const mockData = {
type: 'LOCATION',
timestamp: playback.currentTime.value,
data: [
{
id: '666',
label: '1-1',
stationName: 'AP190',
occupied: occupied,
locked: false,
disabled: false,
emptyTray: false,
},
],
};
//
storageLocationService.value?.handlePlaybackData(mockData.data);
occupied = !occupied; //
}, 2000); // 2
}
});
onUnmounted(() => {
clearInterval(mockLocationInterval);
});
watch(selectedDate, (date) => {
if (date) {
const startOfDayTimestamp = date.startOf('day').valueOf();

View File

@ -115,6 +115,7 @@ export class StorageLocationService {
private config: StorageLocationConfig;
// 渲染调度标记,避免在高频事件中重复 render
private renderScheduled = false;
private isPlaybackMode = false;
constructor(editor: EditorService, sceneId: string, config?: Partial<StorageLocationConfig>) {
this.editor = editor;
@ -472,6 +473,9 @@ export class StorageLocationService {
* @param options
*/
async startMonitoring(options: { interval?: number } = {}) {
if (this.isPlaybackMode) {
return;
}
this.stopMonitoring();
// 监控库位状态
@ -765,6 +769,70 @@ export class StorageLocationService {
this.storageLocations.value.clear();
this.editor = null;
}
setPlaybackMode(isPlayback: boolean) {
this.isPlaybackMode = isPlayback;
}
handlePlaybackData(data: any[]) {
const stationToPointIdMap = this.buildStationToPointIdMap();
const locationsByPointId = new Map<string, StorageLocationInfo[]>();
data.forEach((location) => {
const pointId = stationToPointIdMap.get(location.stationName);
if (pointId) {
if (!locationsByPointId.has(pointId)) {
locationsByPointId.set(pointId, []);
}
locationsByPointId.get(pointId)!.push({
...location,
is_occupied: location.occupied,
is_locked: location.locked,
is_disabled: location.disabled,
is_empty_tray: location.emptyTray,
layer_name: location.label,
station_name: location.stationName,
});
}
});
const changedPointIds = this.getChangedPointIds(locationsByPointId);
if (changedPointIds.size === 0) {
return;
}
this.storageLocations.value = locationsByPointId;
storageStateMap.clear();
for (const [pointId, list] of locationsByPointId.entries()) {
const inner = new Map<string, StorageState>();
list.forEach((loc) => {
inner.set(loc.layer_name, {
occupied: loc.is_occupied,
locked: loc.is_locked,
disabled: loc.is_disabled,
isEmptyTray: loc.is_empty_tray,
});
});
storageStateMap.set(pointId, inner);
}
this.updatePointBorderColorsOptimized(changedPointIds);
for (const pointId of changedPointIds) {
const pointPen = this.editor?.getPenById(pointId);
const storageNames = pointPen?.point?.associatedStorageLocations;
if (pointPen && Array.isArray(storageNames) && storageNames.length > 0) {
const existing = this.getStorageLocationPens(pointId);
if (existing.length > 0) {
this.update(pointId, storageNames);
} else {
this.create(pointId, storageNames);
}
}
}
this.scheduleRender();
}
}
// ==================== 新增简化的库位更新API ====================