Implement storage retrieval functionality: add useRetrieveHandler, update action handling in StorageMechanics, and modify related components for improved material management.
This commit is contained in:
@@ -31,7 +31,8 @@ function StorageMechanics() {
|
||||
) as StoragePointSchema | undefined;
|
||||
if (point && "action" in 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);
|
||||
}
|
||||
}
|
||||
@@ -46,7 +47,8 @@ function StorageMechanics() {
|
||||
) as StoragePointSchema | undefined;
|
||||
if (point && "action" in 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);
|
||||
}
|
||||
} else {
|
||||
@@ -70,11 +72,12 @@ function StorageMechanics() {
|
||||
|
||||
const handleActionTypeChange = (option: string) => {
|
||||
if (!selectedEventData || !selectedPointData) return;
|
||||
const validOption = option as "store" | "spawn";
|
||||
setActiveOption(validOption);
|
||||
const internalOption = actionTypeMap[option as keyof typeof actionTypeMap] as "store" | "retrieve";
|
||||
|
||||
setActiveOption(option as "store" | "spawn");
|
||||
|
||||
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
|
||||
actionType: validOption,
|
||||
actionType: internalOption,
|
||||
});
|
||||
|
||||
if (event) {
|
||||
@@ -87,7 +90,7 @@ function StorageMechanics() {
|
||||
updateSelectedPointData();
|
||||
}
|
||||
|
||||
if (validOption === "spawn") {
|
||||
if (option === "spawn") {
|
||||
const storageUnit = getStorageUnitById(selectedEventData.data.modelUuid);
|
||||
if (storageUnit) {
|
||||
const materialType = selectedPointData.action.materialType || "Default material";
|
||||
@@ -211,6 +214,11 @@ function StorageMechanics() {
|
||||
options: ["store", "spawn"],
|
||||
};
|
||||
|
||||
const actionTypeMap = {
|
||||
spawn: "retrieve",
|
||||
store: "store"
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{selectedEventData && (
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -21,7 +21,6 @@ export function useStoreHandler() {
|
||||
if (!material) return;
|
||||
|
||||
const modelUuid = getModelUuidByActionUuid(selectedProduct.productId, action.actionUuid);
|
||||
|
||||
if (!modelUuid) return;
|
||||
|
||||
removeMaterial(material.materialId);
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
import { useEffect, useCallback } from 'react';
|
||||
import { useStoreHandler } from './actionHandler/useStoreHandler';
|
||||
import { useRetrieveHandler } from './actionHandler/useRetrieveHandler';
|
||||
|
||||
export function useStorageActions() {
|
||||
const { handleStore } = useStoreHandler();
|
||||
const { handleRetrieve } = useRetrieveHandler();
|
||||
|
||||
const handleStoreAction = useCallback((action: StorageAction, materialId: string) => {
|
||||
handleStore(action, materialId);
|
||||
}, [handleStore]);
|
||||
|
||||
const handleRetrieveAction = useCallback((action: StorageAction) => {
|
||||
handleRetrieve(action);
|
||||
}, [handleRetrieve]);
|
||||
|
||||
const handleStorageAction = useCallback((action: StorageAction, materialId: string) => {
|
||||
if (!action) return;
|
||||
|
||||
@@ -15,6 +21,9 @@ export function useStorageActions() {
|
||||
case 'store':
|
||||
handleStoreAction(action, materialId);
|
||||
break;
|
||||
case 'retrieve':
|
||||
handleRetrieveAction(action);
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unknown storage action type: ${action.actionType}`);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ export function useActionHandler() {
|
||||
case 'process':
|
||||
handleMachineAction(action as MachineAction, materialId as string);
|
||||
break;
|
||||
case 'store':
|
||||
case 'store': case 'retrieve':
|
||||
handleStorageAction(action as StorageAction, materialId as string);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -104,7 +104,7 @@ function Products() {
|
||||
if (event.type === 'storageUnit') {
|
||||
addStorageUnit(selectedProduct.productId, event);
|
||||
|
||||
if (event.point.action.actionType === 'spawn') {
|
||||
if (event.point.action.actionType === 'retrieve') {
|
||||
const storageAction = event.point.action as StorageAction;
|
||||
const materials = Array.from({ length: storageAction.storageCapacity }, () => ({
|
||||
materialType: storageAction.materialType || 'Default material',
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useMaterialStore } from '../../../../../store/simulation/useMaterialSto
|
||||
import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore';
|
||||
import { useProductStore } from '../../../../../store/simulation/useProductStore';
|
||||
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
|
||||
import { useStorageUnitStore } from '../../../../../store/simulation/useStorageUnitStore';
|
||||
import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore';
|
||||
import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler';
|
||||
|
||||
@@ -28,6 +29,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||
|
||||
const { setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore();
|
||||
const { decrementVehicleLoad, removeLastMaterial } = useVehicleStore();
|
||||
const { removeLastMaterial: removeLastStorageMaterial, updateCurrentLoad } = useStorageUnitStore();
|
||||
const { setIsVisible, getMaterialById } = useMaterialStore();
|
||||
const { selectedProduct } = useSelectedProduct();
|
||||
const { getActionByUuid, getEventByActionUuid, getEventByModelUuid } = useProductStore();
|
||||
@@ -58,6 +60,8 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||
removeLastMaterial(previousModel.modelUuid);
|
||||
} else if (previousModel.type === 'storageUnit') {
|
||||
// storage unit logic
|
||||
removeLastStorageMaterial(previousModel.modelUuid);
|
||||
updateCurrentLoad(previousModel.modelUuid, -1)
|
||||
}
|
||||
} else {
|
||||
setIsVisible(armBot.currentAction.materialId, false);
|
||||
|
||||
@@ -9,7 +9,7 @@ const MaterialAnimator = ({
|
||||
const meshRef = useRef<any>(null!);
|
||||
const [hasLoad, setHasLoad] = useState(false);
|
||||
const { scene } = useThree();
|
||||
const padding = 0.1;
|
||||
const padding = 0;
|
||||
|
||||
useEffect(() => {
|
||||
setHasLoad(storage.currentLoad > 0);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -177,23 +177,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
||||
if (action.triggers.length > 0 && action.triggers[0].triggeredAsset?.triggeredModel.modelUuid) {
|
||||
const storageUnit = getStorageUnitById(action.triggers[0].triggeredAsset?.triggeredModel.modelUuid);
|
||||
if (storageUnit) {
|
||||
if (storageUnit.point.action.actionType === 'spawn') {
|
||||
// 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') {
|
||||
if (storageUnit.point.action.actionType === 'store') {
|
||||
handleMaterialDropToStorage(
|
||||
agvDetail.modelUuid,
|
||||
agvDetail.currentLoad,
|
||||
|
||||
@@ -22,7 +22,8 @@ interface StorageUnitStore {
|
||||
|
||||
addCurrentMaterial: (modelUuid: string, 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;
|
||||
|
||||
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) => {
|
||||
let materialId: string | undefined;
|
||||
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.pop();
|
||||
if (material) {
|
||||
materialId = material.materialId
|
||||
removedMaterial = { materialId: material.materialId, materialType: material.materialType };
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return materialId;
|
||||
return removedMaterial;
|
||||
},
|
||||
|
||||
clearCurrentMaterials: (modelUuid) => {
|
||||
|
||||
@@ -153,19 +153,19 @@ export const useVehicleStore = create<VehiclesStore>()(
|
||||
},
|
||||
|
||||
removeLastMaterial: (modelUuid) => {
|
||||
let materialId: { materialId: string; materialType: string; } | undefined;
|
||||
let removedMaterial: { materialId: string; materialType: string; } | undefined;
|
||||
set((state) => {
|
||||
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||
if (vehicle) {
|
||||
if (vehicle.currentMaterials.length > 0) {
|
||||
const material = vehicle.currentMaterials.pop();
|
||||
if (material) {
|
||||
materialId = { materialId: material.materialId, materialType: material.materialType };
|
||||
removedMaterial = { materialId: material.materialId, materialType: material.materialType };
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return materialId;
|
||||
return removedMaterial;
|
||||
},
|
||||
|
||||
clearCurrentMaterials: (modelUuid) => {
|
||||
|
||||
2
app/src/types/simulationTypes.d.ts
vendored
2
app/src/types/simulationTypes.d.ts
vendored
@@ -124,7 +124,7 @@ interface MachineAction {
|
||||
interface StorageAction {
|
||||
actionUuid: string;
|
||||
actionName: string;
|
||||
actionType: "store" | "spawn";
|
||||
actionType: "store" | "retrieve";
|
||||
materialType?: string;
|
||||
storageCapacity: number;
|
||||
triggers: TriggerSchema[];
|
||||
|
||||
Reference in New Issue
Block a user