Enhance analysis components with input values integration and improve state management for production capacity and ROI calculations
This commit is contained in:
parent
d88e93395f
commit
28e11d04b4
|
@ -9,7 +9,7 @@ import {
|
|||
} from "chart.js";
|
||||
import { PowerIcon, ProductionCapacityIcon } from "../../icons/analysis";
|
||||
import SkeletonUI from "../../templates/SkeletonUI";
|
||||
import { useMachineUptime, useProductionCapacityData } from "../../../store/builder/store";
|
||||
import { useInputValues, useMachineUptime, useProductionCapacityData } from "../../../store/builder/store";
|
||||
|
||||
ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement);
|
||||
|
||||
|
@ -73,6 +73,7 @@ const ThroughputSummary: React.FC = () => {
|
|||
assetUsage: assetUsage,
|
||||
};
|
||||
|
||||
const { inputValues } = useInputValues();
|
||||
// Chart data configuration
|
||||
const chartData = {
|
||||
labels: throughputData.labels,
|
||||
|
@ -123,7 +124,7 @@ const ThroughputSummary: React.FC = () => {
|
|||
<div className="lineChart">
|
||||
<div className="assetUsage">
|
||||
<div className="key">Asset usage</div>
|
||||
<div className="value">{throughputData.assetUsage}%</div>
|
||||
<div className="value">{parseFloat(inputValues["Yield rate"])}%</div>
|
||||
</div>
|
||||
<Line data={chartData} options={chartOptions} />
|
||||
</div>
|
||||
|
|
|
@ -86,7 +86,6 @@ const ROISummary = ({
|
|||
|
||||
useEffect(() => {
|
||||
if (roiSummary && typeof roiSummary === "object") {
|
||||
console.log('roiSummary: ', roiSummary);
|
||||
setIsLoading(false); // Data loaded
|
||||
} else {
|
||||
setIsLoading(true); // Show skeleton while loading
|
||||
|
|
|
@ -31,12 +31,10 @@ const ProductionCapacity = ({
|
|||
|
||||
useEffect(() => {
|
||||
if (throughputData >= 0) {
|
||||
console.log('machineActiveTime: ', machineActiveTime);
|
||||
console.log('materialCycleTime: ', materialCycleTime);
|
||||
console.log('throughputData: ', throughputData);
|
||||
console.log('productionCapacityData: ', productionCapacityData);
|
||||
|
||||
|
||||
// console.log('machineActiveTime: ', machineActiveTime);
|
||||
// console.log('materialCycleTime: ', materialCycleTime);
|
||||
// console.log('throughputData: ', throughputData);
|
||||
// console.log('productionCapacityData: ', productionCapacityData);
|
||||
setIsLoading(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,28 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { useInputValues, useProductionCapacityData, useROISummaryData } from '../../../../store/builder/store';
|
||||
import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore';
|
||||
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
|
||||
|
||||
export default function ROIData() {
|
||||
const { inputValues } = useInputValues();
|
||||
const { productionCapacityData } = useProductionCapacityData()
|
||||
const { selectedProduct } = useSelectedProduct();
|
||||
|
||||
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { setRoiSummaryData } = useROISummaryData();
|
||||
useEffect(() => {
|
||||
if (!isPlaying) {
|
||||
setRoiSummaryData({
|
||||
productName: "",
|
||||
roiPercentage: 0,
|
||||
paybackPeriod: 0,
|
||||
totalCost: 0,
|
||||
revenueGenerated: 0,
|
||||
netProfit: 0,
|
||||
netLoss: 0,
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
if (inputValues === undefined) return;
|
||||
|
||||
const electricityCost = parseFloat(inputValues["Electricity cost"]);
|
||||
|
@ -29,69 +42,77 @@ export default function ROIData() {
|
|||
!isNaN(materialCost) && !isNaN(productionPeriod) && !isNaN(salvageValue) && !isNaN(sellingPrice) &&
|
||||
!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && productionCapacityData > 0) {
|
||||
|
||||
console.log('sellingPrice: ', sellingPrice);
|
||||
console.log('salvageValue: ', salvageValue);
|
||||
console.log('productionPeriod: ', productionPeriod);
|
||||
console.log('materialCost: ', materialCost);
|
||||
console.log('maintenanceCost: ', maintenanceCost);
|
||||
console.log('laborCost: ', laborCost);
|
||||
console.log('fixedCost: ', fixedCost);
|
||||
console.log('electricityCost: ', electricityCost);
|
||||
|
||||
|
||||
// Revenue
|
||||
const RevenueForYear = productionCapacityData * sellingPrice;
|
||||
console.log('RevenueForYear: ', RevenueForYear);
|
||||
|
||||
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;
|
||||
|
||||
let materialCount = 1200;
|
||||
const totalAnnualCost = totalMaterialCost + totalLaborCost + totalEnergyCost + totalMaintenanceCost;
|
||||
|
||||
//Material Cost
|
||||
// Annual Profit
|
||||
const annualProfit = annualRevenue - totalAnnualCost;
|
||||
console.log('annualProfit: ', annualProfit);
|
||||
|
||||
let MaterialCost = productionCapacityData * materialCost
|
||||
console.log('MaterialCost: ', MaterialCost);
|
||||
let LaborCost = laborCost * shiftLength * shiftsPerDay * workingDaysPerYear;
|
||||
console.log('LaborCost: ', LaborCost);
|
||||
let EnergyCost = electricityCost * shiftLength * shiftsPerDay * workingDaysPerYear;
|
||||
console.log('EnergyCost: ', EnergyCost);
|
||||
let MaintenceCost = maintenanceCost + fixedCost;
|
||||
console.log('MaintenceCost: ', MaintenceCost);
|
||||
|
||||
//Total Anuual Cost
|
||||
let TotalAnnualCost = (MaterialCost * materialCount) + LaborCost + EnergyCost + MaintenceCost;
|
||||
console.log('TotalAnnualCost: ', TotalAnnualCost);
|
||||
|
||||
|
||||
//Profit for Year
|
||||
let ProfitforYear = RevenueForYear - TotalAnnualCost;
|
||||
console.log('ProfitforYear: ', ProfitforYear);
|
||||
|
||||
//Net Profit
|
||||
let NetProfit = ProfitforYear * productionPeriod;
|
||||
console.log('NetProfit: ', NetProfit);
|
||||
|
||||
|
||||
//Final ROI
|
||||
const ROIData = ((NetProfit + salvageValue - initialInvestment) / TotalAnnualCost) * 100;
|
||||
console.log('ROIData: ', ROIData);
|
||||
// Net Profit over production period
|
||||
const netProfit = annualProfit * productionPeriod;
|
||||
|
||||
// ROI
|
||||
const roiPercentage = ((netProfit + salvageValue - initialInvestment) / initialInvestment) * 100;
|
||||
|
||||
// Payback Period
|
||||
const paybackPeriod = initialInvestment / ProfitforYear;
|
||||
const paybackPeriod = initialInvestment / (annualProfit || 1); // Avoid division by 0
|
||||
console.log('paybackPeriod: ', paybackPeriod);
|
||||
|
||||
// console.log("--- ROI Breakdown ---");
|
||||
// console.log("Annual Production Units:", annualProductionUnits.toFixed(2));
|
||||
// console.log("Annual Revenue:", annualRevenue.toFixed(2));
|
||||
// console.log("Total Annual Cost:", totalAnnualCost.toFixed(2));
|
||||
// console.log("Annual Profit:", annualProfit.toFixed(2));
|
||||
// console.log("Net Profit:", netProfit.toFixed(2));
|
||||
// console.log("ROI %:", roiPercentage.toFixed(2));
|
||||
// console.log("Payback Period (years):", paybackPeriod.toFixed(2));
|
||||
|
||||
setRoiSummaryData({
|
||||
productName: selectedProduct.productName,
|
||||
roiPercentage: parseFloat((ROIData / 100).toFixed(2)),
|
||||
roiPercentage: parseFloat((roiPercentage / 100).toFixed(2)), // normalized to 0.x format
|
||||
paybackPeriod: parseFloat(paybackPeriod.toFixed(2)),
|
||||
totalCost: TotalAnnualCost,
|
||||
revenueGenerated: RevenueForYear,
|
||||
netProfit: NetProfit > 0 ? NetProfit : 0,
|
||||
netLoss: NetProfit < 0 ? -NetProfit : 0
|
||||
totalCost: parseFloat(totalAnnualCost.toFixed(2)),
|
||||
revenueGenerated: parseFloat(annualRevenue.toFixed(2)),
|
||||
netProfit: netProfit > 0 ? parseFloat(netProfit.toFixed(2)) : 0,
|
||||
netLoss: netProfit < 0 ? -netProfit : 0
|
||||
});
|
||||
|
||||
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;
|
||||
|
||||
const netProfitForTarget = profitForTargetUnits > 0 ? profitForTargetUnits : 0;
|
||||
const netLossForTarget = profitForTargetUnits < 0 ? -profitForTargetUnits : 0;
|
||||
|
||||
// console.log("--- Fixed Product Count (" + productCount + ") ---");
|
||||
// console.log("Cost per Unit:", costPerUnit.toFixed(2));
|
||||
// console.log("Total Cost for " + productCount + " Units:", costForTargetUnits.toFixed(2));
|
||||
// console.log("Revenue for " + productCount + " Units:", revenueForTargetUnits.toFixed(2));
|
||||
// console.log("Profit:", netProfitForTarget.toFixed(2));
|
||||
// console.log("Loss:", netLossForTarget.toFixed(2));
|
||||
|
||||
}
|
||||
|
||||
}, [inputValues, productionCapacityData]);
|
||||
|
|
|
@ -1,37 +1,44 @@
|
|||
import React, { useEffect } from 'react'
|
||||
import { useInputValues, useProductionCapacityData, useThroughPutData } from '../../../../store/builder/store'
|
||||
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
|
||||
|
||||
export default function ProductionCapacityData() {
|
||||
const { throughputData } = useThroughPutData()
|
||||
const { productionCapacityData, setProductionCapacityData } = useProductionCapacityData()
|
||||
const { inputValues } = useInputValues();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (inputValues === undefined || throughputData === undefined) return;
|
||||
if (!isPlaying) {
|
||||
setProductionCapacityData(0);
|
||||
return;
|
||||
}
|
||||
if (!inputValues || throughputData === undefined) return;
|
||||
|
||||
const shiftLength = parseFloat(inputValues["Shift length"]);
|
||||
// console.log('shiftLength: ', shiftLength);
|
||||
const shiftsPerDay = parseFloat(inputValues["Shifts / day"]);
|
||||
// console.log('shiftsPerDay: ', shiftsPerDay);
|
||||
const workingDaysPerYear = parseFloat(inputValues["Working days / year"]);
|
||||
// console.log('workingDaysPerYear: ', workingDaysPerYear);
|
||||
const yieldRate = parseFloat(inputValues["Yield rate"]);
|
||||
// console.log('yieldRate: ', yieldRate);
|
||||
|
||||
|
||||
if (!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && !isNaN(yieldRate) && throughputData >= 0) {
|
||||
//Daily Output
|
||||
if (!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) &&
|
||||
!isNaN(yieldRate) && throughputData >= 0) {
|
||||
// Total units produced per day before yield
|
||||
const dailyProduction = throughputData * shiftLength * shiftsPerDay;
|
||||
console.log("DailyProduction: ", dailyProduction.toFixed(2));
|
||||
// Good units (after Yield)
|
||||
const afterYield = dailyProduction * (yieldRate / 100);
|
||||
console.log('afterYield: ', afterYield.toFixed(2));
|
||||
//Annual Output
|
||||
const annualProduction = afterYield * workingDaysPerYear;
|
||||
console.log('annualProduction: ', Number(annualProduction.toFixed(2)));
|
||||
//Production per Hour
|
||||
|
||||
|
||||
// Units after applying yield rate
|
||||
const goodUnitsPerDay = dailyProduction * (yieldRate / 100);
|
||||
|
||||
|
||||
// Annual output
|
||||
const annualProduction = goodUnitsPerDay * workingDaysPerYear;
|
||||
|
||||
|
||||
// Final production capacity per hour (after yield)
|
||||
const productionPerHour = throughputData * (yieldRate / 100);
|
||||
console.log('productionPerHour: ', productionPerHour);
|
||||
|
||||
|
||||
// Set the final capacity (units/hour)
|
||||
setProductionCapacityData(Number(productionPerHour.toFixed(2)));
|
||||
}
|
||||
}, [throughputData, inputValues]);
|
||||
|
|
|
@ -10,47 +10,53 @@ import { useConveyorStore } from '../../../../store/simulation/useConveyorStore'
|
|||
import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore';
|
||||
import { useMaterialStore } from '../../../../store/simulation/useMaterialStore';
|
||||
import { usePauseButtonStore, usePlayButtonStore } from '../../../../store/usePlayButtonStore';
|
||||
import { is, set } from 'immer/dist/internal';
|
||||
|
||||
export default function ThroughPutData() {
|
||||
const { selectedProduct } = useSelectedProduct();
|
||||
const { products, getProductById } = useProductStore();
|
||||
const { armBots, incrementActiveTime, incrementIdleTime } = useArmBotStore();
|
||||
const { armBots } = useArmBotStore();
|
||||
const { vehicles } = useVehicleStore();
|
||||
const { machines } = useMachineStore();
|
||||
const { conveyors } = useConveyorStore();
|
||||
const { storageUnits } = useStorageUnitStore();
|
||||
const { materialHistory } = useMaterialStore();
|
||||
|
||||
const { machineCount, setMachineCount } = useMachineCount();
|
||||
const { machineActiveTime, setMachineActiveTime } = useMachineUptime();
|
||||
|
||||
const { materialCycleTime, setMaterialCycleTime } = useMaterialCycle();
|
||||
const { processBar, setProcessBar } = useProcessBar();
|
||||
|
||||
// const [totalActiveTime, setTotalActiveTime] = useState(0);
|
||||
const { setThroughputData } = useThroughPutData() // <=== ADD THIS
|
||||
const { setProcessBar } = useProcessBar();
|
||||
const { setThroughputData } = useThroughPutData()
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
|
||||
// Setting machine count
|
||||
let totalItems = 0;
|
||||
let totalActiveTime = 0;
|
||||
useEffect(() => {
|
||||
if (materialCycleTime <= 0) return
|
||||
if (!isPlaying) {
|
||||
totalActiveTime = 0;
|
||||
totalItems = 0;
|
||||
setMachineCount(0);
|
||||
setMachineActiveTime(0);
|
||||
setMaterialCycleTime(0);
|
||||
setProcessBar([]);
|
||||
setThroughputData(0);
|
||||
return;
|
||||
} else {
|
||||
let process: any = [];
|
||||
const fetchProductSequenceData = async () => {
|
||||
const productData = getProductById(selectedProduct.productId);
|
||||
if (productData) {
|
||||
const productSequenceData = await determineExecutionMachineSequences([productData])
|
||||
if (productSequenceData?.length > 0) {
|
||||
let totalItems = 0;
|
||||
let totalActiveTime = 0;
|
||||
productSequenceData.forEach((sequence) => {
|
||||
sequence.forEach((item) => {
|
||||
|
||||
if (item.type === "roboticArm") {
|
||||
armBots.filter(arm => arm.modelUuid === item.modelUuid)
|
||||
.forEach(arm => {
|
||||
if (arm.activeTime >= 0) {
|
||||
process.push({ modelid: arm.modelUuid, modelName: arm.modelName, activeTime: arm?.activeTime })
|
||||
totalActiveTime += arm.activeTime;
|
||||
|
||||
}
|
||||
});
|
||||
} else if (item.type === "vehicle") {
|
||||
|
@ -87,6 +93,7 @@ export default function ThroughPutData() {
|
|||
});
|
||||
}
|
||||
});
|
||||
|
||||
totalItems += sequence.length;
|
||||
});
|
||||
|
||||
|
@ -97,14 +104,13 @@ export default function ThroughPutData() {
|
|||
completed: Math.round((item.activeTime / totalActiveTime) * 100)
|
||||
}));
|
||||
setProcessBar(arr);
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fetchProductSequenceData();
|
||||
}
|
||||
// if (materialCycleTime <= 0) return
|
||||
}, [products, selectedProduct, getProductById, setMachineCount, materialCycleTime, armBots, vehicles, machines]);
|
||||
|
||||
// Setting material cycle time
|
||||
|
@ -112,9 +118,7 @@ export default function ThroughPutData() {
|
|||
materialHistory.forEach((material) => {
|
||||
const start = material.material.startTime ?? 0;
|
||||
const end = material.material.endTime ?? 0;
|
||||
|
||||
if (start === 0 || end === 0) return;
|
||||
|
||||
const totalCycleTime = (end - start) / 1000; // Convert milliseconds to seconds
|
||||
setMaterialCycleTime(Number(totalCycleTime.toFixed(2))); // Set the material cycle time in the store
|
||||
});
|
||||
|
@ -124,26 +128,24 @@ export default function ThroughPutData() {
|
|||
|
||||
useEffect(() => {
|
||||
if (machineActiveTime > 0 && materialCycleTime > 0 && machineCount > 0) {
|
||||
const avgProcessTime = (machineActiveTime / materialCycleTime) * 100;
|
||||
const throughput = (3600 / materialCycleTime) * machineCount * (avgProcessTime / 100);
|
||||
setThroughputData(throughput.toFixed(2)); // Set the throughput data in the store
|
||||
|
||||
|
||||
console.log('---Throughput Results---');
|
||||
console.log('Total Active Time:', machineActiveTime);
|
||||
console.log('Material Cycle Time:', materialCycleTime);
|
||||
console.log('Machine Count:', machineCount);
|
||||
console.log('Average Process Time (%):', avgProcessTime);
|
||||
console.log('Calculated Throughput:', throughput);
|
||||
|
||||
|
||||
const utilization = machineActiveTime / 3600; // Active time per hour
|
||||
const unitsPerMachinePerHour = 3600 / materialCycleTime;
|
||||
const throughput = unitsPerMachinePerHour * machineCount * utilization;
|
||||
|
||||
setThroughputData(throughput.toFixed(2)); // Set throughput to state/store
|
||||
|
||||
// console.log('---Throughput Results---');
|
||||
// console.log('Machine Active Time (s):', machineActiveTime);
|
||||
// console.log('Material Cycle Time (s):', materialCycleTime);
|
||||
// console.log('Machine Count:', machineCount);
|
||||
// console.log('Utilization:', utilization);
|
||||
// console.log('Throughput (units/hr):', throughput);
|
||||
}
|
||||
}, [machineActiveTime, materialCycleTime, machineCount]);
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
</>
|
||||
|
|
|
@ -32,7 +32,6 @@ function MachineInstance({ machineDetail }: { machineDetail: MachineStatus }) {
|
|||
|
||||
const reset = () => {
|
||||
setCurrentPhase("idle");
|
||||
console.log("exit");
|
||||
setMachineState(machineDetail.modelUuid, 'idle');
|
||||
setMachineActive(machineDetail.modelUuid, false);
|
||||
isIncrememtable.current = true;
|
||||
|
|
|
@ -190,6 +190,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
|||
activeSecondsElapsed.current = 0;
|
||||
idleSecondsElapsed.current = 0;
|
||||
previousTimeRef.current = null;
|
||||
|
||||
if (animationFrameIdRef.current !== null) {
|
||||
cancelAnimationFrame(animationFrameIdRef.current);
|
||||
animationFrameIdRef.current = null;
|
||||
|
|
Loading…
Reference in New Issue