Implement storage retrieval functionality: add useRetrieveHandler, update action handling in StorageMechanics, and modify related components for improved material management.

This commit is contained in:
2025-05-10 16:26:54 +05:30
parent bf6e95b7f2
commit 9746cfdf80
13 changed files with 279 additions and 35 deletions

View File

@@ -31,7 +31,8 @@ function StorageMechanics() {
) as StoragePointSchema | undefined; ) as StoragePointSchema | undefined;
if (point && "action" in point) { if (point && "action" in point) {
setSelectedPointData(point); setSelectedPointData(point);
setActiveOption(point.action.actionType as "store" | "spawn"); const uiOption = point.action.actionType === "retrieve" ? "spawn" : point.action.actionType;
setActiveOption(uiOption as "store" | "spawn");
setSelectedAction(point.action.actionUuid, point.action.actionName); setSelectedAction(point.action.actionUuid, point.action.actionName);
} }
} }
@@ -46,7 +47,8 @@ function StorageMechanics() {
) as StoragePointSchema | undefined; ) as StoragePointSchema | undefined;
if (point && "action" in point) { if (point && "action" in point) {
setSelectedPointData(point); setSelectedPointData(point);
setActiveOption(point.action.actionType as "store" | "spawn"); const uiOption = point.action.actionType === "retrieve" ? "spawn" : point.action.actionType;
setActiveOption(uiOption as "store" | "spawn");
setSelectedAction(point.action.actionUuid, point.action.actionName); setSelectedAction(point.action.actionUuid, point.action.actionName);
} }
} else { } else {
@@ -70,11 +72,12 @@ function StorageMechanics() {
const handleActionTypeChange = (option: string) => { const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return; if (!selectedEventData || !selectedPointData) return;
const validOption = option as "store" | "spawn"; const internalOption = actionTypeMap[option as keyof typeof actionTypeMap] as "store" | "retrieve";
setActiveOption(validOption);
setActiveOption(option as "store" | "spawn");
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
actionType: validOption, actionType: internalOption,
}); });
if (event) { if (event) {
@@ -87,7 +90,7 @@ function StorageMechanics() {
updateSelectedPointData(); updateSelectedPointData();
} }
if (validOption === "spawn") { if (option === "spawn") {
const storageUnit = getStorageUnitById(selectedEventData.data.modelUuid); const storageUnit = getStorageUnitById(selectedEventData.data.modelUuid);
if (storageUnit) { if (storageUnit) {
const materialType = selectedPointData.action.materialType || "Default material"; const materialType = selectedPointData.action.materialType || "Default material";
@@ -211,6 +214,11 @@ function StorageMechanics() {
options: ["store", "spawn"], options: ["store", "spawn"],
}; };
const actionTypeMap = {
spawn: "retrieve",
store: "store"
};
return ( return (
<> <>
{selectedEventData && ( {selectedEventData && (

View File

@@ -0,0 +1,207 @@
import { useCallback, useState, useEffect, useRef } from "react";
import * as THREE from 'three';
import { useFrame } from "@react-three/fiber";
import { useMaterialStore } from "../../../../../store/simulation/useMaterialStore";
import { useProductStore } from "../../../../../store/simulation/useProductStore";
import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore";
import { useStorageUnitStore } from "../../../../../store/simulation/useStorageUnitStore";
import { useArmBotStore } from "../../../../../store/simulation/useArmBotStore";
import { useVehicleStore } from "../../../../../store/simulation/useVehicleStore";
import { usePlayButtonStore, usePauseButtonStore, useResetButtonStore } from "../../../../../store/usePlayButtonStore";
export function useRetrieveHandler() {
const { addMaterial } = useMaterialStore();
const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid } = useProductStore();
const { getStorageUnitById, getLastMaterial } = useStorageUnitStore();
const { selectedProduct } = useSelectedProduct();
const { getArmBotById, addCurrentAction } = useArmBotStore();
const { getVehicleById } = useVehicleStore();
const { isPlaying } = usePlayButtonStore();
const { isPaused } = usePauseButtonStore();
const { isReset } = useResetButtonStore();
const [activeRetrievals, setActiveRetrievals] = useState<Map<string, { action: StorageAction, isProcessing: boolean, lastCheckTime: number }>>(new Map());
const [initialDelayComplete, setInitialDelayComplete] = useState(false);
const delayTimerRef = useRef<NodeJS.Timeout | null>(null);
const retrieveLogStatus = (materialUuid: string, status: string) => {
// console.log(`${materialUuid}, ${status}`);
}
const createNewMaterial = useCallback((materialId: string, materialType: string, action: StorageAction) => {
const modelUuid = getModelUuidByActionUuid(selectedProduct.productId, action.actionUuid);
const pointUuid = getPointUuidByActionUuid(selectedProduct.productId, action.actionUuid);
if (!modelUuid || !pointUuid) return null;
const currentTime = performance.now();
if (action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid &&
action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid &&
action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid
) {
const newMaterial: MaterialSchema = {
materialId: materialId,
materialName: `${materialType}-${Date.now()}`,
materialType: materialType,
isActive: false,
isVisible: false,
isPaused: false,
isRendered: true,
startTime: currentTime,
previous:{
modelUuid: modelUuid,
pointUuid: pointUuid,
actionUuid: action.actionUuid
},
current: {
modelUuid: action.triggers[0].triggeredAsset.triggeredModel.modelUuid,
pointUuid: action.triggers[0].triggeredAsset.triggeredPoint.pointUuid,
actionUuid: action.triggers[0].triggeredAsset.triggeredAction.actionUuid
},
};
addMaterial(newMaterial);
return newMaterial;
}
return null;
}, [addMaterial, getModelUuidByActionUuid, getPointUuidByActionUuid, selectedProduct.productId]);
useEffect(() => {
if (isPlaying && !initialDelayComplete) {
delayTimerRef.current = setTimeout(() => {
setInitialDelayComplete(true);
}, 3000);
}
return () => {
if (delayTimerRef.current) {
clearTimeout(delayTimerRef.current);
}
};
}, [isPlaying, initialDelayComplete]);
useEffect(() => {
if (isReset || isPaused) {
setInitialDelayComplete(false);
if (delayTimerRef.current) {
clearTimeout(delayTimerRef.current);
}
}
}, [isReset, isPaused]);
useFrame(() => {
if (!isPlaying || isPaused || isReset || !initialDelayComplete) return;
const currentTime = performance.now();
const completedActions: string[] = [];
let hasChanges = false;
activeRetrievals.forEach((retrieval, actionUuid) => {
if (retrieval.isProcessing) return;
const storageUnit = getStorageUnitById(
getModelUuidByActionUuid(selectedProduct.productId, retrieval.action.actionUuid) || ''
);
if (!storageUnit || storageUnit.currentLoad <= 0) {
completedActions.push(actionUuid);
hasChanges = true;
return;
}
if (retrieval.action.triggers.length === 0 || !retrieval.action.triggers[0].triggeredAsset) {
return;
}
const triggeredModel = getEventByModelUuid(
selectedProduct.productId,
retrieval.action.triggers[0].triggeredAsset.triggeredModel.modelUuid
);
if (!triggeredModel) return;
let isIdle = false;
if (triggeredModel.type === 'roboticArm') {
const armBot = getArmBotById(triggeredModel.modelUuid);
isIdle = armBot && !armBot.isActive && armBot.state === 'idle' && !armBot.currentAction || false;
} else if (triggeredModel.type === 'vehicle') {
const vehicle = getVehicleById(triggeredModel.modelUuid);
isIdle = vehicle && !vehicle.isActive && vehicle.state === 'idle' || false;
}
if (isIdle) {
setActiveRetrievals(prev => {
const newRetrievals = new Map(prev);
newRetrievals.set(actionUuid, {
...retrieval,
isProcessing: true,
lastCheckTime: currentTime
});
return newRetrievals;
});
const lastMaterial = getLastMaterial(storageUnit.modelUuid);
if (lastMaterial) {
const material = createNewMaterial(
lastMaterial.materialId,
lastMaterial.materialType,
storageUnit.point.action
);
if (material && triggeredModel.type === 'roboticArm') {
addCurrentAction(
triggeredModel.modelUuid,
retrieval.action.triggers[0].triggeredAsset.triggeredAction?.actionUuid || '',
material.materialType,
material.materialId
);
}
}
setActiveRetrievals(prev => {
const newRetrievals = new Map(prev);
newRetrievals.set(actionUuid, {
...retrieval,
isProcessing: false,
lastCheckTime: currentTime
});
return newRetrievals;
});
}
});
if (hasChanges || completedActions.length > 0) {
setActiveRetrievals(prev => {
const newRetrievals = new Map(prev);
completedActions.forEach(actionUuid => newRetrievals.delete(actionUuid));
return newRetrievals;
});
}
});
const handleRetrieve = useCallback((action: StorageAction) => {
if (!action || action.actionType !== 'retrieve') return;
setActiveRetrievals(prev => {
const newRetrievals = new Map(prev);
newRetrievals.set(action.actionUuid, {
action,
isProcessing: false,
lastCheckTime: performance.now()
});
return newRetrievals;
});
}, []);
useEffect(() => {
if (isReset) {
setActiveRetrievals(new Map());
setInitialDelayComplete(false);
}
}, [isReset]);
return {
handleRetrieve,
};
}

View File

@@ -21,7 +21,6 @@ export function useStoreHandler() {
if (!material) return; if (!material) return;
const modelUuid = getModelUuidByActionUuid(selectedProduct.productId, action.actionUuid); const modelUuid = getModelUuidByActionUuid(selectedProduct.productId, action.actionUuid);
if (!modelUuid) return; if (!modelUuid) return;
removeMaterial(material.materialId); removeMaterial(material.materialId);

View File

@@ -1,13 +1,19 @@
import { useEffect, useCallback } from 'react'; import { useEffect, useCallback } from 'react';
import { useStoreHandler } from './actionHandler/useStoreHandler'; import { useStoreHandler } from './actionHandler/useStoreHandler';
import { useRetrieveHandler } from './actionHandler/useRetrieveHandler';
export function useStorageActions() { export function useStorageActions() {
const { handleStore } = useStoreHandler(); const { handleStore } = useStoreHandler();
const { handleRetrieve } = useRetrieveHandler();
const handleStoreAction = useCallback((action: StorageAction, materialId: string) => { const handleStoreAction = useCallback((action: StorageAction, materialId: string) => {
handleStore(action, materialId); handleStore(action, materialId);
}, [handleStore]); }, [handleStore]);
const handleRetrieveAction = useCallback((action: StorageAction) => {
handleRetrieve(action);
}, [handleRetrieve]);
const handleStorageAction = useCallback((action: StorageAction, materialId: string) => { const handleStorageAction = useCallback((action: StorageAction, materialId: string) => {
if (!action) return; if (!action) return;
@@ -15,6 +21,9 @@ export function useStorageActions() {
case 'store': case 'store':
handleStoreAction(action, materialId); handleStoreAction(action, materialId);
break; break;
case 'retrieve':
handleRetrieveAction(action);
break;
default: default:
console.warn(`Unknown storage action type: ${action.actionType}`); console.warn(`Unknown storage action type: ${action.actionType}`);
} }

View File

@@ -35,7 +35,7 @@ export function useActionHandler() {
case 'process': case 'process':
handleMachineAction(action as MachineAction, materialId as string); handleMachineAction(action as MachineAction, materialId as string);
break; break;
case 'store': case 'store': case 'retrieve':
handleStorageAction(action as StorageAction, materialId as string); handleStorageAction(action as StorageAction, materialId as string);
break; break;
default: default:

View File

@@ -104,7 +104,7 @@ function Products() {
if (event.type === 'storageUnit') { if (event.type === 'storageUnit') {
addStorageUnit(selectedProduct.productId, event); addStorageUnit(selectedProduct.productId, event);
if (event.point.action.actionType === 'spawn') { if (event.point.action.actionType === 'retrieve') {
const storageAction = event.point.action as StorageAction; const storageAction = event.point.action as StorageAction;
const materials = Array.from({ length: storageAction.storageCapacity }, () => ({ const materials = Array.from({ length: storageAction.storageCapacity }, () => ({
materialType: storageAction.materialType || 'Default material', materialType: storageAction.materialType || 'Default material',

View File

@@ -10,6 +10,7 @@ import { useMaterialStore } from '../../../../../store/simulation/useMaterialSto
import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore'; import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore';
import { useProductStore } from '../../../../../store/simulation/useProductStore'; import { useProductStore } from '../../../../../store/simulation/useProductStore';
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
import { useStorageUnitStore } from '../../../../../store/simulation/useStorageUnitStore';
import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore';
import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler'; import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler';
@@ -28,6 +29,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
const { setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore(); const { setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore();
const { decrementVehicleLoad, removeLastMaterial } = useVehicleStore(); const { decrementVehicleLoad, removeLastMaterial } = useVehicleStore();
const { removeLastMaterial: removeLastStorageMaterial, updateCurrentLoad } = useStorageUnitStore();
const { setIsVisible, getMaterialById } = useMaterialStore(); const { setIsVisible, getMaterialById } = useMaterialStore();
const { selectedProduct } = useSelectedProduct(); const { selectedProduct } = useSelectedProduct();
const { getActionByUuid, getEventByActionUuid, getEventByModelUuid } = useProductStore(); const { getActionByUuid, getEventByActionUuid, getEventByModelUuid } = useProductStore();
@@ -58,6 +60,8 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
removeLastMaterial(previousModel.modelUuid); removeLastMaterial(previousModel.modelUuid);
} else if (previousModel.type === 'storageUnit') { } else if (previousModel.type === 'storageUnit') {
// storage unit logic // storage unit logic
removeLastStorageMaterial(previousModel.modelUuid);
updateCurrentLoad(previousModel.modelUuid, -1)
} }
} else { } else {
setIsVisible(armBot.currentAction.materialId, false); setIsVisible(armBot.currentAction.materialId, false);

View File

@@ -9,7 +9,7 @@ const MaterialAnimator = ({
const meshRef = useRef<any>(null!); const meshRef = useRef<any>(null!);
const [hasLoad, setHasLoad] = useState(false); const [hasLoad, setHasLoad] = useState(false);
const { scene } = useThree(); const { scene } = useThree();
const padding = 0.1; const padding = 0;
useEffect(() => { useEffect(() => {
setHasLoad(storage.currentLoad > 0); setHasLoad(storage.currentLoad > 0);

View File

@@ -131,6 +131,22 @@ function TriggerConnector() {
}); });
} }
} }
// Handle StorageUnit point
else if (event.type === "storageUnit" && 'point' in event) {
const point = event.point;
if (point.action?.triggers) {
point.action.triggers.forEach(trigger => {
if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
newConnections.push({
id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
startPointUuid: point.uuid,
endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
trigger
});
}
});
}
}
}); });
setConnections(newConnections); setConnections(newConnections);

View File

@@ -177,23 +177,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
if (action.triggers.length > 0 && action.triggers[0].triggeredAsset?.triggeredModel.modelUuid) { if (action.triggers.length > 0 && action.triggers[0].triggeredAsset?.triggeredModel.modelUuid) {
const storageUnit = getStorageUnitById(action.triggers[0].triggeredAsset?.triggeredModel.modelUuid); const storageUnit = getStorageUnitById(action.triggers[0].triggeredAsset?.triggeredModel.modelUuid);
if (storageUnit) { if (storageUnit) {
if (storageUnit.point.action.actionType === 'spawn') { if (storageUnit.point.action.actionType === 'store') {
// const newMaterial: MaterialSchema = {
// materialId: THREE.MathUtils.generateUUID(),
// materialName: `${storageUnit.point.action.materialType}-${Date.now()}`,
// materialType: storageUnit.point.action.materialType || 'Default material',
// isActive: false,
// isVisible: true,
// isPaused: false,
// isRendered: true,
// startTime: performance.now(),
// current: {
// modelUuid: storageUnit.modelUuid,
// pointUuid: storageUnit.point.uuid,
// actionUuid: storageUnit.point.action.actionUuid
// },
// };
} else if (storageUnit.point.action.actionType === 'store') {
handleMaterialDropToStorage( handleMaterialDropToStorage(
agvDetail.modelUuid, agvDetail.modelUuid,
agvDetail.currentLoad, agvDetail.currentLoad,

View File

@@ -22,7 +22,8 @@ interface StorageUnitStore {
addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void; addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void;
setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string; }[]) => void; setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string; }[]) => void;
removeLastMaterial: (modelUuid: string) => string | undefined; getLastMaterial: (modelUuid: string) => { materialId: string; materialType: string; } | undefined;
removeLastMaterial: (modelUuid: string) => { materialId: string; materialType: string; } | undefined;
clearCurrentMaterials: (modelUuid: string) => void; clearCurrentMaterials: (modelUuid: string) => void;
getStorageUnitById: (modelUuid: string) => StorageUnitStatus | undefined; getStorageUnitById: (modelUuid: string) => StorageUnitStatus | undefined;
@@ -140,20 +141,36 @@ export const useStorageUnitStore = create<StorageUnitStore>()(
}); });
}, },
getLastMaterial: (modelUuid) => {
let removedMaterial: { materialId: string; materialType: string; } | undefined;
set((state) => {
const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid);
if (storage) {
if (storage.currentMaterials.length > 0) {
const material = storage.currentMaterials[storage.currentMaterials.length - 1];
if (material) {
removedMaterial = { materialId: material.materialId, materialType: material.materialType };
}
}
}
});
return removedMaterial;
},
removeLastMaterial: (modelUuid) => { removeLastMaterial: (modelUuid) => {
let materialId: string | undefined; let removedMaterial: { materialId: string; materialType: string; } | undefined;
set((state) => { set((state) => {
const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid); const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid);
if (storage) { if (storage) {
if (storage.currentMaterials.length > 0) { if (storage.currentMaterials.length > 0) {
const material = storage.currentMaterials.pop(); const material = storage.currentMaterials.pop();
if (material) { if (material) {
materialId = material.materialId removedMaterial = { materialId: material.materialId, materialType: material.materialType };
} }
} }
} }
}); });
return materialId; return removedMaterial;
}, },
clearCurrentMaterials: (modelUuid) => { clearCurrentMaterials: (modelUuid) => {

View File

@@ -153,19 +153,19 @@ export const useVehicleStore = create<VehiclesStore>()(
}, },
removeLastMaterial: (modelUuid) => { removeLastMaterial: (modelUuid) => {
let materialId: { materialId: string; materialType: string; } | undefined; let removedMaterial: { materialId: string; materialType: string; } | undefined;
set((state) => { set((state) => {
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
if (vehicle) { if (vehicle) {
if (vehicle.currentMaterials.length > 0) { if (vehicle.currentMaterials.length > 0) {
const material = vehicle.currentMaterials.pop(); const material = vehicle.currentMaterials.pop();
if (material) { if (material) {
materialId = { materialId: material.materialId, materialType: material.materialType }; removedMaterial = { materialId: material.materialId, materialType: material.materialType };
} }
} }
} }
}); });
return materialId; return removedMaterial;
}, },
clearCurrentMaterials: (modelUuid) => { clearCurrentMaterials: (modelUuid) => {

View File

@@ -124,7 +124,7 @@ interface MachineAction {
interface StorageAction { interface StorageAction {
actionUuid: string; actionUuid: string;
actionName: string; actionName: string;
actionType: "store" | "spawn"; actionType: "store" | "retrieve";
materialType?: string; materialType?: string;
storageCapacity: number; storageCapacity: number;
triggers: TriggerSchema[]; triggers: TriggerSchema[];