added comparsion data
This commit is contained in:
@@ -1,15 +1,103 @@
|
|||||||
import { useProductContext } from '../../../modules/simulation/products/productContext'
|
import { useProductContext } from "../../../modules/simulation/products/productContext";
|
||||||
import RegularDropDown from '../../ui/inputs/RegularDropDown';
|
import RegularDropDown from "../../ui/inputs/RegularDropDown";
|
||||||
import { useCompareProductDataStore, useLoadingProgress, useSaveVersion } from '../../../store/builder/store';
|
import { useCompareProductDataStore, useLoadingProgress, useSaveVersion } from "../../../store/builder/store";
|
||||||
import useModuleStore from '../../../store/useModuleStore';
|
import useModuleStore from "../../../store/useModuleStore";
|
||||||
import CompareLayOut from '../../ui/compareVersion/CompareLayOut';
|
import CompareLayOut from "../../ui/compareVersion/CompareLayOut";
|
||||||
import ComparisonResult from '../../ui/compareVersion/ComparisonResult';
|
import ComparisonResult from "../../ui/compareVersion/ComparisonResult";
|
||||||
import { useComparisonProduct, useMainProduct } from '../../../store/simulation/useSimulationStore';
|
import { useComparisonProduct, useMainProduct } from "../../../store/simulation/useSimulationStore";
|
||||||
import { usePlayButtonStore } from '../../../store/usePlayButtonStore';
|
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from "react";
|
||||||
import { useVersionHistoryStore } from '../../../store/builder/useVersionHistoryStore';
|
import { useVersionHistoryStore } from "../../../store/builder/useVersionHistoryStore";
|
||||||
import { useVersionContext } from '../../../modules/builder/version/versionContext';
|
import { useVersionContext } from "../../../modules/builder/version/versionContext";
|
||||||
import { useSceneContext } from '../../../modules/scene/sceneContext';
|
import { useSceneContext } from "../../../modules/scene/sceneContext";
|
||||||
|
import { useSimulationManager } from "../../../store/rough/useSimulationManagerStore";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
|
||||||
|
export interface CompareProduct {
|
||||||
|
productUuid: string;
|
||||||
|
productName: string;
|
||||||
|
simulationData: {
|
||||||
|
roiPercentage: number;
|
||||||
|
netProfit: number;
|
||||||
|
productionCapacity: number;
|
||||||
|
paybackPeriod: number;
|
||||||
|
machineIdleTime: number;
|
||||||
|
machineActiveTime: number;
|
||||||
|
throughputData: number;
|
||||||
|
simulationTime?: number;
|
||||||
|
simulationCost?: number;
|
||||||
|
efficiencyScore?: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssetData = {
|
||||||
|
activeTime: number;
|
||||||
|
idleTime: number;
|
||||||
|
type: string;
|
||||||
|
assetId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const calculateSimulationData = (assets: AssetData[]) => {
|
||||||
|
let totalActiveTime = 0;
|
||||||
|
let totalIdleTime = 0;
|
||||||
|
let throughput = 0;
|
||||||
|
let productionCapacity = 0;
|
||||||
|
let simulationCost = 0;
|
||||||
|
|
||||||
|
// Cost weight per type (example values, adjust as needed)
|
||||||
|
const costWeight: Record<string, number> = {
|
||||||
|
roboticArm: 50,
|
||||||
|
machine: 100,
|
||||||
|
human: 30,
|
||||||
|
transfer: 20,
|
||||||
|
storageUnit: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
assets.forEach((asset) => {
|
||||||
|
totalActiveTime += asset.activeTime;
|
||||||
|
totalIdleTime += asset.idleTime;
|
||||||
|
|
||||||
|
if (asset.activeTime > 0) throughput += 1;
|
||||||
|
|
||||||
|
productionCapacity += asset.activeTime;
|
||||||
|
simulationCost += asset.activeTime * (costWeight[asset.type] || 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
const machineActiveTime = assets.filter((a) => a.type === "machine").reduce((acc, a) => acc + a.activeTime, 0);
|
||||||
|
|
||||||
|
const machineIdleTime = assets.filter((a) => a.type === "machine").reduce((acc, a) => acc + a.idleTime, 0);
|
||||||
|
|
||||||
|
const simulationTime = totalActiveTime + totalIdleTime;
|
||||||
|
|
||||||
|
// --- Efficiency Score ---
|
||||||
|
// Weighted formula: lower cost + lower time => higher score
|
||||||
|
// Example formula (normalize to 0–100):
|
||||||
|
const efficiencyScore = Math.max(
|
||||||
|
0,
|
||||||
|
100 -
|
||||||
|
(simulationTime / 1000) * 0.5 - // weight 0.5 for time
|
||||||
|
(simulationCost / 1000) * 0.5 // weight 0.5 for cost
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
throughputData: throughput,
|
||||||
|
machineActiveTime,
|
||||||
|
machineIdleTime,
|
||||||
|
productionCapacity,
|
||||||
|
netProfit: 0, // placeholder
|
||||||
|
roiPercentage: 0, // placeholder
|
||||||
|
paybackPeriod: 0, // placeholder
|
||||||
|
simulationTime,
|
||||||
|
simulationCost,
|
||||||
|
efficiencyScore,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createCompareProduct = (productUuid: string, productName: string, assets: AssetData[]): CompareProduct => ({
|
||||||
|
productUuid,
|
||||||
|
productName,
|
||||||
|
simulationData: calculateSimulationData(assets),
|
||||||
|
});
|
||||||
|
|
||||||
function ComparisonScene() {
|
function ComparisonScene() {
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
@@ -27,6 +115,8 @@ function ComparisonScene() {
|
|||||||
const { versionHistory } = useVersionHistoryStore();
|
const { versionHistory } = useVersionHistoryStore();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion, setSelectedVersion } = selectedVersionStore();
|
const { selectedVersion, setSelectedVersion } = selectedVersionStore();
|
||||||
|
const { simulationRecords } = useSimulationManager();
|
||||||
|
const { projectId } = useParams();
|
||||||
|
|
||||||
const handleSelectVersion = (option: string) => {
|
const handleSelectVersion = (option: string) => {
|
||||||
const version = versionHistory.find((version) => version.versionName === option);
|
const version = versionHistory.find((version) => version.versionName === option);
|
||||||
@@ -79,27 +169,53 @@ function ComparisonScene() {
|
|||||||
// ])
|
// ])
|
||||||
// }, []);
|
// }, []);
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
|
||||||
|
// console.log('mainProduct: ', mainProduct);
|
||||||
|
// console.log('comparisonProduct: ', comparisonProduct);
|
||||||
|
// if (mainProduct && comparisonProduct) {
|
||||||
|
// // if (mainProduct && comparisonProduct && compareProductsData.length > 1) {
|
||||||
|
// // console.log('compareProductsData: ', compareProductsData);
|
||||||
|
// const hasMain = compareProductsData.some(val => val.productUuid === mainProduct.productUuid);
|
||||||
|
// const hasComparison = compareProductsData.some(val => val.productUuid === comparisonProduct.productUuid);
|
||||||
|
// console.log('hasMain: ', hasMain);
|
||||||
|
// console.log('hasComparison: ', hasComparison);
|
||||||
|
// if (hasMain && hasComparison) {
|
||||||
|
// setShouldShowComparisonResult(true);
|
||||||
|
// } else {
|
||||||
|
// setShouldShowComparisonResult(false);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }, [compareProductsData, mainProduct, comparisonProduct]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (mainProduct && comparisonProduct && compareProductsData.length > 1) {
|
if (mainProduct && comparisonProduct && selectedVersion) {
|
||||||
// console.log('compareProductsData: ', compareProductsData);
|
const product1 = useSimulationManager.getState().getProductById(projectId, selectedVersion?.versionId, mainProduct.productUuid);
|
||||||
const hasMain = compareProductsData.some(val => val.productUuid === mainProduct.productUuid);
|
|
||||||
const hasComparison = compareProductsData.some(val => val.productUuid === comparisonProduct.productUuid);
|
const product2 = useSimulationManager.getState().getProductById(projectId, selectedVersion?.versionId, comparisonProduct.productUuid);
|
||||||
if (hasMain && hasComparison && mainProduct.productUuid !== comparisonProduct.productUuid) {
|
|
||||||
|
const compareProduct1 = createCompareProduct(product1?.productId ?? "", mainProduct.productName, product1?.data || []);
|
||||||
|
const compareProduct2 = createCompareProduct(product2?.productId ?? "", comparisonProduct.productName, product2?.data || []);
|
||||||
|
|
||||||
|
const comparedArray = [compareProduct1, compareProduct2];
|
||||||
|
|
||||||
|
if (product1 == undefined || product2 === undefined) {
|
||||||
|
setShouldShowComparisonResult(false);
|
||||||
|
} else if (comparedArray.length === 2) {
|
||||||
|
console.log("comparedArray: ", comparedArray);
|
||||||
|
setCompareProductsData(comparedArray);
|
||||||
setShouldShowComparisonResult(true);
|
setShouldShowComparisonResult(true);
|
||||||
} else {
|
|
||||||
setShouldShowComparisonResult(false);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setShouldShowComparisonResult(false);
|
setShouldShowComparisonResult(false);
|
||||||
}
|
}
|
||||||
}, [compareProductsData, mainProduct, comparisonProduct]);
|
}, [mainProduct, comparisonProduct, simulationRecords]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isVersionSaved && activeModule === "simulation" && selectedProduct && (
|
{isVersionSaved && activeModule === "simulation" && selectedProduct && (
|
||||||
<>
|
<>
|
||||||
{selectedVersion && !isPlaying &&
|
{selectedVersion && !isPlaying && (
|
||||||
<div className="initial-selectLayout-wrapper">
|
<div className="initial-selectLayout-wrapper">
|
||||||
<RegularDropDown
|
<RegularDropDown
|
||||||
header={selectedVersion.versionName}
|
header={selectedVersion.versionName}
|
||||||
@@ -115,14 +231,13 @@ function ComparisonScene() {
|
|||||||
search={false}
|
search={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
)}
|
||||||
<CompareLayOut />
|
<CompareLayOut />
|
||||||
|
{shouldShowComparisonResult && !loadingProgress && compareProductsData && <ComparisonResult />}
|
||||||
{(shouldShowComparisonResult && !loadingProgress) && <ComparisonResult />}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ComparisonScene;
|
export default ComparisonScene;
|
||||||
|
|||||||
@@ -9,5 +9,6 @@ export const saveSimulationData = ({ key, data }: SimulationData) => {
|
|||||||
export const getSimulationData = ({ key }: SimulationData) => {
|
export const getSimulationData = ({ key }: SimulationData) => {
|
||||||
const data = localStorage.getItem(key);
|
const data = localStorage.getItem(key);
|
||||||
console.log("data: ", JSON.parse(data || "{}"));
|
console.log("data: ", JSON.parse(data || "{}"));
|
||||||
|
return data;
|
||||||
};
|
};
|
||||||
export const clearSimulationData = ({ key, data }: SimulationData) => {};
|
export const clearSimulationData = ({ key, data }: SimulationData) => {};
|
||||||
|
|||||||
@@ -2,9 +2,25 @@ import React, { useEffect, useMemo, useState } from "react";
|
|||||||
import PerformanceResult from "./result-card/PerformanceResult";
|
import PerformanceResult from "./result-card/PerformanceResult";
|
||||||
import EnergyUsage from "./result-card/EnergyUsage";
|
import EnergyUsage from "./result-card/EnergyUsage";
|
||||||
import { Bar, Line, Pie } from "react-chartjs-2";
|
import { Bar, Line, Pie } from "react-chartjs-2";
|
||||||
import { CompareProduct, useCompareProductDataStore } from "../../../store/builder/store";
|
import { useCompareProductDataStore } from "../../../store/builder/store";
|
||||||
|
// import { CompareProduct, useCompareProductDataStore } from "../../../store/builder/store";
|
||||||
import { useComparisonProduct, useMainProduct } from "../../../store/simulation/useSimulationStore";
|
import { useComparisonProduct, useMainProduct } from "../../../store/simulation/useSimulationStore";
|
||||||
|
export interface CompareProduct {
|
||||||
|
productUuid: string;
|
||||||
|
productName: string;
|
||||||
|
simulationData: {
|
||||||
|
roiPercentage: number;
|
||||||
|
netProfit: number;
|
||||||
|
productionCapacity: number;
|
||||||
|
paybackPeriod: number;
|
||||||
|
machineIdleTime: number;
|
||||||
|
machineActiveTime: number;
|
||||||
|
throughputData: number;
|
||||||
|
simulationTime?: number;
|
||||||
|
simulationCost?: number;
|
||||||
|
efficiencyScore?: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
const ComparisonResult = () => {
|
const ComparisonResult = () => {
|
||||||
const { compareProductsData, setCompareProductsData } = useCompareProductDataStore();
|
const { compareProductsData, setCompareProductsData } = useCompareProductDataStore();
|
||||||
const { comparisonProduct, setComparisonProduct } = useComparisonProduct();
|
const { comparisonProduct, setComparisonProduct } = useComparisonProduct();
|
||||||
@@ -13,12 +29,8 @@ const ComparisonResult = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (compareProductsData.length > 0 && mainProduct && comparisonProduct) {
|
if (compareProductsData.length > 0 && mainProduct && comparisonProduct) {
|
||||||
const mainProductData = compareProductsData.find(
|
const mainProductData = compareProductsData.find((product) => product.productUuid === mainProduct.productUuid);
|
||||||
(product) => product.productUuid === mainProduct.productUuid
|
const comparisonProductData = compareProductsData.find((product) => product.productUuid === comparisonProduct.productUuid);
|
||||||
);
|
|
||||||
const comparisonProductData = compareProductsData.find(
|
|
||||||
(product) => product.productUuid === comparisonProduct.productUuid
|
|
||||||
);
|
|
||||||
|
|
||||||
if (mainProductData && comparisonProductData) {
|
if (mainProductData && comparisonProductData) {
|
||||||
setComparedProducts([mainProductData, comparisonProductData]);
|
setComparedProducts([mainProductData, comparisonProductData]);
|
||||||
@@ -32,7 +44,6 @@ const ComparisonResult = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (comparedProducts.length === 2) {
|
if (comparedProducts.length === 2) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}, [comparedProducts]);
|
}, [comparedProducts]);
|
||||||
|
|
||||||
@@ -71,7 +82,6 @@ const ComparisonResult = () => {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const cycleTimePieData = {
|
const cycleTimePieData = {
|
||||||
labels: [comparedProducts[0]?.productName, comparedProducts[1]?.productName],
|
labels: [comparedProducts[0]?.productName, comparedProducts[1]?.productName],
|
||||||
datasets: [
|
datasets: [
|
||||||
@@ -115,25 +125,17 @@ const ComparisonResult = () => {
|
|||||||
|
|
||||||
const highestProductivityProduct = (comparedProducts[0]?.simulationData?.productionCapacity ?? 0) > (comparedProducts[1]?.simulationData?.productionCapacity ?? 0) ? comparedProducts[0] : comparedProducts[1];
|
const highestProductivityProduct = (comparedProducts[0]?.simulationData?.productionCapacity ?? 0) > (comparedProducts[1]?.simulationData?.productionCapacity ?? 0) ? comparedProducts[0] : comparedProducts[1];
|
||||||
|
|
||||||
const product1CyclePercentage = (comparedProducts[0]?.simulationData?.machineActiveTime ?? 0) /
|
const product1CyclePercentage = ((comparedProducts[0]?.simulationData?.machineActiveTime ?? 0) / ((compareProductsData[0]?.simulationData?.machineActiveTime ?? 0) + (compareProductsData[0]?.simulationData?.machineIdleTime ?? 0))) * 100;
|
||||||
((compareProductsData[0]?.simulationData?.machineActiveTime ?? 0) +
|
const product2CyclePercentage = ((comparedProducts[1]?.simulationData?.machineActiveTime ?? 0) / ((compareProductsData[1]?.simulationData?.machineActiveTime ?? 0) + (compareProductsData[1]?.simulationData?.machineIdleTime ?? 0))) * 100;
|
||||||
(compareProductsData[0]?.simulationData?.machineIdleTime ?? 0)) * 100;
|
|
||||||
const product2CyclePercentage = ((comparedProducts[1]?.simulationData?.machineActiveTime ?? 0) /
|
|
||||||
((compareProductsData[1]?.simulationData?.machineActiveTime ?? 0) +
|
|
||||||
(compareProductsData[1]?.simulationData?.machineIdleTime ?? 0))) * 100;
|
|
||||||
|
|
||||||
const product1IdlePercentage = (comparedProducts[0]?.simulationData?.machineIdleTime ?? 0) /
|
const product1IdlePercentage = ((comparedProducts[0]?.simulationData?.machineIdleTime ?? 0) / ((compareProductsData[0]?.simulationData?.machineActiveTime ?? 0) + (compareProductsData[0]?.simulationData?.machineIdleTime ?? 0))) * 100;
|
||||||
((compareProductsData[0]?.simulationData?.machineActiveTime ?? 0) +
|
const product2IdlePercentage = ((comparedProducts[1]?.simulationData?.machineIdleTime ?? 0) / ((compareProductsData[1]?.simulationData?.machineActiveTime ?? 0) + (compareProductsData[1]?.simulationData?.machineIdleTime ?? 0))) * 100;
|
||||||
(compareProductsData[0]?.simulationData?.machineIdleTime ?? 0)) * 100;
|
|
||||||
const product2IdlePercentage = ((comparedProducts[1]?.simulationData?.machineIdleTime ?? 0) /
|
|
||||||
((compareProductsData[1]?.simulationData?.machineActiveTime ?? 0) +
|
|
||||||
(compareProductsData[1]?.simulationData?.machineIdleTime ?? 0))) * 100;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="compare-result-container">
|
<div className="compare-result-container">
|
||||||
<div className="header">Performance Comparison</div>
|
<div className="header">Performance Comparison</div>
|
||||||
<div className="compare-result-wrapper">
|
<div className="compare-result-wrapper">
|
||||||
<EnergyUsage comparedProducts={comparedProducts}/>
|
<EnergyUsage comparedProducts={comparedProducts} />
|
||||||
<div className="throughPutCard-container comparisionCard">
|
<div className="throughPutCard-container comparisionCard">
|
||||||
<h4>Throughput (units/hr)</h4>
|
<h4>Throughput (units/hr)</h4>
|
||||||
<div className="layers-wrapper">
|
<div className="layers-wrapper">
|
||||||
@@ -159,14 +161,16 @@ const ComparisonResult = () => {
|
|||||||
<div className="layer-name">{comparedProducts[0]?.productName}</div>
|
<div className="layer-name">{comparedProducts[0]?.productName}</div>
|
||||||
<div className="layer-time">{compareProductsData[0]?.simulationData.machineActiveTime} Sec</div>
|
<div className="layer-time">{compareProductsData[0]?.simulationData.machineActiveTime} Sec</div>
|
||||||
<div className="layer-profit">
|
<div className="layer-profit">
|
||||||
<span>↑</span>{(100 - product1CyclePercentage).toFixed(2)}%
|
<span>↑</span>
|
||||||
|
{(100 - product1CyclePercentage).toFixed(2)}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="layers">
|
<div className="layers">
|
||||||
<div className="layer-name">{comparedProducts[1]?.productName}</div>
|
<div className="layer-name">{comparedProducts[1]?.productName}</div>
|
||||||
<div className="layer-time">{compareProductsData[1]?.simulationData.machineActiveTime} Sec</div>
|
<div className="layer-time">{compareProductsData[1]?.simulationData.machineActiveTime} Sec</div>
|
||||||
<div className="layer-profit">
|
<div className="layer-profit">
|
||||||
<span>↑</span>{(100 - product2CyclePercentage).toFixed(2)}%
|
<span>↑</span>
|
||||||
|
{(100 - product2CyclePercentage).toFixed(2)}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -184,14 +188,16 @@ const ComparisonResult = () => {
|
|||||||
<div className="layer-name">{comparedProducts[0]?.productName}</div>
|
<div className="layer-name">{comparedProducts[0]?.productName}</div>
|
||||||
<div className="layer-time">{compareProductsData[0]?.simulationData.machineIdleTime} Sec</div>
|
<div className="layer-time">{compareProductsData[0]?.simulationData.machineIdleTime} Sec</div>
|
||||||
<div className="layer-profit">
|
<div className="layer-profit">
|
||||||
<span>↑</span>{(100 - product1IdlePercentage).toFixed(2)}%
|
<span>↑</span>
|
||||||
|
{(100 - product1IdlePercentage).toFixed(2)}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="layers">
|
<div className="layers">
|
||||||
<div className="layer-name">{comparedProducts[1]?.productName}</div>
|
<div className="layer-name">{comparedProducts[1]?.productName}</div>
|
||||||
<div className="layer-time">{compareProductsData[1]?.simulationData.machineIdleTime} Sec</div>
|
<div className="layer-time">{compareProductsData[1]?.simulationData.machineIdleTime} Sec</div>
|
||||||
<div className="layer-profit">
|
<div className="layer-profit">
|
||||||
<span>↑</span>{(100 - product2IdlePercentage).toFixed(2)}%
|
<span>↑</span>
|
||||||
|
{(100 - product2IdlePercentage).toFixed(2)}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -200,7 +206,7 @@ const ComparisonResult = () => {
|
|||||||
<Pie data={downtimeData} options={options} />
|
<Pie data={downtimeData} options={options} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/*
|
{/*
|
||||||
<div className="overallDowntime-container comparisionCard">
|
<div className="overallDowntime-container comparisionCard">
|
||||||
<h4 className="overallDowntime-header">Overall Downtime</h4>
|
<h4 className="overallDowntime-header">Overall Downtime</h4>
|
||||||
<div className="totalDownTime-wrapper">
|
<div className="totalDownTime-wrapper">
|
||||||
@@ -234,7 +240,7 @@ const ComparisonResult = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{ comparedProducts.length === 2 &&<PerformanceResult comparedProducts={comparedProducts}/>}
|
{comparedProducts.length === 2 && <PerformanceResult comparedProducts={comparedProducts} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -222,6 +222,7 @@ export default function ThroughPutData() {
|
|||||||
|
|
||||||
const Throughput_per_day = Units_per_shift * shiftsPerDay * (yieldRate / 100);
|
const Throughput_per_day = Units_per_shift * shiftsPerDay * (yieldRate / 100);
|
||||||
const data = Number(Throughput_per_day.toFixed(2))
|
const data = Number(Throughput_per_day.toFixed(2))
|
||||||
|
console.log('data: ', data);
|
||||||
saveSimulationData({ key: selectedProduct.productUuid, data: data });
|
saveSimulationData({ key: selectedProduct.productUuid, data: data });
|
||||||
|
|
||||||
setMaterialData({ ...materialData, throughput: data });
|
setMaterialData({ ...materialData, throughput: data });
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from "react";
|
||||||
import { useSceneContext } from '../../scene/sceneContext';
|
import { useSceneContext } from "../../scene/sceneContext";
|
||||||
import { useProductContext } from '../products/productContext';
|
import { useProductContext } from "../products/productContext";
|
||||||
import { determineExecutionMachineSequences } from './functions/determineExecutionMachineSequences';
|
import { determineExecutionMachineSequences } from "./functions/determineExecutionMachineSequences";
|
||||||
import { usePlayButtonStore } from '../../../store/usePlayButtonStore';
|
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||||
import { useSimulationManager } from '../../../store/rough/useSimulationManagerStore';
|
import { useSimulationManager } from "../../../store/rough/useSimulationManagerStore";
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from "react-router-dom";
|
||||||
import { useVersionContext } from '../../builder/version/versionContext';
|
import { useVersionContext } from "../../builder/version/versionContext";
|
||||||
|
import { getSimulationData, saveSimulationData } from "../../../components/layout/scenes/functions/simulationStorage";
|
||||||
|
import { get } from "http";
|
||||||
interface SimulationUsageRecord {
|
interface SimulationUsageRecord {
|
||||||
activeTime: number;
|
activeTime: number;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
@@ -38,7 +40,17 @@ interface ProjectSimulation {
|
|||||||
versions: VersionSimulation[];
|
versions: VersionSimulation[];
|
||||||
}
|
}
|
||||||
const SimulationHandler = () => {
|
const SimulationHandler = () => {
|
||||||
const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, productStore, craneStore, humanStore } = useSceneContext();
|
const {
|
||||||
|
materialStore,
|
||||||
|
armBotStore,
|
||||||
|
machineStore,
|
||||||
|
conveyorStore,
|
||||||
|
vehicleStore,
|
||||||
|
storageUnitStore,
|
||||||
|
productStore,
|
||||||
|
craneStore,
|
||||||
|
humanStore,
|
||||||
|
} = useSceneContext();
|
||||||
const { armBots, getArmBotById } = armBotStore();
|
const { armBots, getArmBotById } = armBotStore();
|
||||||
const { vehicles, getVehicleById } = vehicleStore();
|
const { vehicles, getVehicleById } = vehicleStore();
|
||||||
const { getConveyorById } = conveyorStore();
|
const { getConveyorById } = conveyorStore();
|
||||||
@@ -48,16 +60,106 @@ const SimulationHandler = () => {
|
|||||||
const { selectedProduct } = selectedProductStore();
|
const { selectedProduct } = selectedProductStore();
|
||||||
const { machines, getMachineById } = machineStore();
|
const { machines, getMachineById } = machineStore();
|
||||||
const { getHumanById } = humanStore();
|
const { getHumanById } = humanStore();
|
||||||
const { getCraneById, } = craneStore();
|
const { getCraneById } = craneStore();
|
||||||
const { getStorageUnitById } = storageUnitStore();
|
const { getStorageUnitById } = storageUnitStore();
|
||||||
const { isPlaying, setIsPlaying } = usePlayButtonStore();
|
const { isPlaying, setIsPlaying } = usePlayButtonStore();
|
||||||
const { simulationData, addData } = useSimulationManager();
|
const { simulationRecords, addSimulationRecord } = useSimulationManager();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
const COST_RATES: Record<SimulationUsageRecord["type"], number> = {
|
||||||
|
roboticArm: 5,
|
||||||
|
vehicle: 2,
|
||||||
|
transfer: 1,
|
||||||
|
storageUnit: 1,
|
||||||
|
crane: 6,
|
||||||
|
human: 4,
|
||||||
|
machine: 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate totals for one product
|
||||||
|
function calculateProductMetrics(product: ProductSimulation) {
|
||||||
|
let totalActiveTime = 0;
|
||||||
|
let totalIdleTime = 0;
|
||||||
|
let totalCost = 0;
|
||||||
|
|
||||||
|
product.data.forEach((record) => {
|
||||||
|
const resourceTime = record.activeTime + record.idleTime;
|
||||||
|
const costRate = COST_RATES[record.type] || 0;
|
||||||
|
|
||||||
|
totalActiveTime += record.activeTime;
|
||||||
|
totalIdleTime += record.idleTime;
|
||||||
|
totalCost += resourceTime * costRate;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
totalTime: totalActiveTime + totalIdleTime,
|
||||||
|
totalActiveTime,
|
||||||
|
totalIdleTime,
|
||||||
|
totalCost,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate totals for a version
|
||||||
|
function calculateVersionMetrics(version: VersionSimulation) {
|
||||||
|
return version.products.reduce(
|
||||||
|
(acc, product) => {
|
||||||
|
const metrics = calculateProductMetrics(product);
|
||||||
|
|
||||||
|
acc.totalTime += metrics.totalTime;
|
||||||
|
acc.totalActiveTime += metrics.totalActiveTime;
|
||||||
|
acc.totalIdleTime += metrics.totalIdleTime;
|
||||||
|
acc.totalCost += metrics.totalCost;
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{ totalTime: 0, totalActiveTime: 0, totalIdleTime: 0, totalCost: 0 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Efficiency score (compare across versions)
|
||||||
|
function calculateEfficiencyScores(versions: VersionSimulation[]) {
|
||||||
|
const versionMetrics = versions.map((v) => ({
|
||||||
|
versionId: v.versionId,
|
||||||
|
...calculateVersionMetrics(v),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const minTime = Math.min(...versionMetrics.map((m) => m.totalTime));
|
||||||
|
const minCost = Math.min(...versionMetrics.map((m) => m.totalCost));
|
||||||
|
|
||||||
|
return versionMetrics.map((m) => {
|
||||||
|
const timeFactor = minTime / m.totalTime;
|
||||||
|
const costFactor = minCost / m.totalCost;
|
||||||
|
|
||||||
|
const efficiencyScore = 0.5 * timeFactor + 0.5 * costFactor;
|
||||||
|
|
||||||
|
return { ...m, efficiencyScore };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('simulationRecords: ', simulationRecords);
|
||||||
|
if (!projectId || !selectedVersion || !selectedProduct.productUuid || simulationRecords.length === 0) return;
|
||||||
|
|
||||||
|
const project = simulationRecords[0];
|
||||||
|
|
||||||
|
if (project) {
|
||||||
|
const scores = calculateEfficiencyScores(project.versions);
|
||||||
|
console.log("Version Comparisons:", scores);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveSimulationData({
|
||||||
|
key: selectedProduct.productUuid,
|
||||||
|
data: simulationRecords,
|
||||||
|
});
|
||||||
|
}, [simulationRecords]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const simData = getSimulationData({ key: selectedProduct.productUuid });
|
||||||
|
if (simData) {
|
||||||
|
useSimulationManager.getState().setSimulationRecords(JSON.parse(simData));
|
||||||
|
// Parse and set in the store
|
||||||
|
} else { }
|
||||||
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let checkTimer: ReturnType<typeof setTimeout>;
|
let checkTimer: ReturnType<typeof setTimeout>;
|
||||||
@@ -67,41 +169,43 @@ const SimulationHandler = () => {
|
|||||||
let hasActiveEntity = false;
|
let hasActiveEntity = false;
|
||||||
|
|
||||||
if (currentProduct) {
|
if (currentProduct) {
|
||||||
const executionSequences = await determineExecutionMachineSequences([currentProduct]);
|
const executionSequences = await determineExecutionMachineSequences([
|
||||||
|
currentProduct,
|
||||||
|
]);
|
||||||
if (executionSequences?.length > 0) {
|
if (executionSequences?.length > 0) {
|
||||||
executionSequences.forEach(sequence => {
|
executionSequences.forEach((sequence) => {
|
||||||
sequence.forEach(entity => {
|
sequence.forEach((entity) => {
|
||||||
if (entity.type === 'roboticArm') {
|
if (entity.type === "roboticArm") {
|
||||||
const roboticArm = getArmBotById(entity.modelUuid);
|
const roboticArm = getArmBotById(entity.modelUuid);
|
||||||
if (roboticArm?.isActive) {
|
if (roboticArm?.isActive) {
|
||||||
hasActiveEntity = true;
|
hasActiveEntity = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (entity.type === 'vehicle') {
|
if (entity.type === "vehicle") {
|
||||||
const vehicle = getVehicleById(entity.modelUuid);
|
const vehicle = getVehicleById(entity.modelUuid);
|
||||||
if (vehicle?.isActive) {
|
if (vehicle?.isActive) {
|
||||||
hasActiveEntity = true;
|
hasActiveEntity = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (entity.type === 'machine') {
|
if (entity.type === "machine") {
|
||||||
const machine = getMachineById(entity.modelUuid);
|
const machine = getMachineById(entity.modelUuid);
|
||||||
if (machine?.isActive) {
|
if (machine?.isActive) {
|
||||||
hasActiveEntity = true;
|
hasActiveEntity = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (entity.type === 'human') {
|
if (entity.type === "human") {
|
||||||
const human = getHumanById(entity.modelUuid);
|
const human = getHumanById(entity.modelUuid);
|
||||||
if (human?.isActive) {
|
if (human?.isActive) {
|
||||||
hasActiveEntity = true;
|
hasActiveEntity = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (entity.type === 'crane') {
|
if (entity.type === "crane") {
|
||||||
const crane = getCraneById(entity.modelUuid);
|
const crane = getCraneById(entity.modelUuid);
|
||||||
if (crane?.isActive) {
|
if (crane?.isActive) {
|
||||||
hasActiveEntity = true;
|
hasActiveEntity = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (entity.type === 'storageUnit') {
|
if (entity.type === "storageUnit") {
|
||||||
const storageUnit = getStorageUnitById(entity.modelUuid);
|
const storageUnit = getStorageUnitById(entity.modelUuid);
|
||||||
if (storageUnit?.isActive) {
|
if (storageUnit?.isActive) {
|
||||||
hasActiveEntity = true;
|
hasActiveEntity = true;
|
||||||
@@ -117,8 +221,11 @@ const SimulationHandler = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (materials.length === 0 && materialHistory.length >= 0 && !hasActiveEntity) {
|
if (
|
||||||
|
materials.length === 0 &&
|
||||||
|
materialHistory.length >= 0 &&
|
||||||
|
!hasActiveEntity
|
||||||
|
) {
|
||||||
if (executionSequences?.length > 0) {
|
if (executionSequences?.length > 0) {
|
||||||
executionSequences.forEach((sequence) => {
|
executionSequences.forEach((sequence) => {
|
||||||
sequence.forEach((entity) => {
|
sequence.forEach((entity) => {
|
||||||
@@ -138,7 +245,7 @@ const SimulationHandler = () => {
|
|||||||
const obj = getter(entity.modelUuid);
|
const obj = getter(entity.modelUuid);
|
||||||
if (!obj) return; // skip if not found
|
if (!obj) return; // skip if not found
|
||||||
|
|
||||||
addData(
|
addSimulationRecord(
|
||||||
projectId,
|
projectId,
|
||||||
selectedVersion?.versionId || "",
|
selectedVersion?.versionId || "",
|
||||||
selectedProduct?.productUuid,
|
selectedProduct?.productUuid,
|
||||||
@@ -154,6 +261,7 @@ const SimulationHandler = () => {
|
|||||||
| "crane"
|
| "crane"
|
||||||
| "storageUnit"
|
| "storageUnit"
|
||||||
| "transfer",
|
| "transfer",
|
||||||
|
assetId: entity.modelUuid,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -173,9 +281,18 @@ const SimulationHandler = () => {
|
|||||||
return () => {
|
return () => {
|
||||||
if (checkTimer) clearTimeout(checkTimer);
|
if (checkTimer) clearTimeout(checkTimer);
|
||||||
};
|
};
|
||||||
}, [materials, materialHistory, selectedVersion, selectedProduct?.productUuid, isPlaying, armBots, vehicles, machines]);
|
}, [
|
||||||
|
materials,
|
||||||
|
materialHistory,
|
||||||
|
selectedVersion,
|
||||||
|
selectedProduct?.productUuid,
|
||||||
|
isPlaying,
|
||||||
|
armBots,
|
||||||
|
vehicles,
|
||||||
|
machines,
|
||||||
|
]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
};
|
||||||
|
|
||||||
export default SimulationHandler;
|
export default SimulationHandler;
|
||||||
|
|||||||
@@ -1,19 +1,11 @@
|
|||||||
|
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
|
|
||||||
|
|
||||||
interface SimulationUsageRecord {
|
interface SimulationUsageRecord {
|
||||||
activeTime: number;
|
activeTime: number;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
idleTime: number;
|
idleTime: number;
|
||||||
type:
|
type: "roboticArm" | "vehicle" | "transfer" | "storageUnit" | "crane" | "human" | "machine";
|
||||||
| "roboticArm"
|
assetId: string;
|
||||||
| "vehicle"
|
|
||||||
| "transfer"
|
|
||||||
| "storageUnit"
|
|
||||||
| "crane"
|
|
||||||
| "human"
|
|
||||||
| "machine";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Product → holds multiple usage records
|
// Product → holds multiple usage records
|
||||||
@@ -36,28 +28,22 @@ interface ProjectSimulation {
|
|||||||
// or same file
|
// or same file
|
||||||
|
|
||||||
interface SimulationManagerStore {
|
interface SimulationManagerStore {
|
||||||
simulationData: ProjectSimulation[];
|
simulationRecords: ProjectSimulation[];
|
||||||
|
setSimulationRecords: (data: ProjectSimulation[]) => void;
|
||||||
|
addSimulationRecord: (projectId: string | undefined, versionId: string, productId: string, record: SimulationUsageRecord) => void;
|
||||||
|
|
||||||
addData: (
|
resetProductRecords: (projectId: string, versionId: string, productId: string) => void;
|
||||||
projectId: string | undefined,
|
getProjectById: (projectId: string | undefined) => ProjectSimulation | undefined;
|
||||||
versionId: string,
|
getVersionById: (projectId: string | undefined, versionId: string) => VersionSimulation | undefined;
|
||||||
productId: string,
|
getProductById: (projectId: string | undefined, versionId: string, productId: string) => ProductSimulation | undefined;
|
||||||
record: SimulationUsageRecord
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
resetProductData: (
|
|
||||||
projectId: string,
|
|
||||||
versionId: string,
|
|
||||||
productId: string
|
|
||||||
) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useSimulationManager = create<SimulationManagerStore>((set) => ({
|
export const useSimulationManager = create<SimulationManagerStore>((set, get) => ({
|
||||||
simulationData: [],
|
simulationRecords: [],
|
||||||
|
|
||||||
addData: (projectId, versionId, productId, record) =>
|
addSimulationRecord: (projectId, versionId, productId, record) =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const projects = state.simulationData.map((project) => {
|
const projects = state.simulationRecords.map((project) => {
|
||||||
if (project.projectId !== projectId) return project;
|
if (project.projectId !== projectId) return project;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -67,18 +53,14 @@ export const useSimulationManager = create<SimulationManagerStore>((set) => ({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...version,
|
...version,
|
||||||
products: version.products.map((product) =>
|
products: version.products.map((product) => (product.productId === productId ? { ...product, data: [...product.data, record] } : product)),
|
||||||
product.productId === productId
|
|
||||||
? { ...product, data: [...product.data, record] }
|
|
||||||
: product
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// If project doesn't exist, create it
|
// If project doesn't exist, create it
|
||||||
if (!state.simulationData.find((p) => p.projectId === projectId)) {
|
if (!state.simulationRecords.find((p) => p.projectId === projectId)) {
|
||||||
projects.push({
|
projects.push({
|
||||||
projectId,
|
projectId,
|
||||||
versions: [
|
versions: [
|
||||||
@@ -96,21 +78,19 @@ export const useSimulationManager = create<SimulationManagerStore>((set) => ({
|
|||||||
products: [{ productId, data: [record] }],
|
products: [{ productId, data: [record] }],
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const version = project.versions.find(
|
const version = project.versions.find((v) => v.versionId === versionId)!;
|
||||||
(v) => v.versionId === versionId
|
|
||||||
)!;
|
|
||||||
if (!version.products.find((p) => p.productId === productId)) {
|
if (!version.products.find((p) => p.productId === productId)) {
|
||||||
version.products.push({ productId, data: [record] });
|
version.products.push({ productId, data: [record] });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { simulationData: projects };
|
return { simulationRecords: projects };
|
||||||
}),
|
}),
|
||||||
|
|
||||||
resetProductData: (projectId, versionId, productId) =>
|
resetProductRecords: (projectId, versionId, productId) =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const projects = state.simulationData.map((project) => {
|
const projects = state.simulationRecords.map((project) => {
|
||||||
if (project.projectId !== projectId) return project;
|
if (project.projectId !== projectId) return project;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -120,17 +100,30 @@ export const useSimulationManager = create<SimulationManagerStore>((set) => ({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...version,
|
...version,
|
||||||
products: version.products.map((product) =>
|
products: version.products.map((product) => (product.productId === productId ? { ...product, data: [] } : product)),
|
||||||
product.productId === productId
|
|
||||||
? { ...product, data: [] }
|
|
||||||
: product
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return { simulationData: projects };
|
return { simulationRecords: projects };
|
||||||
}),
|
}),
|
||||||
|
setSimulationRecords: (data) => {
|
||||||
|
set({ simulationRecords: data });
|
||||||
|
},
|
||||||
|
getProjectById: (projectId: string | undefined) => {
|
||||||
|
return get().simulationRecords.find((p: ProjectSimulation) => p.projectId === projectId);
|
||||||
|
},
|
||||||
|
|
||||||
|
getVersionById: (projectId: string | undefined, versionId: string) => {
|
||||||
|
const project = get().simulationRecords.find((p: ProjectSimulation) => p.projectId === projectId);
|
||||||
|
return project?.versions.find((v: VersionSimulation) => v.versionId === versionId);
|
||||||
|
},
|
||||||
|
|
||||||
|
getProductById: (projectId: string | undefined, versionId: string, productId: string) => {
|
||||||
|
const project = get().simulationRecords.find((p: ProjectSimulation) => p.projectId === projectId);
|
||||||
|
const version = project?.versions.find((v: VersionSimulation) => v.versionId === versionId);
|
||||||
|
return version?.products.find((p: ProductSimulation) => p.productId === productId);
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
///////////////////////////
|
///////////////////////////
|
||||||
|
|||||||
@@ -305,7 +305,7 @@
|
|||||||
background-color: #b7b7c6;
|
background-color: #b7b7c6;
|
||||||
|
|
||||||
// Custom polygon shape (adjust if needed)
|
// Custom polygon shape (adjust if needed)
|
||||||
clipPath: polygon(96% 52%,
|
clip-path: polygon(96% 52%,
|
||||||
96% 54%,
|
96% 54%,
|
||||||
45% 53%,
|
45% 53%,
|
||||||
3% 100%,
|
3% 100%,
|
||||||
|
|||||||
Reference in New Issue
Block a user