Merge remote-tracking branch 'origin/dev-resourceManagement' into main-demo
This commit is contained in:
@@ -336,18 +336,35 @@ export const MachineIcon = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const CraneIcon = () => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M18.5 5.7502L12.875 1.3752C12.6875 1.1877 12.375 1.1877 12.125 1.3127L5.4375 5.6252H1.875C1.5 5.6252 1.25 5.8752 1.25 6.2502C1.25 6.6252 1.5 6.8752 1.875 6.8752H4.375V10.0002H1.875C1.5 10.0002 1.25 10.2502 1.25 10.6252V13.7502C1.25 14.1252 1.5 14.3752 1.875 14.3752H8.125C8.5 14.3752 8.75 14.1252 8.75 13.7502V10.6252C8.75 10.2502 8.5 10.0002 8.125 10.0002H5.625V6.8752H10.625V15.9377L8.375 17.6252C8.1875 17.8127 8.0625 18.0627 8.1875 18.3127C8.25 18.5627 8.5 18.7502 8.75 18.7502H16.25C16.5 18.7502 16.75 18.5627 16.8125 18.3127C16.875 18.0627 16.8125 17.7502 16.625 17.6252L14.375 15.9377V6.8752H18.125C18.375 6.8752 18.625 6.6877 18.6875 6.4377C18.8125 6.1877 18.75 5.9377 18.5 5.7502ZM3.6875 11.2502L2.5 12.7502V11.2502H3.6875ZM5 11.6252L6.1875 13.1252H3.8125L5 11.6252ZM7.5 12.7502L6.3125 11.2502H7.5V12.7502ZM11.875 3.0002V5.6252H11.25H7.75L11.875 3.0002ZM13.75 5.6252H13.125V3.1252L16.3125 5.6252H13.75Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
type TypeBasedAssetIconsProps = {
|
type TypeBasedAssetIconsProps = {
|
||||||
assetType: string;
|
assetType: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function TypeBasedAssetIcons({ assetType }: TypeBasedAssetIconsProps) {
|
export function TypeBasedAssetIcons({ assetType }: TypeBasedAssetIconsProps) {
|
||||||
console.log("assetType: ", assetType);
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{assetType === "machine" && <MachineIcon />}
|
{assetType === "StaticMachine" && <MachineIcon />}
|
||||||
{assetType === "vehicle" && <ForkLiftIcon />}
|
{assetType === "Vehicle" && <ForkLiftIcon />}
|
||||||
{assetType === "transfer" && <ConveyorIcon />}
|
{assetType === "Conveyor" && <ConveyorIcon />}
|
||||||
{assetType === "roboticArm" && <RoboticArmIcon />}
|
{assetType === "Crane" && <CraneIcon />}
|
||||||
|
{assetType === "ArmBot" && <RoboticArmIcon />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,38 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { ClockThreeIcon, LocationPinIcon, TargetIcon } from '../../../../icons/ExportCommonIcons'
|
import { ClockThreeIcon, LocationPinIcon, TargetIcon } from '../../../../icons/ExportCommonIcons'
|
||||||
import { useSceneContext } from '../../../../../modules/scene/sceneContext';
|
import { useSceneContext } from '../../../../../modules/scene/sceneContext';
|
||||||
import { useProductContext } from '../../../../../modules/simulation/products/productContext';
|
|
||||||
import RenameInput from '../../../../ui/inputs/RenameInput';
|
import RenameInput from '../../../../ui/inputs/RenameInput';
|
||||||
import { useResourceManagementId } from '../../../../../store/builder/store';
|
import { useResourceManagementId } from '../../../../../store/builder/store';
|
||||||
import { set } from 'immer/dist/internal';
|
import { getAssetThumbnail } from '../../../../../services/factoryBuilder/asset/assets/getAssetThumbnail';
|
||||||
// import NavigateCatagory from '../NavigateCatagory'
|
// import NavigateCatagory from '../NavigateCatagory'
|
||||||
|
|
||||||
const Hrm = () => {
|
const Hrm = () => {
|
||||||
const [selectedCard, setSelectedCard] = useState(0);
|
const [selectedCard, setSelectedCard] = useState(0);
|
||||||
const [workers, setWorkers] = useState<any[]>([]);
|
const [workers, setWorkers] = useState<any[]>([]);
|
||||||
|
|
||||||
const { productStore } = useSceneContext();
|
|
||||||
const { products, getProductById } = productStore();
|
|
||||||
const { selectedProductStore } = useProductContext();
|
|
||||||
const { selectedProduct } = selectedProductStore();
|
|
||||||
const { setResourceManagementId } = useResourceManagementId();
|
const { setResourceManagementId } = useResourceManagementId();
|
||||||
|
const { assetStore } = useSceneContext();
|
||||||
|
const { assets: allAssets } = assetStore();
|
||||||
|
|
||||||
|
async function getAsset(assetId: string) {
|
||||||
|
let thumbnail = await getAssetThumbnail(assetId)
|
||||||
|
if (thumbnail.thumbnail) {
|
||||||
|
let assetImage = thumbnail.thumbnail
|
||||||
|
return assetImage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedProduct) {
|
if (allAssets.length > 0) {
|
||||||
const productDetails = getProductById(selectedProduct.productUuid);
|
const fetchWorkers = async () => {
|
||||||
const workerDetails = productDetails?.eventDatas || [];
|
const humans = allAssets.filter((worker: any) => worker.eventData.type === "Human");
|
||||||
|
|
||||||
const formattedWorkers = workerDetails
|
const formattedWorkers = await Promise.all(
|
||||||
.filter((worker: any) => worker.type === "human")
|
humans.map(async (worker: any, index: number) => {
|
||||||
.map((worker: any, index: number) => ({
|
const assetImage = await getAsset(worker.assetId);
|
||||||
|
|
||||||
|
return {
|
||||||
employee: {
|
employee: {
|
||||||
image: "",
|
image: assetImage,
|
||||||
name: worker.modelName,
|
name: worker.modelName,
|
||||||
modelId: worker.modelUuid,
|
modelId: worker.modelUuid,
|
||||||
employee_id: `HR-${204 + index}`,
|
employee_id: `HR-${204 + index}`,
|
||||||
@@ -34,33 +40,28 @@ const Hrm = () => {
|
|||||||
},
|
},
|
||||||
task: {
|
task: {
|
||||||
status: "Ongoing",
|
status: "Ongoing",
|
||||||
title: worker.taskTitle || "No Task Assigned",
|
title: worker.taskTitle ?? "No Task Assigned",
|
||||||
location: {
|
location: {
|
||||||
floor: worker.floor || 0,
|
floor: worker.floor ?? 0,
|
||||||
zone: worker.zone || "N/A"
|
zone: worker.zone ?? "N/A",
|
||||||
},
|
},
|
||||||
planned_time_hours: worker.plannedTime || 0,
|
planned_time_hours: worker.plannedTime ?? 0,
|
||||||
time_spent_hours: worker.timeSpent || 0,
|
time_spent_hours: worker.timeSpent ?? 0,
|
||||||
total_tasks: worker.totalTasks || 0,
|
total_tasks: worker.totalTasks ?? 0,
|
||||||
completed_tasks: worker.completedTasks || 0
|
completed_tasks: worker.completedTasks ?? 0,
|
||||||
},
|
},
|
||||||
actions: [
|
actions: ["Assign Task", "Reassign Task", "Pause", "Emergency Stop"],
|
||||||
"Assign Task",
|
location: `Floor ${worker.floor || "-"} . Zone ${worker.zone || "-"}`,
|
||||||
"Reassign Task",
|
};
|
||||||
"Pause",
|
})
|
||||||
"Emergency Stop"
|
);
|
||||||
],
|
|
||||||
location: `Floor ${worker.floor || "-"} . Zone ${worker.zone || "-"}`
|
|
||||||
}));
|
|
||||||
|
|
||||||
setWorkers(formattedWorkers);
|
setWorkers(formattedWorkers);
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchWorkers();
|
||||||
}
|
}
|
||||||
}, [selectedProduct, getProductById]);
|
}, [allAssets]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
//
|
|
||||||
}, [workers]);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -151,7 +152,7 @@ const Hrm = () => {
|
|||||||
// },
|
// },
|
||||||
// ]
|
// ]
|
||||||
function handleRenameWorker(newName: string) {
|
function handleRenameWorker(newName: string) {
|
||||||
//
|
|
||||||
|
|
||||||
}
|
}
|
||||||
function handleHumanClick(employee: any) {
|
function handleHumanClick(employee: any) {
|
||||||
|
|||||||
@@ -1,65 +1,70 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
// import NavigateCatagory from '../../NavigateCatagory'
|
// import NavigateCatagory from '../../NavigateCatagory'
|
||||||
import { EyeIcon, KebabIcon, LocationPinIcon, RightHalfFillCircleIcon } from '../../../../../icons/ExportCommonIcons';
|
import { EyeIcon, KebabIcon, LocationPinIcon, RightHalfFillCircleIcon } from '../../../../../icons/ExportCommonIcons';
|
||||||
import assetImage from "../../../../../../assets/image/asset-image.png"
|
import assetImageFallback from "../../../../../../assets/image/asset-image.png"
|
||||||
import { useSceneContext } from '../../../../../../modules/scene/sceneContext';
|
import { useSceneContext } from '../../../../../../modules/scene/sceneContext';
|
||||||
import { useProductContext } from '../../../../../../modules/simulation/products/productContext';
|
|
||||||
import RenameInput from '../../../../../ui/inputs/RenameInput';
|
import RenameInput from '../../../../../ui/inputs/RenameInput';
|
||||||
import { useResourceManagementId } from '../../../../../../store/builder/store';
|
import { useResourceManagementId } from '../../../../../../store/builder/store';
|
||||||
|
import { getAssetThumbnail } from '../../../../../../services/factoryBuilder/asset/assets/getAssetThumbnail';
|
||||||
import { TypeBasedAssetIcons } from '../../../../../icons/AssetTypeIcons';
|
import { TypeBasedAssetIcons } from '../../../../../icons/AssetTypeIcons';
|
||||||
|
|
||||||
const AssetManagement = () => {
|
const AssetManagement = () => {
|
||||||
// const [selectedCategory, setSelectedCategory] = useState("All Assets");
|
// const [selectedCategory, setSelectedCategory] = useState("All Assets");
|
||||||
const [expandedAssetId, setExpandedAssetId] = useState<string | null>(null);
|
const [expandedAssetId, setExpandedAssetId] = useState<string | null>(null);
|
||||||
const [assets, setAssets] = useState<any[]>([]);
|
const [assets, setAssets] = useState<any[]>([]);
|
||||||
|
|
||||||
const { productStore } = useSceneContext();
|
|
||||||
const { getProductById } = productStore();
|
|
||||||
const { selectedProductStore } = useProductContext();
|
|
||||||
const { selectedProduct } = selectedProductStore();
|
|
||||||
const { setResourceManagementId } = useResourceManagementId();
|
const { setResourceManagementId } = useResourceManagementId();
|
||||||
|
const { assetStore } = useSceneContext();
|
||||||
|
const { assets: allAssets } = assetStore();
|
||||||
|
|
||||||
|
async function getAsset(assetId: string) {
|
||||||
|
let thumbnail = await getAssetThumbnail(assetId)
|
||||||
|
if (thumbnail.thumbnail) {
|
||||||
|
let assetImage = thumbnail.thumbnail ?? assetImageFallback;
|
||||||
|
return assetImage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedProduct) {
|
if (allAssets.length > 0) {
|
||||||
const productDetails = getProductById(selectedProduct.productUuid);
|
const fetchAssets = async () => {
|
||||||
const productAssets = productDetails?.eventDatas || [];
|
|
||||||
const grouped: Record<string, any> = {};
|
const grouped: Record<string, any> = {};
|
||||||
productAssets.forEach((asset: any) => {
|
|
||||||
if (asset.type === "storageUnit" || asset.type === "human") return;
|
// Use Promise.all to handle all async operations
|
||||||
if (!grouped[asset.modelName]) {
|
await Promise.all(allAssets.map(async (asset: any) => {
|
||||||
grouped[asset.modelName] = {
|
|
||||||
|
if (asset.eventData.type === "Storage" || asset.eventData.type === "Human") return;
|
||||||
|
|
||||||
|
const assetImage = await getAsset(asset.assetId);
|
||||||
|
|
||||||
|
if (!grouped[asset.assetId]) {
|
||||||
|
//
|
||||||
|
grouped[asset.assetId] = {
|
||||||
id: asset.modelUuid,
|
id: asset.modelUuid,
|
||||||
|
assetId: asset.assetId,
|
||||||
name: asset.modelName,
|
name: asset.modelName,
|
||||||
type: asset.type,
|
type: asset.eventData.type,
|
||||||
model: asset.modelCode || "N/A",
|
model: asset.modelCode ?? "N/A",
|
||||||
status: asset.status || "Online",
|
status: asset.status ?? "Online",
|
||||||
usageRate: asset.usageRate || 15,
|
usageRate: asset.usageRate ?? 15,
|
||||||
level: asset.level || "Level 1",
|
level: asset.level ?? "Level 1",
|
||||||
image: assetImage,
|
image: assetImage,
|
||||||
description: asset.description || "No description",
|
description: asset.description ?? "No description",
|
||||||
cost: asset.cost || 0,
|
cost: asset.cost ?? 0,
|
||||||
count: 1,
|
count: 1,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
grouped[asset.modelName].count += 1;
|
grouped[asset.assetId].count += 1;
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
|
|
||||||
setAssets(Object.values(grouped));
|
setAssets(Object.values(grouped));
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line
|
fetchAssets();
|
||||||
}, [selectedProduct]);
|
}
|
||||||
|
}, [allAssets]);
|
||||||
|
|
||||||
function handleRenameAsset(newName: string) {
|
function handleRenameAsset(newName: string) {
|
||||||
//
|
|
||||||
// if (expandedAssetId) {
|
|
||||||
// setAssets(prevAssets =>
|
|
||||||
// prevAssets.map(asset =>
|
|
||||||
// asset.id === expandedAssetId ? { ...asset, name: newName } : asset
|
|
||||||
// )
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -68,8 +73,6 @@ const AssetManagement = () => {
|
|||||||
}, [assets]);
|
}, [assets]);
|
||||||
|
|
||||||
function handleAssetClick(id: string) {
|
function handleAssetClick(id: string) {
|
||||||
|
|
||||||
|
|
||||||
setResourceManagementId(id);
|
setResourceManagementId(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +129,6 @@ const AssetManagement = () => {
|
|||||||
<div className={`assetManagement-card-wrapper ${expandedAssetId === asset.id ? "openViewMore" : ""}`} key={index}>
|
<div className={`assetManagement-card-wrapper ${expandedAssetId === asset.id ? "openViewMore" : ""}`} key={index}>
|
||||||
<header>
|
<header>
|
||||||
<div className="header-wrapper">
|
<div className="header-wrapper">
|
||||||
|
|
||||||
{expandedAssetId === asset.id ?
|
{expandedAssetId === asset.id ?
|
||||||
<>
|
<>
|
||||||
<div className="drop-icon" onClick={() => setExpandedAssetId(null)}>▾</div>
|
<div className="drop-icon" onClick={() => setExpandedAssetId(null)}>▾</div>
|
||||||
@@ -173,9 +175,9 @@ const AssetManagement = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="asset-estimate__view-button">
|
<div className="asset-estimate__view-button" onClick={() => handleAssetClick(asset.id)}>
|
||||||
<EyeIcon isClosed={false} />
|
<EyeIcon isClosed={false} />
|
||||||
<div className="asset-estimate__view-text" onClick={() => handleAssetClick(asset.id)}>View in Scene</div>
|
<div className="asset-estimate__view-text">View in Scene</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
|
|
||||||
|
export const getAssetThumbnail = async (assetId: String) => {
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${url_Backend_dwinzo}/api/v2/getAssetThumbnail/${assetId}`,
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer <access_token>",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
token: localStorage.getItem("token") || "",
|
||||||
|
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const newAccessToken = response.headers.get("x-access-token");
|
||||||
|
if (newAccessToken) {
|
||||||
|
localStorage.setItem("token", newAccessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Failed to fetch assets");
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
return await response.json();
|
||||||
|
} catch (error: any) {
|
||||||
|
echo.error("Failed to get asset image");
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -117,6 +117,12 @@
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
.user-image{
|
||||||
|
height: 300%;
|
||||||
|
width: 300%;
|
||||||
|
transform: translate(-26px, -12px);
|
||||||
|
}
|
||||||
|
|
||||||
.status {
|
.status {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
|||||||
Reference in New Issue
Block a user