Merge remote-tracking branch 'origin/v3-refactor' into v3

This commit is contained in:
Jerald-Golden-B 2025-06-12 12:08:45 +05:30
commit da0961d50e
20 changed files with 262 additions and 152 deletions

View File

@ -1292,8 +1292,8 @@ export const PerformanceIcon = () => {
<path
d="M11.1484 1.16797C16.2895 1.16797 20.4921 5.3714 20.4922 10.5117C20.4922 12.7821 19.6669 14.8349 18.3467 16.4316L18.1807 16.2656C19.3378 14.8012 20.1179 12.9631 20.2236 10.9746L20.2354 10.5107C20.2364 9.46665 20.0573 8.43143 19.707 7.4502L19.5469 7.03223C19.1476 6.06682 18.5848 5.17876 17.8848 4.40625L17.5771 4.08301C16.733 3.23884 15.7302 2.56951 14.627 2.11328C13.524 1.65716 12.342 1.42257 11.1484 1.42383C10.1041 1.42277 9.06837 1.60175 8.08691 1.95215L7.66992 2.11328C6.70451 2.51257 5.81644 3.07536 5.04395 3.77539L4.71973 4.08398C3.98113 4.8228 3.37584 5.68237 2.93066 6.625L2.75 7.03418C2.3509 7.99977 2.12214 9.02598 2.07227 10.0674L2.06152 10.5127C2.06152 12.7338 2.80096 14.7019 4.10059 16.2803L3.93652 16.4443C2.58335 14.8587 1.80469 12.8058 1.80469 10.5117C1.80479 5.37146 6.00742 1.16807 11.1484 1.16797ZM10.8008 11.2383L10.3887 10.8076L13.8027 7.81543L10.8008 11.2383Z"
stroke="url(#paint0_linear_1736_988)"
stroke-width="1.80917"
stroke-linecap="round"
strokeWidth="1.80917"
strokeLinecap="round"
/>
<defs>
<linearGradient
@ -1304,8 +1304,8 @@ export const PerformanceIcon = () => {
y2="17.742"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#6F42C1" />
<stop offset="1" stop-color="#B392F0" />
<stop stopColor="#6F42C1" />
<stop offset="1" stopColor="#B392F0" />
</linearGradient>
</defs>
</svg>
@ -1328,9 +1328,9 @@ export const GreenTickIcon = () => {
<path
d="M4.85742 7.20505L6.91318 9.25578L10.3394 5.83789"
stroke="white"
stroke-width="2.45534"
stroke-linecap="round"
stroke-linejoin="round"
strokeWidth="2.45534"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);

View File

@ -1,12 +1,13 @@
import { useProductContext } from '../../../modules/simulation/products/productContext'
import RegularDropDown from '../../ui/inputs/RegularDropDown';
import { useProductStore } from '../../../store/simulation/useProductStore';
import { useLoadingProgress, useSaveVersion } from '../../../store/builder/store';
import { useCompareProductDataStore, useLoadingProgress, useSaveVersion } from '../../../store/builder/store';
import useModuleStore from '../../../store/useModuleStore';
import CompareLayOut from '../../ui/compareVersion/CompareLayOut';
import ComparisonResult from '../../ui/compareVersion/ComparisonResult';
import { useComparisonProduct, useMainProduct } from '../../../store/simulation/useSimulationStore';
import { usePauseButtonStore, usePlayButtonStore } from '../../../store/usePlayButtonStore';
import { useEffect, useState } from 'react';
function ComparisonScene() {
const { isPlaying, setIsPlaying } = usePlayButtonStore();
@ -19,6 +20,8 @@ function ComparisonScene() {
const { mainProduct } = useMainProduct();
const { setIsPaused } = usePauseButtonStore();
const { loadingProgress } = useLoadingProgress();
const { compareProductsData, setCompareProductsData } = useCompareProductDataStore();
const [shouldShowComparisonResult, setShouldShowComparisonResult] = useState(false);
const handleSelectLayout = (option: string) => {
const product = products.find((product) => product.productName === option);
@ -26,6 +29,24 @@ function ComparisonScene() {
setComparisonProduct(product.productUuid, product.productName);
}
};
useEffect(() => {
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);
if (hasMain && hasComparison && mainProduct.productUuid !== comparisonProduct.productUuid) {
setShouldShowComparisonResult(true);
} else {
setShouldShowComparisonResult(false);
}
} else {
setShouldShowComparisonResult(false);
}
}, [compareProductsData, mainProduct, comparisonProduct]);
return (
<>
{isVersionSaved && activeModule === "simulation" && selectedProduct && (
@ -41,7 +62,8 @@ function ComparisonScene() {
</div>
}
<CompareLayOut />
{(comparisonProduct && mainProduct && !loadingProgress) && <ComparisonResult />}
{(shouldShowComparisonResult && !loadingProgress) && <ComparisonResult />}
</>
)}
</>

View File

@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { AIIcon } from "../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
import { AnalysisPresetsType } from "../../../../types/analysis";
@ -19,55 +19,66 @@ const Analysis: React.FC = () => {
// { type: "default", inputs: { label: "Machine uptime", activeOption: "%" } },
],
"Production capacity": [
{ type: "range", inputs: { label: "Shift length", activeOption: "hr" } },
{ type: "default", inputs: { label: "Shifts / day", activeOption: "unit" } },
{ type: "default", inputs: { label: "Working days / year", activeOption: "days" } },
{ type: "default", inputs: { label: "Yield rate", activeOption: "%" } },
{ type: "range", inputs: { label: "Shift length", activeOption: "hr", defaultValue: 6 } },
{ type: "default", inputs: { label: "Shifts / day", activeOption: "unit", defaultValue: 2 } },
{ type: "default", inputs: { label: "Working days / year", activeOption: "days", defaultValue: 300 } },
{ type: "default", inputs: { label: "Yield rate", activeOption: "%", defaultValue: 92 } },
],
ROI: [
{
type: "default",
inputs: { label: "Selling price", activeOption: "INR" },
inputs: { label: "Selling price", activeOption: "INR", defaultValue: 800 },
},
{
type: "default",
inputs: { label: "Material cost", activeOption: "INR" },
inputs: { label: "Material cost", activeOption: "INR", defaultValue: 300 },
},
{
type: "default",
inputs: { label: "Labor Cost", activeOption: "INR" },
inputs: { label: "Labor Cost", activeOption: "INR", defaultValue: 150 },
},
{
type: "default",
inputs: { label: "Maintenance cost", activeOption: "INR" },
inputs: { label: "Maintenance cost", activeOption: "INR", defaultValue: 1200 },
},
{
type: "default",
inputs: { label: "Electricity cost", activeOption: "INR" },
inputs: { label: "Electricity cost", activeOption: "INR", defaultValue: 840 },
},
{
type: "default",
inputs: { label: "Fixed costs", activeOption: "INR" },
inputs: { label: "Fixed costs", activeOption: "INR", defaultValue: 1250 },
},
{
type: "default",
inputs: { label: "Initial Investment", activeOption: "INR" },
inputs: { label: "Initial Investment", activeOption: "INR", defaultValue: 1500000 },
},
{
type: "default",
inputs: { label: "Salvage value", activeOption: "Hrs" },
inputs: { label: "Salvage value", activeOption: "Day", defaultValue: 565 },
},
{
type: "default",
inputs: { label: "Production period", activeOption: "yrs" },
inputs: { label: "Production period", activeOption: "yrs", defaultValue: 5 },
},
{
type: "default",
inputs: { label: "Tax rate", activeOption: "%" },
inputs: { label: "Tax rate", activeOption: "%", defaultValue: 30 },
},
],
};
useEffect(() => {
Object.values(AnalysisPresets).forEach((category) => {
category.forEach((item) => {
const { label, defaultValue } = item.inputs;
if (defaultValue !== undefined) {
updateInputValue(label, defaultValue.toString());
}
});
});
}, []);
const { inputValues, setInputValues, updateInputValue } = useInputValues();
return (

View File

@ -11,6 +11,7 @@ interface InputRendererProps {
}
const RenderAnalysisInputs: React.FC<InputRendererProps> = ({ keyName, presets, inputValues, onInputChange }) => {
return (
<div key={`main-${keyName}`} className="analysis-inputs">
{presets.map((preset, index) => {
@ -19,7 +20,7 @@ const RenderAnalysisInputs: React.FC<InputRendererProps> = ({ keyName, presets,i
<InputWithDropDown
key={index}
label={preset.inputs.label}
value={inputValues[preset.inputs.label] || ""}
value={preset.inputs.defaultValue?.toString() || inputValues[preset.inputs.label] || ""}
activeOption={preset.inputs.activeOption}
onChange={(newValue) => onInputChange(preset.inputs.label, newValue)}
/>
@ -32,7 +33,7 @@ const RenderAnalysisInputs: React.FC<InputRendererProps> = ({ keyName, presets,i
label={preset.inputs.label}
min={0}
max={8}
value={5}
value={Number(preset.inputs.defaultValue) || Number(inputValues[preset.inputs.label]) || 5}
/>
);
}

View File

@ -2,7 +2,7 @@ import React, { useEffect, useRef, useState } from "react";
import { AddIcon, ArrowIcon, RemoveIcon, ResizeHeightIcon, } from "../../../icons/ExportCommonIcons";
import RenameInput from "../../../ui/inputs/RenameInput";
import { handleResize } from "../../../../functions/handleResizePannel";
import { useSelectedAsset } from "../../../../store/simulation/useSimulationStore";
import { useMainProduct, useSelectedAsset } from "../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../store/simulation/useProductStore";
import { generateUUID } from "three/src/math/MathUtils";
import RenderOverlay from "../../../templates/Overlay";
@ -48,6 +48,7 @@ const Simulations: React.FC = () => {
const [processes, setProcesses] = useState<Event[][]>();
const { setToggleUI } = useToggleStore();
const { projectId } = useParams();
const { setMainProduct } = useMainProduct();
const { comparePopUp, setComparePopUp } = useCompareStore();
const { setIsVersionSaved } = useSaveVersion();
@ -85,8 +86,13 @@ const Simulations: React.FC = () => {
updatedProducts[newSelectedIndex].productUuid,
updatedProducts[newSelectedIndex].productName
);
setMainProduct(
updatedProducts[newSelectedIndex].productUuid,
updatedProducts[newSelectedIndex].productName
);
} else {
setSelectedProduct("", "");
setMainProduct("", "");
}
}
@ -102,6 +108,7 @@ const Simulations: React.FC = () => {
renameProductApi({ productName: newName, productUuid, projectId: projectId || '' });
if (selectedProduct.productUuid === productUuid) {
setSelectedProduct(productUuid, newName);
setMainProduct(productUuid, newName);
}
};
@ -172,9 +179,10 @@ const Simulations: React.FC = () => {
{/* eslint-disable-next-line */}
<div
className="value"
onClick={() =>
onClick={() => {
setSelectedProduct(product.productUuid, product.productName)
}
setMainProduct(product.productUuid, product.productName)
}}
>
<input
type="radio"

View File

@ -121,8 +121,9 @@ const ROISummary = ({
<SonarCrownIcon />
<div className="icon"></div>
<div className="info">
<span> {roiSummary.roiPercentage}%</span> ROI with payback
in just <span>{roiSummary.paybackPeriod}</span> months
<span>{roiSummary.roiPercentage}% </span>
ROI
<span></span>
</div>
</div>
<div className="roi-details">

View File

@ -26,6 +26,7 @@ const ProductionCapacity = ({
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
console.log('throughputData: ', throughputData);
if (throughputData > 0) {
setIsLoading(false);
} else {

View File

@ -2,8 +2,13 @@ import React, { useMemo } from "react";
import PerformanceResult from "./result-card/PerformanceResult";
import EnergyUsage from "./result-card/EnergyUsage";
import { Bar, Line, Pie } from "react-chartjs-2";
import { useCompareProductDataStore } from "../../../store/builder/store";
import { useComparisonProduct, useMainProduct } from "../../../store/simulation/useSimulationStore";
const ComparisonResult = () => {
const { compareProductsData, setCompareProductsData } = useCompareProductDataStore();
const { comparisonProduct, setComparisonProduct } = useComparisonProduct();
const { mainProduct } = useMainProduct();
const options = useMemo(
() => ({
responsive: true,
@ -150,7 +155,7 @@ const ComparisonResult = () => {
</div>
<div className="overallScrapRate comparisionCard">
<div className="overallScrapRate-header">Overall Scrap Rate</div>
<div className="overallScrapRate-header">Production Capacity</div>
<div className="overallScrapRate-wrapper">
<div className="overallScrapRate-value">
<div className="overallScrapRate-label">Layout 1</div>

View File

@ -146,9 +146,6 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
newName,
projectId
);
// console.log("response: ", response);
console.log(' zoneAssetId.id,: ', zoneAssetId.id,);
setName(zoneAssetId.id, response.modelName);
}
}

View File

@ -187,7 +187,7 @@ const SimulationPlayer: React.FC = () => {
<div className="icon">
<HourlySimulationIcon />
</div>
<div className="label">ThroughPut Data</div>
<div className="label">ThroughPut</div>
</div>
<div className="progress-wrapper">
<div
@ -202,7 +202,7 @@ const SimulationPlayer: React.FC = () => {
<div className="icon">
<DailyProductionIcon />
</div>
<div className="label">Daily Production</div>
<div className="label">Production Capacity</div>
</div>
<div className="progress-wrapper">
<div
@ -217,7 +217,7 @@ const SimulationPlayer: React.FC = () => {
<div className="icon">
<MonthlyROI />
</div>
<div className="label">Monthly ROI</div>
<div className="label">ROI</div>
</div>
<div className="progress-wrapper">
<div

View File

@ -1,9 +1,10 @@
import React, { useEffect, useState } from 'react'
import { useInputValues, useProductionCapacityData, useROISummaryData } from '../../../../store/builder/store';
import React, { useEffect } from 'react'
import { CompareProduct, useCompareProductDataStore, useInputValues, useMachineDowntime, useMachineUptime, useProductionCapacityData, useROISummaryData, useThroughPutData } from '../../../../store/builder/store';
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
import { useProductContext } from '../../products/productContext';
import { useProductStore } from '../../../../store/simulation/useProductStore';
export default function ROIData() {
const { selectedProductStore } = useProductContext();
const { inputValues } = useInputValues();
@ -12,10 +13,13 @@ export default function ROIData() {
const { isPlaying } = usePlayButtonStore();
const { setRoiSummaryData } = useROISummaryData();
const { products, getProductById } = useProductStore();
const [compareProducts, setCompareProducts] = useState<any[]>([]);
const { compareProductsData, setCompareProductsData } = useCompareProductDataStore();
const { machineActiveTime, setMachineActiveTime } = useMachineUptime();
const { machineIdleTime, setMachineIdleTime } = useMachineDowntime();
const { throughputData } = useThroughPutData()
useEffect(() => {
if (!isPlaying) {
if (isPlaying) return;
setRoiSummaryData({
productName: "",
roiPercentage: 0,
@ -24,16 +28,15 @@ export default function ROIData() {
revenueGenerated: 0,
netProfit: 0,
netLoss: 0,
})
return;
}
if (inputValues === undefined) return;
});
}, [isPlaying]);
useEffect(() => {
if (inputValues === undefined || !isPlaying) return;
const electricityCost = parseFloat(inputValues["Electricity cost"]);
const fixedCost = parseFloat(inputValues["Fixed costs"]);
const laborCost = parseFloat(inputValues["Labor Cost"]);
const maintenanceCost = parseFloat(inputValues["Maintenance cost"]); // Remove space typ
const maintenanceCost = parseFloat(inputValues["Maintenance cost"]);
const materialCost = parseFloat(inputValues["Material cost"]);
const productionPeriod = parseFloat(inputValues["Production period"]);
const salvageValue = parseFloat(inputValues["Salvage value"]);
@ -46,41 +49,26 @@ export default function ROIData() {
if (!isNaN(electricityCost) && !isNaN(fixedCost) && !isNaN(laborCost) && !isNaN(maintenanceCost) &&
!isNaN(materialCost) && !isNaN(productionPeriod) && !isNaN(salvageValue) && !isNaN(sellingPrice) &&
!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && productionCapacityData > 0) {
console.log('productionCapacityData: ', productionCapacityData);
const totalHoursPerYear = shiftLength * shiftsPerDay * workingDaysPerYear;
// Total good units produced per year
const annualProductionUnits = productionCapacityData * totalHoursPerYear;
// Revenue for a year
const annualRevenue = annualProductionUnits * sellingPrice;
// Costs
const totalMaterialCost = annualProductionUnits * materialCost;
const totalLaborCost = laborCost * totalHoursPerYear;
const totalEnergyCost = electricityCost * totalHoursPerYear;
const totalMaintenanceCost = maintenanceCost + fixedCost;
const totalAnnualCost = totalMaterialCost + totalLaborCost + totalEnergyCost + totalMaintenanceCost;
// Annual Profit
const annualProfit = annualRevenue - totalAnnualCost;
// Net Profit over production period
const netProfit = annualProfit * productionPeriod;
// ROI
const roiPercentage = ((netProfit + salvageValue - initialInvestment) / initialInvestment) * 100;
// Payback Period
const roiPercentage = ((annualProfit + salvageValue - initialInvestment) / initialInvestment) * 100;
const paybackPeriod = initialInvestment / (annualProfit || 1); // Avoid division by 0
//
//
//
//
//
//
//
//
setRoiSummaryData({
productName: selectedProduct.productName,
roiPercentage: parseFloat((roiPercentage / 100).toFixed(2)), // normalized to 0.x format
roiPercentage: parseFloat((roiPercentage / 100).toFixed(2)),
paybackPeriod: parseFloat(paybackPeriod.toFixed(2)),
totalCost: parseFloat(totalAnnualCost.toFixed(2)),
revenueGenerated: parseFloat(annualRevenue.toFixed(2)),
@ -89,10 +77,7 @@ export default function ROIData() {
});
const productCount = 1000;
// Cost per unit (based on full annual cost)
const costPerUnit = totalAnnualCost / annualProductionUnits;
const costForTargetUnits = productCount * costPerUnit;
const revenueForTargetUnits = productCount * sellingPrice;
const profitForTargetUnits = revenueForTargetUnits - costForTargetUnits;
@ -100,55 +85,46 @@ export default function ROIData() {
const netProfitForTarget = profitForTargetUnits > 0 ? profitForTargetUnits : 0;
const netLossForTarget = profitForTargetUnits < 0 ? -profitForTargetUnits : 0;
//
//
//
//
//
//
const productData = getProductById(selectedProduct.productUuid);
setCompareProducts(prev => {
const newData = {
productUuid: productData?.productUuid,
productName: productData?.productName,
costPerUnit: parseFloat(costPerUnit.toFixed(2)),
workingDaysPerYear: parseFloat(workingDaysPerYear.toFixed(2)),
shiftLength: parseFloat(shiftLength.toFixed(2)),
shiftsPerDay: parseFloat(shiftsPerDay.toFixed(2)),
const prev = useCompareProductDataStore.getState().compareProductsData;
const newData: CompareProduct = {
productUuid: productData?.productUuid ?? '',
productName: productData?.productName ?? '',
simulationData: {
// costPerUnit: parseFloat(costPerUnit.toFixed(2)),
// workingDaysPerYear: parseFloat(workingDaysPerYear.toFixed(2)),
// shiftLength: parseFloat(shiftLength.toFixed(2)),
// shiftsPerDay: parseFloat(shiftsPerDay.toFixed(2)),
roiPercentage: parseFloat((roiPercentage / 100).toFixed(2)),
paybackPeriod: parseFloat(paybackPeriod.toFixed(2)),
totalCost: parseFloat(totalAnnualCost.toFixed(2)),
revenueGenerated: parseFloat(annualRevenue.toFixed(2)),
// paybackPeriod: parseFloat(paybackPeriod.toFixed(2)),
// totalCost: parseFloat(totalAnnualCost.toFixed(2)),
// revenueGenerated: parseFloat(annualRevenue.toFixed(2)),
netProfit: netProfit > 0 ? parseFloat(netProfit.toFixed(2)) : 0,
netLoss: netProfit < 0 ? parseFloat((-netProfit).toFixed(2)) : 0
// netLoss: netProfit < 0 ? parseFloat((-netProfit).toFixed(2)) : 0,
machineIdleTime: parseFloat(machineIdleTime.toFixed(2)),
machineActiveTime: parseFloat(machineActiveTime.toFixed(2)),
throughputData: throughputData,
}
};
const existingIndex = prev.findIndex(
item => item.productUuid === productData?.productUuid
const existingIndex = prev.findIndex((item: CompareProduct) =>
item.productUuid === productData?.productUuid
);
if (existingIndex !== -1) {
// Replace the existing item
const updated = [...prev];
updated[existingIndex] = newData;
return updated;
setCompareProductsData(updated);
} else {
// Add as new item
return [...prev, newData];
setCompareProductsData([...prev, newData]);
}
});
// console.log('compareProducts: ', compareProducts);
}
}, [inputValues, productionCapacityData]);
}, [inputValues, productionCapacityData, selectedProduct?.productUuid, isPlaying]);
return (
<></>
)
useEffect(() => {
console.log('compareProductsData: ', compareProductsData);
}, [compareProductsData])
return null;
}

View File

@ -1,27 +1,39 @@
import React, { useEffect } from 'react'
import { useInputValues, useProductionCapacityData, useThroughPutData } from '../../../../store/builder/store'
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
import { useProductContext } from '../../products/productContext';
export default function ProductionCapacityData() {
const { throughputData } = useThroughPutData()
const { productionCapacityData, setProductionCapacityData } = useProductionCapacityData()
const { inputValues } = useInputValues();
const { isPlaying } = usePlayButtonStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
useEffect(() => {
if (!isPlaying) {
console.log('isPlaying: ', isPlaying);
setProductionCapacityData(0);
return;
}
if (!inputValues || throughputData === undefined) return;
}, [isPlaying]);
useEffect(() => {
if (!inputValues || throughputData === undefined || !isPlaying) return;
console.log('throughputData: ', throughputData);
const shiftLength = parseFloat(inputValues["Shift length"]);
console.log('shiftLength: ', shiftLength);
const shiftsPerDay = parseFloat(inputValues["Shifts / day"]);
const workingDaysPerYear = parseFloat(inputValues["Working days / year"]);
const yieldRate = parseFloat(inputValues["Yield rate"]);
if (!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) &&
!isNaN(yieldRate) && throughputData >= 0) {
!isNaN(yieldRate) && throughputData > 0) {
// Total units produced per day before yield
const dailyProduction = throughputData * shiftLength * shiftsPerDay;
@ -41,7 +53,7 @@ export default function ProductionCapacityData() {
// Set the final capacity (units/hour)
setProductionCapacityData(Number(productionPerHour.toFixed(2)));
}
}, [throughputData, inputValues]);
}, [throughputData, inputValues, isPlaying]);
return (
<></>

View File

@ -1,10 +1,11 @@
import { useEffect } from 'react';
import { useProductStore } from '../../../../store/simulation/useProductStore';
import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences';
import { useMachineCount, useMachineUptime, useMaterialCycle, useProcessBar, useThroughPutData } from '../../../../store/builder/store';
import { useMachineCount, useMachineDowntime, useMachineUptime, useMaterialCycle, useProcessBar, useThroughPutData } from '../../../../store/builder/store';
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
import { useSceneContext } from '../../../scene/sceneContext';
import { useProductContext } from '../../products/productContext';
import { set } from 'immer/dist/internal';
export default function ThroughPutData() {
const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore } = useSceneContext();
@ -19,6 +20,7 @@ export default function ThroughPutData() {
const { materialHistory, materials } = materialStore();
const { machineCount, setMachineCount } = useMachineCount();
const { machineActiveTime, setMachineActiveTime } = useMachineUptime();
const { machineIdleTime, setMachineIdleTime } = useMachineDowntime();
const { materialCycleTime, setMaterialCycleTime } = useMaterialCycle();
const { setProcessBar } = useProcessBar();
const { setThroughputData } = useThroughPutData()
@ -27,17 +29,24 @@ export default function ThroughPutData() {
// Setting machine count
let totalItems = 0;
let totalActiveTime = 0;
let totalIdleTime = 0
useEffect(() => {
if (!isPlaying) {
totalActiveTime = 0;
totalItems = 0;
totalIdleTime = 0;
setMachineCount(0);
setMachineActiveTime(0);
setMachineIdleTime(0);
setMaterialCycleTime(0);
setProcessBar([]);
setThroughputData(0);
return;
} else {
}
}, [isPlaying])
useEffect(() => {
if (isPlaying) {
let process: any = [];
const fetchProductSequenceData = async () => {
const productData = getProductById(selectedProduct.productUuid);
@ -53,6 +62,9 @@ export default function ThroughPutData() {
process.push({ modelid: arm.modelUuid, modelName: arm.modelName, activeTime: arm?.activeTime })
totalActiveTime += arm.activeTime;
}
if (arm.idleTime > 0) {
totalIdleTime += arm.idleTime;
}
});
} else if (item.type === "vehicle") {
vehicles.filter(vehicle => vehicle.modelUuid === item.modelUuid)
@ -62,6 +74,9 @@ export default function ThroughPutData() {
totalActiveTime += vehicle.activeTime;
}
if (vehicle.idleTime > 0) {
totalIdleTime += vehicle.idleTime;
}
});
} else if (item.type === "machine") {
machines.filter(machine => machine.modelUuid === item.modelUuid)
@ -70,6 +85,9 @@ export default function ThroughPutData() {
process.push({ modelid: machine.modelUuid, modelName: machine.modelName, activeTime: machine?.activeTime })
totalActiveTime += machine.activeTime;
}
if (machine.idleTime > 0) {
totalIdleTime += machine.idleTime;
}
});
} else if (item.type === "transfer") {
conveyors.filter(conveyor => conveyor.modelUuid === item.modelUuid)
@ -95,6 +113,7 @@ export default function ThroughPutData() {
setMachineCount(totalItems);
setMachineActiveTime(totalActiveTime);
setMachineIdleTime(totalIdleTime);
let arr = process.map((item: any) => ({
name: item.modelName,
completed: Math.round((item.activeTime / totalActiveTime) * 100)
@ -107,15 +126,15 @@ export default function ThroughPutData() {
fetchProductSequenceData();
}
// if (materialCycleTime <= 0) return
}, [products, selectedProduct, getProductById, setMachineCount, materialCycleTime, armBots, vehicles, machines]);
}, [products, selectedProduct?.productUuid, getProductById, setMachineCount, materialCycleTime, armBots, vehicles, machines]);
useEffect(() => {
let timeoutId: ReturnType<typeof setTimeout>;
async function getMachineActive() {
const productData = getProductById(selectedProduct.productUuid);
let anyArmActive;
let anyVehicleActive;
let anyMachineActive;
if (productData) {
const productSequenceData = await determineExecutionMachineSequences([productData]);
if (productSequenceData?.length > 0) {
@ -182,21 +201,24 @@ export default function ThroughPutData() {
}
}
if (isPlaying) {
setTimeout(() => {
timeoutId = setTimeout(() => {
getMachineActive();
}, 500)
}, 1500);
}
}, [armBots, materials, materialHistory, machines, vehicles, selectedProduct])
return () => {
if (timeoutId) clearTimeout(timeoutId);
};
}, [armBots, materials, materialHistory, machines, vehicles, selectedProduct?.productUuid])
useEffect(() => {
if (machineActiveTime > 0 && materialCycleTime > 0 && machineCount > 0) {
if (machineActiveTime > 0 && materialCycleTime > 0 && machineCount > 0 && isPlaying) {
const utilization = machineActiveTime / 3600; // Active time per hour
const unitsPerMachinePerHour = 3600 / materialCycleTime;
const throughput = unitsPerMachinePerHour * machineCount * utilization;
setThroughputData(Number(throughput.toFixed(2))); // Keep as number
//
}
}, [machineActiveTime, materialCycleTime, machineCount]);
}, [machineActiveTime, materialCycleTime, machineCount, selectedProduct?.productUuid, isPlaying]);
return (
<>

View File

@ -13,6 +13,7 @@ function Products() {
const { armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, layout } = useSceneContext();
const { products, getProductById, addProduct, setProducts } = useProductStore();
const { selectedProductStore } = useProductContext();
const { setMainProduct } = useMainProduct();
const { selectedProduct, setSelectedProduct } = selectedProductStore();
const { addVehicle, clearvehicles } = vehicleStore();
const { addArmBot, clearArmBots } = armBotStore();
@ -51,11 +52,13 @@ function Products() {
})
if (layout === 'Main Layout') {
setSelectedProduct(id, name);
setMainProduct(id, name);
}
} else {
setProducts(data);
if (layout === 'Main Layout') {
setSelectedProduct(data[0].productUuid, data[0].productName);
setMainProduct(data[0].productUuid, data[0].productName);
}
}
})

View File

@ -3,12 +3,13 @@ export const setFloorItemApi = async (
organization: string,
modelUuid?: string,
modelName?: string,
projectId?: string,
assetId?: string,
projectId?: string,
position?: Object,
rotation?: Object,
isLocked?: boolean,
isVisible?: boolean
isVisible?: boolean,
) => {
try {
const body: any = {
@ -22,7 +23,6 @@ export const setFloorItemApi = async (
isLocked,
isVisible,
};
const response = await fetch(`${url_Backend_dwinzo}/api/V1/setAsset`, {
method: "POST",
headers: {

View File

@ -546,6 +546,10 @@ export const useMachineUptime = create<any>((set: any) => ({
machineActiveTime: 0,
setMachineActiveTime: (x: any) => set({ machineActiveTime: x }),
}));
export const useMachineDowntime = create<any>((set: any) => ({
machineIdleTime: 0,
setMachineIdleTime: (x: any) => set({ machineIdleTime: x }),
}));
export const useMaterialCycle = create<any>((set: any) => ({
materialCycleTime: 0,
setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }),
@ -709,3 +713,30 @@ function getInitialViewSceneLabels(): boolean {
const saved = localStorage.getItem('viewSceneLabels');
return saved ? JSON.parse(saved) : false;
}
export interface CompareProduct {
productUuid: string;
productName: string;
simulationData: {
// costPerUnit: number;
// workingDaysPerYear: number;
// shiftLength: number;
// shiftsPerDay: number;
roiPercentage: number;
// paybackPeriod: number;
// totalCost: number;
// revenueGenerated: number;
netProfit: number;
// netLoss: number;
machineIdleTime: number;
machineActiveTime: number;
throughputData: number;
}
}
export const useCompareProductDataStore = create<{
compareProductsData: CompareProduct[];
setCompareProductsData: (x: CompareProduct[]) => void;
}>((set) => ({
compareProductsData: [],
setCompareProductsData: (x) => set({ compareProductsData: x }),
}));

View File

@ -88,6 +88,7 @@ export const createMaterialStore = () => {
clearMaterials: () => {
set((state) => {
state.materials = [];
state.materialHistory = [];
});
},

View File

@ -0,0 +1,18 @@
// store/simulation/useCompareProductDataStore.ts
import { create } from 'zustand';
interface CompareProduct {
productUuid: string;
productName: string;
costPerUnit: number;
workingDaysPerYear: number;
shiftLength: number;
shiftsPerDay: number;
roiPercentage: number;
paybackPeriod: number;
totalCost: number;
revenueGenerated: number;
netProfit: number;
netLoss: number;
}

View File

@ -657,7 +657,7 @@
path {
stroke: var(--text-button-color);
stroke-width: 1.3;
strokeWidth: 1.3;
}
}
}
@ -1021,7 +1021,7 @@
path {
stroke: var(--accent-color);
stroke-width: 1.5px;
strokeWidth: 1.5px;
}
&:hover {

View File

@ -5,6 +5,7 @@ type Preset = {
activeOption: string;
min?: number;
max?: number;
defaultValue?: string | number;
};
};