feat: Implement Zustand stores for machine, simulation, storage unit, vehicle, and visualization management
- Added `useMachineStore` for managing machine statuses, including actions for adding, removing, and updating machines. - Introduced `useSimulationStore` to handle product and event management with actions for adding, removing, and updating products and events. - Created `useStorageUnitStore` for managing storage unit statuses, including load tracking and state updates. - Developed `useVehicleStore` for vehicle management, including load and state updates. - Implemented `useChartStore` for managing measurement data and visualization settings. - Added `useDroppedObjectsStore` for handling dropped objects in visualization zones, including object manipulation actions. - Created `useZone3DWidgetStore` for managing 3D widget data in zones, including position and rotation updates. - Introduced `useZoneStore` for managing selected zone states and widget configurations.
This commit is contained in:
172
app/src/store/simulation/useArmBotStore.ts
Normal file
172
app/src/store/simulation/useArmBotStore.ts
Normal file
@@ -0,0 +1,172 @@
|
||||
import { create } from 'zustand';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
interface ArmBotStatus extends RoboticArmSchemaEvent {
|
||||
productId: string;
|
||||
isActive: boolean;
|
||||
idleTime: number;
|
||||
activeTime: number;
|
||||
currentAction?: {
|
||||
actionUuid: string;
|
||||
actionName: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface ArmBotStore {
|
||||
armBots: Record<string, ArmBotStatus>;
|
||||
|
||||
// ArmBot actions
|
||||
addArmBot: (productId: string, event: RoboticArmSchemaEvent) => void;
|
||||
removeArmBot: (modelUuid: string) => void;
|
||||
updateArmBot: (
|
||||
modelUuid: string,
|
||||
updates: Partial<Omit<ArmBotStatus, 'modelUuid' | 'productId'>>
|
||||
) => void;
|
||||
|
||||
// Action management
|
||||
startAction: (modelUuid: string, actionUuid: string) => void;
|
||||
completeAction: (modelUuid: string) => void;
|
||||
cancelAction: (modelUuid: string) => void;
|
||||
|
||||
// Status updates
|
||||
setArmBotActive: (modelUuid: string, isActive: boolean) => void;
|
||||
|
||||
// Time tracking
|
||||
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
||||
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
|
||||
|
||||
// Helper functions
|
||||
getArmBotById: (modelUuid: string) => ArmBotStatus | undefined;
|
||||
getArmBotsByProduct: (productId: string) => ArmBotStatus[];
|
||||
getActiveArmBots: () => ArmBotStatus[];
|
||||
getIdleArmBots: () => ArmBotStatus[];
|
||||
getArmBotsByCurrentAction: (actionUuid: string) => ArmBotStatus[];
|
||||
}
|
||||
|
||||
export const useArmBotStore = create<ArmBotStore>()(
|
||||
immer((set, get) => ({
|
||||
armBots: {},
|
||||
|
||||
// ArmBot actions
|
||||
addArmBot: (productId, event) => {
|
||||
set((state) => {
|
||||
state.armBots[event.modelUuid] = {
|
||||
...event,
|
||||
productId,
|
||||
isActive: false,
|
||||
idleTime: 0,
|
||||
activeTime: 0,
|
||||
state: 'idle'
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
removeArmBot: (modelUuid) => {
|
||||
set((state) => {
|
||||
delete state.armBots[modelUuid];
|
||||
});
|
||||
},
|
||||
|
||||
updateArmBot: (modelUuid, updates) => {
|
||||
set((state) => {
|
||||
const armBot = state.armBots[modelUuid];
|
||||
if (armBot) {
|
||||
Object.assign(armBot, updates);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Action management
|
||||
startAction: (modelUuid, actionUuid) => {
|
||||
set((state) => {
|
||||
const armBot = state.armBots[modelUuid];
|
||||
if (armBot) {
|
||||
const action = armBot.point.actions.find(a => a.actionUuid === actionUuid);
|
||||
if (action) {
|
||||
armBot.currentAction = {
|
||||
actionUuid: action.actionUuid,
|
||||
actionName: action.actionName
|
||||
};
|
||||
armBot.isActive = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
completeAction: (modelUuid) => {
|
||||
set((state) => {
|
||||
const armBot = state.armBots[modelUuid];
|
||||
if (armBot && armBot.currentAction) {
|
||||
armBot.currentAction = undefined;
|
||||
armBot.isActive = false;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
cancelAction: (modelUuid) => {
|
||||
set((state) => {
|
||||
const armBot = state.armBots[modelUuid];
|
||||
if (armBot) {
|
||||
armBot.currentAction = undefined;
|
||||
armBot.isActive = false;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Status updates
|
||||
setArmBotActive: (modelUuid, isActive) => {
|
||||
set((state) => {
|
||||
const armBot = state.armBots[modelUuid];
|
||||
if (armBot) {
|
||||
armBot.isActive = isActive;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Time tracking
|
||||
incrementActiveTime: (modelUuid, incrementBy) => {
|
||||
set((state) => {
|
||||
const armBot = state.armBots[modelUuid];
|
||||
if (armBot) {
|
||||
armBot.activeTime += incrementBy;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
incrementIdleTime: (modelUuid, incrementBy) => {
|
||||
set((state) => {
|
||||
const armBot = state.armBots[modelUuid];
|
||||
if (armBot) {
|
||||
armBot.idleTime += incrementBy;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Helper functions
|
||||
getArmBotById: (modelUuid) => {
|
||||
return get().armBots[modelUuid];
|
||||
},
|
||||
|
||||
getArmBotsByProduct: (productId) => {
|
||||
return Object.values(get().armBots).filter(
|
||||
a => a.productId === productId
|
||||
);
|
||||
},
|
||||
|
||||
getActiveArmBots: () => {
|
||||
return Object.values(get().armBots).filter(a => a.isActive);
|
||||
},
|
||||
|
||||
getIdleArmBots: () => {
|
||||
return Object.values(get().armBots).filter(
|
||||
a => !a.isActive && a.state === 'idle'
|
||||
);
|
||||
},
|
||||
|
||||
getArmBotsByCurrentAction: (actionUuid) => {
|
||||
return Object.values(get().armBots).filter(
|
||||
a => a.currentAction?.actionUuid === actionUuid
|
||||
);
|
||||
}
|
||||
}))
|
||||
);
|
||||
129
app/src/store/simulation/useConveyorStore.ts
Normal file
129
app/src/store/simulation/useConveyorStore.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { create } from 'zustand';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
interface ConveyorStatus extends ConveyorEventSchema {
|
||||
productId: string;
|
||||
isActive: boolean;
|
||||
idleTime: number;
|
||||
activeTime: number;
|
||||
}
|
||||
|
||||
interface ConveyorStore {
|
||||
conveyors: Record<string, ConveyorStatus>;
|
||||
|
||||
// Actions
|
||||
addConveyor: (productId: string, event: ConveyorEventSchema) => void;
|
||||
removeConveyor: (modelUuid: string) => void;
|
||||
updateConveyor: (
|
||||
modelUuid: string,
|
||||
updates: Partial<Omit<ConveyorStatus, 'modelUuid' | 'productId'>>
|
||||
) => void;
|
||||
|
||||
// Status updates
|
||||
setConveyorActive: (modelUuid: string, isActive: boolean) => void;
|
||||
setConveyorState: (modelUuid: string, newState: ConveyorStatus['state']) => void;
|
||||
|
||||
// Time tracking
|
||||
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
||||
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
|
||||
|
||||
// Helper functions
|
||||
getConveyorById: (modelUuid: string) => ConveyorStatus | undefined;
|
||||
getConveyorsByProduct: (productId: string) => ConveyorStatus[];
|
||||
getActiveConveyors: () => ConveyorStatus[];
|
||||
getIdleConveyors: () => ConveyorStatus[];
|
||||
}
|
||||
|
||||
export const useConveyorStore = create<ConveyorStore>()(
|
||||
immer((set, get) => ({
|
||||
conveyors: {},
|
||||
|
||||
// Actions
|
||||
addConveyor: (productId, event) => {
|
||||
set((state) => {
|
||||
state.conveyors[event.modelUuid] = {
|
||||
...event,
|
||||
productId,
|
||||
isActive: false,
|
||||
idleTime: 0,
|
||||
activeTime: 0,
|
||||
state: 'idle',
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
removeConveyor: (modelUuid) => {
|
||||
set((state) => {
|
||||
delete state.conveyors[modelUuid];
|
||||
});
|
||||
},
|
||||
|
||||
updateConveyor: (modelUuid, updates) => {
|
||||
set((state) => {
|
||||
const conveyor = state.conveyors[modelUuid];
|
||||
if (conveyor) {
|
||||
Object.assign(conveyor, updates);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Status updates
|
||||
setConveyorActive: (modelUuid, isActive) => {
|
||||
set((state) => {
|
||||
const conveyor = state.conveyors[modelUuid];
|
||||
if (conveyor) {
|
||||
conveyor.isActive = isActive;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setConveyorState: (modelUuid, newState) => {
|
||||
set((state) => {
|
||||
const conveyor = state.conveyors[modelUuid];
|
||||
if (conveyor) {
|
||||
conveyor.state = newState;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Time tracking
|
||||
incrementActiveTime: (modelUuid, incrementBy) => {
|
||||
set((state) => {
|
||||
const conveyor = state.conveyors[modelUuid];
|
||||
if (conveyor) {
|
||||
conveyor.activeTime += incrementBy;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
incrementIdleTime: (modelUuid, incrementBy) => {
|
||||
set((state) => {
|
||||
const conveyor = state.conveyors[modelUuid];
|
||||
if (conveyor) {
|
||||
conveyor.idleTime += incrementBy;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Helper functions
|
||||
getConveyorById: (modelUuid) => {
|
||||
return get().conveyors[modelUuid];
|
||||
},
|
||||
|
||||
getConveyorsByProduct: (productId) => {
|
||||
return Object.values(get().conveyors).filter(
|
||||
c => c.productId === productId
|
||||
);
|
||||
},
|
||||
|
||||
getActiveConveyors: () => {
|
||||
return Object.values(get().conveyors).filter(c => c.isActive);
|
||||
},
|
||||
|
||||
getIdleConveyors: () => {
|
||||
return Object.values(get().conveyors).filter(
|
||||
c => !c.isActive && c.state === 'idle'
|
||||
);
|
||||
},
|
||||
}))
|
||||
);
|
||||
331
app/src/store/simulation/useEventsStore.ts
Normal file
331
app/src/store/simulation/useEventsStore.ts
Normal file
@@ -0,0 +1,331 @@
|
||||
import { create } from 'zustand';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
type EventsStore = {
|
||||
events: EventsSchema[];
|
||||
|
||||
// Event-level actions
|
||||
addEvent: (event: EventsSchema) => void;
|
||||
removeEvent: (modelUuid: string) => void;
|
||||
updateEvent: (modelUuid: string, updates: Partial<EventsSchema>) => void;
|
||||
|
||||
// Point-level actions
|
||||
addPoint: (modelUuid: string, point: ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void;
|
||||
removePoint: (modelUuid: string, pointUuid: string) => void;
|
||||
updatePoint: (
|
||||
modelUuid: string,
|
||||
pointUuid: string,
|
||||
updates: Partial<ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema>
|
||||
) => void;
|
||||
|
||||
// Action-level actions
|
||||
addAction: (
|
||||
modelUuid: string,
|
||||
pointUuid: string,
|
||||
action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']
|
||||
) => void;
|
||||
removeAction: (actionUuid: string) => void;
|
||||
updateAction: (
|
||||
actionUuid: string,
|
||||
updates: Partial<ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']>
|
||||
) => void;
|
||||
|
||||
// Trigger-level actions
|
||||
addTrigger: (actionUuid: string, trigger: TriggerSchema) => void;
|
||||
removeTrigger: (triggerUuid: string) => void;
|
||||
updateTrigger: (triggerUuid: string, updates: Partial<TriggerSchema>) => void;
|
||||
|
||||
// Helper functions
|
||||
getEventByModelUuid: (modelUuid: string) => EventsSchema | undefined;
|
||||
getPointByUuid: (modelUuid: string, pointUuid: string) => ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined;
|
||||
getActionByUuid: (actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined;
|
||||
getTriggerByUuid: (triggerUuid: string) => TriggerSchema | undefined;
|
||||
};
|
||||
|
||||
export const useEventsStore = create<EventsStore>()(
|
||||
immer((set, get) => ({
|
||||
events: [],
|
||||
|
||||
// Event-level actions
|
||||
addEvent: (event) => {
|
||||
set((state) => {
|
||||
state.events.push(event);
|
||||
});
|
||||
},
|
||||
|
||||
removeEvent: (modelUuid) => {
|
||||
set((state) => {
|
||||
state.events = state.events.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid);
|
||||
});
|
||||
},
|
||||
|
||||
updateEvent: (modelUuid, updates) => {
|
||||
set((state) => {
|
||||
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event) {
|
||||
Object.assign(event, updates);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Point-level actions
|
||||
addPoint: (modelUuid, point) => {
|
||||
set((state) => {
|
||||
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
(event as ConveyorEventSchema).points.push(point as ConveyorPointSchema);
|
||||
} else if (event && 'point' in event) {
|
||||
(event as VehicleSchemaEvent | RoboticArmSchemaEvent | MachineSchemaEvent | StorageSchemaEvent).point = point as any;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removePoint: (modelUuid, pointUuid) => {
|
||||
set((state) => {
|
||||
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
(event as ConveyorEventSchema).points = (event as ConveyorEventSchema).points.filter(p => p.uuid !== pointUuid);
|
||||
}
|
||||
// For single-point events, you might want to handle differently
|
||||
});
|
||||
},
|
||||
|
||||
updatePoint: (modelUuid, pointUuid, updates) => {
|
||||
set((state) => {
|
||||
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
|
||||
if (point) {
|
||||
Object.assign(point, updates);
|
||||
}
|
||||
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
|
||||
Object.assign((event as any).point, updates);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Action-level actions
|
||||
addAction: (modelUuid, pointUuid, action) => {
|
||||
set((state) => {
|
||||
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
|
||||
if (point) {
|
||||
point.action = action as any;
|
||||
}
|
||||
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
|
||||
if ('action' in (event as any).point) {
|
||||
(event as any).point.action = action;
|
||||
} else if ('actions' in (event as any).point) {
|
||||
(event as any).point.actions.push(action);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeAction: (actionUuid) => {
|
||||
set((state) => {
|
||||
for (const event of state.events) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && point.action.actionUuid === actionUuid) {
|
||||
// Handle removal for single action points
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if (event.type === "roboticArm") {
|
||||
if ('actions' in point) {
|
||||
point.actions = point.actions.filter((a: any) => a.actionUuid !== actionUuid);
|
||||
}
|
||||
} else if ('action' in point && point.action?.actionUuid === actionUuid) {
|
||||
// Handle single action
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateAction: (actionUuid, updates) => {
|
||||
set((state) => {
|
||||
for (const event of state.events) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && point.action.actionUuid === actionUuid) {
|
||||
Object.assign(point.action, updates);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && point.action.actionUuid === actionUuid) {
|
||||
Object.assign(point.action, updates);
|
||||
return;
|
||||
} else if ('actions' in point) {
|
||||
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
|
||||
if (action) {
|
||||
Object.assign(action, updates);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Trigger-level actions
|
||||
addTrigger: (actionUuid, trigger) => {
|
||||
set((state) => {
|
||||
for (const event of state.events) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && point.action.actionUuid === actionUuid) {
|
||||
point.action.triggers.push(trigger);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && point.action.actionUuid === actionUuid) {
|
||||
point.action.triggers.push(trigger);
|
||||
return;
|
||||
} else if ('actions' in point) {
|
||||
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
|
||||
if (action) {
|
||||
action.triggers.push(trigger);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeTrigger: (triggerUuid) => {
|
||||
set((state) => {
|
||||
for (const event of state.events) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && 'triggers' in point.action) {
|
||||
point.action.triggers = point.action.triggers.filter(t => t.triggerUuid !== triggerUuid);
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && 'triggers' in point.action) {
|
||||
point.action.triggers = point.action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
|
||||
} else if ('actions' in point) {
|
||||
for (const action of point.actions) {
|
||||
if ('triggers' in action) {
|
||||
action.triggers = action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateTrigger: (triggerUuid, updates) => {
|
||||
set((state) => {
|
||||
for (const event of state.events) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && 'triggers' in point.action) {
|
||||
const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid);
|
||||
if (trigger) {
|
||||
Object.assign(trigger, updates);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && 'triggers' in point.action) {
|
||||
const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||
if (trigger) {
|
||||
Object.assign(trigger, updates);
|
||||
return;
|
||||
}
|
||||
} else if ('actions' in point) {
|
||||
for (const action of point.actions) {
|
||||
if ('triggers' in action) {
|
||||
const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||
if (trigger) {
|
||||
Object.assign(trigger, updates);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Helper functions
|
||||
getEventByModelUuid: (modelUuid) => {
|
||||
return get().events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
},
|
||||
|
||||
getPointByUuid: (modelUuid, pointUuid) => {
|
||||
const event = get().events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
return (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
|
||||
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
|
||||
return (event as any).point;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getActionByUuid: (actionUuid) => {
|
||||
const state = get();
|
||||
for (const event of state.events) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && point.action.actionUuid === actionUuid) {
|
||||
return point.action;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && point.action.actionUuid === actionUuid) {
|
||||
return point.action;
|
||||
} else if ('actions' in point) {
|
||||
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
|
||||
if (action) return action;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getTriggerByUuid: (triggerUuid) => {
|
||||
const state = get();
|
||||
for (const event of state.events) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && 'triggers' in point.action) {
|
||||
const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid);
|
||||
if (trigger) return trigger;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && 'triggers' in point.action) {
|
||||
const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||
if (trigger) return trigger;
|
||||
} else if ('actions' in point) {
|
||||
for (const action of point.actions) {
|
||||
if ('triggers' in action) {
|
||||
const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||
if (trigger) return trigger;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}))
|
||||
);
|
||||
129
app/src/store/simulation/useMachineStore.ts
Normal file
129
app/src/store/simulation/useMachineStore.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { create } from 'zustand';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
interface MachineStatus extends MachineSchemaEvent {
|
||||
productId: string;
|
||||
isActive: boolean;
|
||||
idleTime: number;
|
||||
activeTime: number;
|
||||
}
|
||||
|
||||
interface MachineStore {
|
||||
machines: Record<string, MachineStatus>;
|
||||
|
||||
// Actions
|
||||
addMachine: (productId: string, machine: MachineSchemaEvent) => void;
|
||||
removeMachine: (modelUuid: string) => void;
|
||||
updateMachine: (
|
||||
modelUuid: string,
|
||||
updates: Partial<Omit<MachineStatus, 'modelUuid' | 'productId'>>
|
||||
) => void;
|
||||
|
||||
// Status updates
|
||||
setMachineActive: (modelUuid: string, isActive: boolean) => void;
|
||||
setMachineState: (modelUuid: string, newState: MachineStatus['state']) => void;
|
||||
|
||||
// Time tracking
|
||||
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
||||
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
|
||||
|
||||
// Helpers
|
||||
getMachineById: (modelUuid: string) => MachineStatus | undefined;
|
||||
getMachinesByProduct: (productId: string) => MachineStatus[];
|
||||
getActiveMachines: () => MachineStatus[];
|
||||
getIdleMachines: () => MachineStatus[];
|
||||
}
|
||||
|
||||
export const useMachineStore = create<MachineStore>()(
|
||||
immer((set, get) => ({
|
||||
machines: {},
|
||||
|
||||
// Actions
|
||||
addMachine: (productId, machine) => {
|
||||
set((state) => {
|
||||
state.machines[machine.modelUuid] = {
|
||||
...machine,
|
||||
productId,
|
||||
isActive: false,
|
||||
idleTime: 0,
|
||||
activeTime: 0,
|
||||
state: 'idle',
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
removeMachine: (modelUuid) => {
|
||||
set((state) => {
|
||||
delete state.machines[modelUuid];
|
||||
});
|
||||
},
|
||||
|
||||
updateMachine: (modelUuid, updates) => {
|
||||
set((state) => {
|
||||
const machine = state.machines[modelUuid];
|
||||
if (machine) {
|
||||
Object.assign(machine, updates);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Status updates
|
||||
setMachineActive: (modelUuid, isActive) => {
|
||||
set((state) => {
|
||||
const machine = state.machines[modelUuid];
|
||||
if (machine) {
|
||||
machine.isActive = isActive;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setMachineState: (modelUuid, newState) => {
|
||||
set((state) => {
|
||||
const machine = state.machines[modelUuid];
|
||||
if (machine) {
|
||||
machine.state = newState;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Time tracking
|
||||
incrementActiveTime: (modelUuid, incrementBy) => {
|
||||
set((state) => {
|
||||
const machine = state.machines[modelUuid];
|
||||
if (machine) {
|
||||
machine.activeTime += incrementBy;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
incrementIdleTime: (modelUuid, incrementBy) => {
|
||||
set((state) => {
|
||||
const machine = state.machines[modelUuid];
|
||||
if (machine) {
|
||||
machine.idleTime += incrementBy;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Helpers
|
||||
getMachineById: (modelUuid) => {
|
||||
return get().machines[modelUuid];
|
||||
},
|
||||
|
||||
getMachinesByProduct: (productId) => {
|
||||
return Object.values(get().machines).filter(
|
||||
m => m.productId === productId
|
||||
);
|
||||
},
|
||||
|
||||
getActiveMachines: () => {
|
||||
return Object.values(get().machines).filter(m => m.isActive);
|
||||
},
|
||||
|
||||
getIdleMachines: () => {
|
||||
return Object.values(get().machines).filter(
|
||||
m => !m.isActive && m.state === 'idle'
|
||||
);
|
||||
},
|
||||
}))
|
||||
);
|
||||
339
app/src/store/simulation/useSimulationStore.ts
Normal file
339
app/src/store/simulation/useSimulationStore.ts
Normal file
@@ -0,0 +1,339 @@
|
||||
import { create } from 'zustand';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
type ProductsStore = {
|
||||
products: productsSchema;
|
||||
|
||||
// Product-level actions
|
||||
addProduct: (productName: string, productId: string) => void;
|
||||
removeProduct: (productId: string) => void;
|
||||
updateProduct: (productId: string, updates: Partial<{ productName: string; eventsData: EventsSchema[] }>) => void;
|
||||
|
||||
// Event-level actions
|
||||
addEvent: (productId: string, event: EventsSchema) => void;
|
||||
removeEvent: (productId: string, modelUuid: string) => void;
|
||||
updateEvent: (productId: string, modelUuid: string, updates: Partial<EventsSchema>) => void;
|
||||
|
||||
// Point-level actions
|
||||
addPoint: (productId: string, modelUuid: string, point: ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void;
|
||||
removePoint: (productId: string, modelUuid: string, pointUuid: string) => void;
|
||||
updatePoint: (
|
||||
productId: string,
|
||||
modelUuid: string,
|
||||
pointUuid: string,
|
||||
updates: Partial<ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema>
|
||||
) => void;
|
||||
|
||||
// Action-level actions
|
||||
addAction: (
|
||||
productId: string,
|
||||
modelUuid: string,
|
||||
pointUuid: string,
|
||||
action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']
|
||||
) => void;
|
||||
removeAction: (actionUuid: string) => void;
|
||||
updateAction: (
|
||||
actionUuid: string,
|
||||
updates: Partial<ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']>
|
||||
) => void;
|
||||
|
||||
// Trigger-level actions
|
||||
addTrigger: (
|
||||
actionUuid: string,
|
||||
trigger: TriggerSchema
|
||||
) => void;
|
||||
removeTrigger: (triggerUuid: string) => void;
|
||||
updateTrigger: (
|
||||
triggerUuid: string,
|
||||
updates: Partial<TriggerSchema>
|
||||
) => void;
|
||||
|
||||
// Helper functions
|
||||
getProductById: (productId: string) => { productName: string; productId: string; eventsData: EventsSchema[] } | undefined;
|
||||
};
|
||||
|
||||
export const useProductStore = create<ProductsStore>()(
|
||||
immer((set, get) => ({
|
||||
products: [],
|
||||
|
||||
// Product-level actions
|
||||
addProduct: (productName, productId) => {
|
||||
set((state) => {
|
||||
const newProduct = {
|
||||
productName,
|
||||
productId: productId,
|
||||
eventsData: []
|
||||
};
|
||||
state.products.push(newProduct);
|
||||
});
|
||||
},
|
||||
|
||||
removeProduct: (productId) => {
|
||||
set((state) => {
|
||||
state.products = state.products.filter(p => p.productId !== productId);
|
||||
});
|
||||
},
|
||||
|
||||
updateProduct: (productId, updates) => {
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productId === productId);
|
||||
if (product) {
|
||||
Object.assign(product, updates);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Event-level actions
|
||||
addEvent: (productId, event) => {
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productId === productId);
|
||||
if (product) {
|
||||
product.eventsData.push(event);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeEvent: (productId, modelUuid) => {
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productId === productId);
|
||||
if (product) {
|
||||
product.eventsData = product.eventsData.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateEvent: (productId, modelUuid, updates) => {
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productId === productId);
|
||||
if (product) {
|
||||
const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event) {
|
||||
Object.assign(event, updates);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Point-level actions
|
||||
addPoint: (productId, modelUuid, point) => {
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productId === productId);
|
||||
if (product) {
|
||||
const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
(event as ConveyorEventSchema).points.push(point as ConveyorPointSchema);
|
||||
} else if (event && 'point' in event) {
|
||||
(event as VehicleSchemaEvent | RoboticArmSchemaEvent | MachineSchemaEvent | StorageSchemaEvent).point = point as any;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removePoint: (productId, modelUuid, pointUuid) => {
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productId === productId);
|
||||
if (product) {
|
||||
const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
(event as ConveyorEventSchema).points = (event as ConveyorEventSchema).points.filter(p => p.uuid !== pointUuid);
|
||||
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
|
||||
// For events with single point, we can't remove it, only reset to empty
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updatePoint: (productId, modelUuid, pointUuid, updates) => {
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productId === productId);
|
||||
if (product) {
|
||||
const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
|
||||
if (point) {
|
||||
Object.assign(point, updates);
|
||||
}
|
||||
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
|
||||
Object.assign((event as any).point, updates);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Action-level actions
|
||||
addAction: (productId, modelUuid, pointUuid, action) => {
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productId === productId);
|
||||
if (product) {
|
||||
const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
|
||||
if (point) {
|
||||
point.action = action as any;
|
||||
}
|
||||
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
|
||||
if ('action' in (event as any).point) {
|
||||
(event as any).point.action = action;
|
||||
} else if ('actions' in (event as any).point) {
|
||||
(event as any).point.actions.push(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeAction: (actionUuid: string) => {
|
||||
set((state) => {
|
||||
for (const product of state.products) {
|
||||
for (const event of product.eventsData) {
|
||||
if ('points' in event) {
|
||||
// Handle ConveyorEventSchema
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if (event.type === "roboticArm") {
|
||||
// Handle RoboticArmSchemaEvent
|
||||
if ('actions' in point) {
|
||||
point.actions = point.actions.filter((a: any) => a.actionUuid !== actionUuid);
|
||||
}
|
||||
} else if ('action' in point && point.action?.actionUuid === actionUuid) {
|
||||
// For other schemas with a single 'action'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateAction: (actionUuid, updates) => {
|
||||
set((state) => {
|
||||
for (const product of state.products) {
|
||||
for (const event of product.eventsData) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && point.action.actionUuid === actionUuid) {
|
||||
Object.assign(point.action, updates);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && point.action.actionUuid === actionUuid) {
|
||||
Object.assign(point.action, updates);
|
||||
return;
|
||||
} else if ('actions' in point) {
|
||||
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
|
||||
if (action) {
|
||||
Object.assign(action, updates);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Trigger-level actions
|
||||
addTrigger: (actionUuid, trigger) => {
|
||||
set((state) => {
|
||||
for (const product of state.products) {
|
||||
for (const event of product.eventsData) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && point.action.actionUuid === actionUuid) {
|
||||
point.action.triggers.push(trigger);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && point.action.actionUuid === actionUuid) {
|
||||
point.action.triggers.push(trigger);
|
||||
return;
|
||||
} else if ('actions' in point) {
|
||||
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
|
||||
if (action) {
|
||||
action.triggers.push(trigger);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeTrigger: (triggerUuid) => {
|
||||
set((state) => {
|
||||
for (const product of state.products) {
|
||||
for (const event of product.eventsData) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && 'triggers' in point.action) {
|
||||
point.action.triggers = point.action.triggers.filter(t => t.triggerUuid !== triggerUuid);
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && 'triggers' in point.action) {
|
||||
point.action.triggers = point.action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
|
||||
} else if ('actions' in point) {
|
||||
for (const action of point.actions) {
|
||||
if ('triggers' in action) {
|
||||
action.triggers = action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateTrigger: (triggerUuid, updates) => {
|
||||
set((state) => {
|
||||
for (const product of state.products) {
|
||||
for (const event of product.eventsData) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && 'triggers' in point.action) {
|
||||
const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid);
|
||||
if (trigger) {
|
||||
Object.assign(trigger, updates);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && 'triggers' in point.action) {
|
||||
const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||
if (trigger) {
|
||||
Object.assign(trigger, updates);
|
||||
return;
|
||||
}
|
||||
} else if ('actions' in point) {
|
||||
for (const action of point.actions) {
|
||||
if ('triggers' in action) {
|
||||
const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||
if (trigger) {
|
||||
Object.assign(trigger, updates);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Helper functions
|
||||
getProductById: (productId) => {
|
||||
return get().products.find(p => p.productId === productId);
|
||||
}
|
||||
}))
|
||||
);
|
||||
158
app/src/store/simulation/useStorageUnitStore.ts
Normal file
158
app/src/store/simulation/useStorageUnitStore.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
import { create } from 'zustand';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
interface StorageUnitStatus extends StorageSchemaEvent {
|
||||
productId: string;
|
||||
isActive: boolean;
|
||||
idleTime: number;
|
||||
activeTime: number;
|
||||
currentLoad: number;
|
||||
}
|
||||
|
||||
interface StorageUnitStore {
|
||||
storageUnits: Record<string, StorageUnitStatus>;
|
||||
|
||||
// Actions
|
||||
addStorageUnit: (productId: string, storageUnit: StorageSchemaEvent) => void;
|
||||
removeStorageUnit: (modelUuid: string) => void;
|
||||
updateStorageUnit: (
|
||||
modelUuid: string,
|
||||
updates: Partial<Omit<StorageUnitStatus, 'modelUuid' | 'productId'>>
|
||||
) => void;
|
||||
|
||||
// Status updates
|
||||
setStorageUnitActive: (modelUuid: string, isActive: boolean) => void;
|
||||
setStorageUnitState: (modelUuid: string, newState: StorageUnitStatus['state']) => void;
|
||||
|
||||
// Load updates
|
||||
updateStorageUnitLoad: (modelUuid: string, load: number) => void;
|
||||
|
||||
// Time tracking
|
||||
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
||||
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
|
||||
|
||||
// Helpers
|
||||
getStorageUnitById: (modelUuid: string) => StorageUnitStatus | undefined;
|
||||
getStorageUnitsByProduct: (productId: string) => StorageUnitStatus[];
|
||||
getActiveStorageUnits: () => StorageUnitStatus[];
|
||||
getIdleStorageUnits: () => StorageUnitStatus[];
|
||||
getFullStorageUnits: () => StorageUnitStatus[];
|
||||
getEmptyStorageUnits: () => StorageUnitStatus[];
|
||||
}
|
||||
|
||||
export const useStorageUnitStore = create<StorageUnitStore>()(
|
||||
immer((set, get) => ({
|
||||
storageUnits: {},
|
||||
|
||||
// Actions
|
||||
addStorageUnit: (productId, storageUnit) => {
|
||||
set((state) => {
|
||||
state.storageUnits[storageUnit.modelUuid] = {
|
||||
...storageUnit,
|
||||
productId,
|
||||
isActive: false,
|
||||
idleTime: 0,
|
||||
activeTime: 0,
|
||||
currentLoad: 0, // Initialize currentLoad to 0
|
||||
state: 'idle',
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
removeStorageUnit: (modelUuid) => {
|
||||
set((state) => {
|
||||
delete state.storageUnits[modelUuid];
|
||||
});
|
||||
},
|
||||
|
||||
updateStorageUnit: (modelUuid, updates) => {
|
||||
set((state) => {
|
||||
const storageUnit = state.storageUnits[modelUuid];
|
||||
if (storageUnit) {
|
||||
Object.assign(storageUnit, updates);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Status updates
|
||||
setStorageUnitActive: (modelUuid, isActive) => {
|
||||
set((state) => {
|
||||
const storageUnit = state.storageUnits[modelUuid];
|
||||
if (storageUnit) {
|
||||
storageUnit.isActive = isActive;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setStorageUnitState: (modelUuid, newState) => {
|
||||
set((state) => {
|
||||
const storageUnit = state.storageUnits[modelUuid];
|
||||
if (storageUnit) {
|
||||
storageUnit.state = newState;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Load updates
|
||||
updateStorageUnitLoad: (modelUuid, load) => {
|
||||
set((state) => {
|
||||
const storageUnit = state.storageUnits[modelUuid];
|
||||
if (storageUnit) {
|
||||
storageUnit.currentLoad = load;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Time tracking
|
||||
incrementActiveTime: (modelUuid, incrementBy) => {
|
||||
set((state) => {
|
||||
const storageUnit = state.storageUnits[modelUuid];
|
||||
if (storageUnit) {
|
||||
storageUnit.activeTime += incrementBy;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
incrementIdleTime: (modelUuid, incrementBy) => {
|
||||
set((state) => {
|
||||
const storageUnit = state.storageUnits[modelUuid];
|
||||
if (storageUnit) {
|
||||
storageUnit.idleTime += incrementBy;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Helpers
|
||||
getStorageUnitById: (modelUuid) => {
|
||||
return get().storageUnits[modelUuid];
|
||||
},
|
||||
|
||||
getStorageUnitsByProduct: (productId) => {
|
||||
return Object.values(get().storageUnits).filter(
|
||||
s => s.productId === productId
|
||||
);
|
||||
},
|
||||
|
||||
getActiveStorageUnits: () => {
|
||||
return Object.values(get().storageUnits).filter(s => s.isActive);
|
||||
},
|
||||
|
||||
getIdleStorageUnits: () => {
|
||||
return Object.values(get().storageUnits).filter(
|
||||
s => !s.isActive && s.state === 'idle'
|
||||
);
|
||||
},
|
||||
|
||||
getFullStorageUnits: () => {
|
||||
return Object.values(get().storageUnits).filter(
|
||||
s => s.currentLoad >= s.point.action.storageCapacity
|
||||
);
|
||||
},
|
||||
|
||||
getEmptyStorageUnits: () => {
|
||||
return Object.values(get().storageUnits).filter(
|
||||
s => s.currentLoad === 0
|
||||
);
|
||||
},
|
||||
}))
|
||||
);
|
||||
149
app/src/store/simulation/useVehicleStore.ts
Normal file
149
app/src/store/simulation/useVehicleStore.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import { create } from 'zustand';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
interface VehicleStatus extends VehicleSchemaEvent {
|
||||
productId: string;
|
||||
isActive: boolean;
|
||||
idleTime: number;
|
||||
activeTime: number;
|
||||
currentLoad: number;
|
||||
distanceTraveled: number;
|
||||
}
|
||||
|
||||
interface VehiclesStore {
|
||||
vehicles: Record<string, VehicleStatus>;
|
||||
|
||||
// Vehicle actions
|
||||
addVehicle: (productId: string, event: VehicleSchemaEvent) => void;
|
||||
removeVehicle: (modelUuid: string) => void;
|
||||
updateVehicle: (
|
||||
modelUuid: string,
|
||||
updates: Partial<Omit<VehicleStatus, 'modelUuid' | 'productId'>>
|
||||
) => void;
|
||||
|
||||
// Status updates
|
||||
setVehicleActive: (modelUuid: string, isActive: boolean) => void;
|
||||
updateVehicleLoad: (modelUuid: string, load: number) => void;
|
||||
|
||||
// State management
|
||||
setVehicleState: (modelUuid: string, newState: VehicleStatus['state']) => void;
|
||||
|
||||
// Time tracking
|
||||
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
||||
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
|
||||
|
||||
// Helper functions
|
||||
getVehicleById: (modelUuid: string) => VehicleStatus | undefined;
|
||||
getVehiclesByProduct: (productId: string) => VehicleStatus[];
|
||||
getActiveVehicles: () => VehicleStatus[];
|
||||
getIdleVehicles: () => VehicleStatus[];
|
||||
}
|
||||
|
||||
export const useVehicleStore = create<VehiclesStore>()(
|
||||
immer((set, get) => ({
|
||||
vehicles: {},
|
||||
|
||||
addVehicle: (productId, event) => {
|
||||
set((state) => {
|
||||
state.vehicles[event.modelUuid] = {
|
||||
...event,
|
||||
isActive: false,
|
||||
productId,
|
||||
idleTime: 0,
|
||||
activeTime: 0,
|
||||
currentLoad: 0,
|
||||
distanceTraveled: 0,
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
removeVehicle: (modelUuid) => {
|
||||
set((state) => {
|
||||
delete state.vehicles[modelUuid];
|
||||
});
|
||||
},
|
||||
|
||||
updateVehicle: (modelUuid, updates) => {
|
||||
set((state) => {
|
||||
const vehicle = state.vehicles[modelUuid];
|
||||
if (vehicle) {
|
||||
Object.assign(vehicle, updates);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Status updates
|
||||
setVehicleActive: (modelUuid, isActive) => {
|
||||
set((state) => {
|
||||
const vehicle = state.vehicles[modelUuid];
|
||||
if (vehicle) {
|
||||
vehicle.isActive = isActive;
|
||||
if (isActive) {
|
||||
vehicle.state = 'running';
|
||||
} else {
|
||||
vehicle.state = vehicle.currentLoad > 0 ? 'idle' : 'stopped';
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateVehicleLoad: (modelUuid, load) => {
|
||||
set((state) => {
|
||||
const vehicle = state.vehicles[modelUuid];
|
||||
if (vehicle) {
|
||||
vehicle.currentLoad = load;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// State management
|
||||
setVehicleState: (modelUuid, newState) => {
|
||||
set((state) => {
|
||||
const vehicle = state.vehicles[modelUuid];
|
||||
if (vehicle) {
|
||||
vehicle.state = newState;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Time tracking
|
||||
incrementActiveTime: (modelUuid, incrementBy) => {
|
||||
set((state) => {
|
||||
const vehicle = state.vehicles[modelUuid];
|
||||
if (vehicle) {
|
||||
vehicle.activeTime += incrementBy;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
incrementIdleTime: (modelUuid, incrementBy) => {
|
||||
set((state) => {
|
||||
const vehicle = state.vehicles[modelUuid];
|
||||
if (vehicle) {
|
||||
vehicle.idleTime += incrementBy;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Getters
|
||||
getVehicleById: (modelUuid) => {
|
||||
return get().vehicles[modelUuid];
|
||||
},
|
||||
|
||||
getVehiclesByProduct: (productId) => {
|
||||
return Object.values(get().vehicles).filter(
|
||||
v => v.productId === productId
|
||||
);
|
||||
},
|
||||
|
||||
getActiveVehicles: () => {
|
||||
return Object.values(get().vehicles).filter(v => v.isActive);
|
||||
},
|
||||
|
||||
getIdleVehicles: () => {
|
||||
return Object.values(get().vehicles).filter(
|
||||
v => !v.isActive && v.currentLoad > 0
|
||||
);
|
||||
}
|
||||
}))
|
||||
);
|
||||
Reference in New Issue
Block a user