پتروشیمی آپادانا

This commit is contained in:
mahmoodsht 2025-11-02 16:50:52 +03:30
parent 46c81cf8ea
commit 69e702d368
3 changed files with 301 additions and 74 deletions

View File

@ -1,3 +1,5 @@
//شماتیک آپادانا
import React from "react"; import React from "react";
import { formatNumber } from "~/lib/utils"; import { formatNumber } from "~/lib/utils";
@ -8,10 +10,10 @@ export type CompanyInfo = {
costReduction: number; costReduction: number;
revenue?: number; revenue?: number;
capacity?: number; capacity?: number;
costI : number, costI: number;
capacityI : number, capacityI: number;
revenueI : number, revenueI: number;
cost : number | string, cost: number | string;
}; };
export type D3ImageInfoProps = { export type D3ImageInfoProps = {
@ -21,7 +23,8 @@ export type D3ImageInfoProps = {
}; };
const InfoBox = ({ company, style }: { company: CompanyInfo; style: any }) => { const InfoBox = ({ company, style }: { company: CompanyInfo; style: any }) => {
const hideCapacity = company.name === "خوارزمی"; // اگر خوارزمی بود ظرفیت مخفی شود // const hideCapacity = company.name === "واحد 300"; // اگر واحد 300 بود ظرفیت مخفی شود
const hideCapacity = false;
return ( return (
<div className={`info-box`} style={style}> <div className={`info-box`} style={style}>
<div className="info-box-content"> <div className="info-box-content">
@ -32,15 +35,11 @@ const InfoBox = ({ company, style }: { company: CompanyInfo; style :any }) => {
</div> </div>
<div className="info-row"> <div className="info-row">
<div className="info-label">هزینه:</div> <div className="info-label">هزینه:</div>
{ {hideCapacity ? (
(hideCapacity ?
<div className="info-value cost2 text-[12px]">{formatNumber(company?.cost || 0)}</div> <div className="info-value cost2 text-[12px]">{formatNumber(company?.cost || 0)}</div>
: ) : (
<div className="info-value cost text-[12px]">{formatNumber(company?.cost || 0)}</div> <div className="info-value cost text-[12px]">{formatNumber(company?.cost || 0)}</div>
) )}
}
<div className="info-unit">میلیون ریال</div> <div className="info-unit">میلیون ریال</div>
</div> </div>
{!hideCapacity && ( {!hideCapacity && (
@ -56,35 +55,33 @@ const InfoBox = ({ company, style }: { company: CompanyInfo; style :any }) => {
}; };
export function D3ImageInfo({ companies }: D3ImageInfoProps) { export function D3ImageInfo({ companies }: D3ImageInfoProps) {
// Ensure we have exactly 6 companies // واحدهای جدید - 4 واحد
const sample = [ const sample = [
{ id: "آب نیرو", name: "آب نیرو", imageUrl: "/abniro.png" }, { id: "واحد 100", name: "واحد 100", imageUrl: "/abniro.png" },
{ id: "بسپاران", name: "بسپاران", imageUrl: "/besparan.png" }, { id: "واحد 200", name: "واحد 200", imageUrl: "/besparan.png" },
{ id: "خوارزمی", name: "خوارزمی", imageUrl: "/khwarazmi.png" }, { id: "واحد 300", name: "واحد 300", imageUrl: "/khwarazmi.png" },
{ id: "فراورش 1", name: "فراورش 1", imageUrl: "/faravash1.png" }, { id: "واحد 400", name: "واحد 400", imageUrl: "/faravash1.png" }
{ id: "فراورش 2", name: "فراورش 2", imageUrl: "/faravash2.png" },
{ id: "کیمیا", name: "کیمیا", imageUrl: "/kimia.png" }
]; ];
const merged = sample.map(company => { const merged = sample.map(company => {
const found = companies.find(item => item.id == company.id); const found = companies.find(item => item.id === company.id);
return found return found
? found ? found
: { ...company, cost: 0, capacity: 0, revenue: 0 }; : { ...company, cost: 0, capacity: 0, revenue: 0, costReduction: 0, costI: 0, capacityI: 0, revenueI: 0 };
}); });
const displayCompanies = merged; const displayCompanies = merged;
console.log(displayCompanies) console.log(displayCompanies);
// Positions inside a 5x4 grid (col, row) // موقعیت‌های جدید برای چیدمان لوزی شکل (3 ردیف - 1-2-1)
// Layout keeps same visual logic: left/middle/right on two bands with spacing grid around // گرید 5x4 نگه داشته شده اما موقعیت‌ها تغییر کرده
const gridPositions = [ const gridPositions = [
{ col: 2, row: 2 , colI : 1 , rowI : 2 , name : "بسپاران"}, // left - top band { col: 2, row: 1, colI: 1, rowI: 1, name: "واحد 100" }, // ردیف اول - ستون اول
{ col: 3, row: 2 , colI : 3 , rowI : 1 , name : "خوارزمی"}, // middle top (image sits in row 2, info box goes to row 1) { col: 4, row: 1, colI: 5, rowI: 1, name: "واحد 200" }, // ردیف اول - ستون دوم
{ col: 4, row: 2 ,colI : 5 , rowI : 2 , name : "فراورش 1"}, // right - top band { col: 2, row: 3, colI: 1, rowI: 3, name: "واحد 300" }, // ردیف دوم - ستون اول
{ col: 2, row: 3 , colI : 1 , rowI : 3 , name : "کیمیا"}, // left - bottom band { col: 4, row: 3, colI: 5, rowI: 3, name: "واحد 400" }, // ردیف دوم - ستون دوم
{ col: 3, row: 3 , colI : 3, rowI : 4 , name : "آب نیرو"}, // middle bottom (image sits in row 3, info box goes to row 4)
{ col: 4, row: 3 , colI : 5 , rowI : 3 , name : "فراورش 2"}, // right - bottom band
]; ];
return ( return (
@ -93,24 +90,23 @@ export function D3ImageInfo({ companies }: D3ImageInfoProps) {
{displayCompanies.map((company, index) => { {displayCompanies.map((company, index) => {
const gp = gridPositions.find(v => v.name === company.name); const gp = gridPositions.find(v => v.name === company.name);
return ( return (
<> <React.Fragment key={company.id}>
<div <div
key={company.id}
className={`company-item`} className={`company-item`}
style={{ gridColumn: gp.col, gridRow: gp.row }} style={{ gridColumn: gp?.col, gridRow: gp?.row }}
> >
<div className="company-image-containe"> <div className="company-image-container">
<img <img
src={company.imageUrl} src={company.imageUrl}
alt={company.name} alt={company.name}
className="company-image" className="company-image"
/> />
</div> </div>
{company.name} {company.name}
</div> </div>
<InfoBox company={company} key={index +10} style={{ gridColumn: gp?.colI , gridRow: gp?.rowI }} /> <InfoBox company={company} style={{ gridColumn: gp?.colI, gridRow: gp?.rowI }} />
</>); </React.Fragment>
);
})} })}
</div> </div>
@ -156,7 +152,6 @@ export function D3ImageInfo({ companies }: D3ImageInfoProps) {
background-color: transparent; background-color: transparent;
} }
.info-box-content { .info-box-content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -170,10 +165,14 @@ export function D3ImageInfo({ companies }: D3ImageInfoProps) {
gap: .5rem; gap: .5rem;
justify-content: space-between; justify-content: space-between;
direction: rtl; direction: rtl;
}
&:has(.info-value.revenue) {border-bottom: 1px solid #3AEA83;} .info-row:has(.info-value.revenue) {
&:has(.info-value.cost) {border-bottom: 1px solid #F76276;} border-bottom: 1px solid #3AEA83;
}
.info-row:has(.info-value.cost) {
border-bottom: 1px solid #F76276;
} }
.info-label { .info-label {

View File

@ -0,0 +1,213 @@
//شماتیک بندر امام
import React from "react";
import { formatNumber } from "~/lib/utils";
export type CompanyInfo = {
id: string;
imageUrl: string;
name: string;
costReduction: number;
revenue?: number;
capacity?: number;
costI : number,
capacityI : number,
revenueI : number,
cost : number | string,
};
export type D3ImageInfoProps = {
companies: CompanyInfo[];
width?: number;
height?: number;
};
const InfoBox = ({ company, style }: { company: CompanyInfo; style :any }) => {
const hideCapacity = company.name === "خوارزمی"; // اگر خوارزمی بود ظرفیت مخفی شود
return (
<div className={`info-box`} style={style}>
<div className="info-box-content">
<div className="info-row">
<div className="info-label">درآمد:</div>
<div className="info-value revenue text-[12px]">{formatNumber(company?.revenue || 0)}</div>
<div className="info-unit">میلیون ریال</div>
</div>
<div className="info-row">
<div className="info-label">هزینه:</div>
{
(hideCapacity ?
<div className="info-value cost2 text-[12px]">{formatNumber(company?.cost || 0)}</div>
:
<div className="info-value cost text-[12px]">{formatNumber(company?.cost || 0)}</div>
)
}
<div className="info-unit">میلیون ریال</div>
</div>
{!hideCapacity && (
<div className="info-row">
<div className="info-label">ظرفیت:</div>
<div className="info-value capacity text-[12px]">{formatNumber(company?.capacity || 0)}</div>
<div className="info-unit">تن در سال</div>
</div>
)}
</div>
</div>
);
};
export function D3ImageInfo({ companies }: D3ImageInfoProps) {
// Ensure we have exactly 6 companies
const sample = [
{ id: "آب نیرو", name: "آب نیرو", imageUrl: "/abniro.png" },
{ id: "بسپاران", name: "بسپاران", imageUrl: "/besparan.png" },
{ id: "خوارزمی", name: "خوارزمی", imageUrl: "/khwarazmi.png" },
{ id: "فراورش 1", name: "فراورش 1", imageUrl: "/faravash1.png" },
{ id: "فراورش 2", name: "فراورش 2", imageUrl: "/faravash2.png" },
{ id: "کیمیا", name: "کیمیا", imageUrl: "/kimia.png" }
];
const merged = sample.map(company => {
const found = companies.find(item => item.id == company.id);
return found
? found
: { ...company, cost: 0, capacity: 0, revenue: 0 };
});
const displayCompanies = merged;
console.log(displayCompanies)
// Positions inside a 5x4 grid (col, row)
// Layout keeps same visual logic: left/middle/right on two bands with spacing grid around
const gridPositions = [
{ col: 2, row: 2 , colI : 1 , rowI : 2 , name : "بسپاران"}, // left - top band
{ col: 3, row: 2 , colI : 3 , rowI : 1 , name : "خوارزمی"}, // middle top (image sits in row 2, info box goes to row 1)
{ col: 4, row: 2 ,colI : 5 , rowI : 2 , name : "فراورش 1"}, // right - top band
{ col: 2, row: 3 , colI : 1 , rowI : 3 , name : "کیمیا"}, // left - bottom band
{ col: 3, row: 3 , colI : 3, rowI : 4 , name : "آب نیرو"}, // middle bottom (image sits in row 3, info box goes to row 4)
{ col: 4, row: 3 , colI : 5 , rowI : 3 , name : "فراورش 2"}, // right - bottom band
];
return (
<div className="w-full h-[500px] rounded-xl">
<div dir="ltr" className="company-grid-container">
{displayCompanies.map((company, index) => {
const gp = gridPositions.find(v => v.name === company.name) ;
return (
<>
<div
key={company.id}
className={`company-item`}
style={{ gridColumn: gp.col, gridRow: gp.row }}
>
<div className="company-image-containe">
<img
src={company.imageUrl}
alt={company.name}
className="company-image"
/>
</div>
{company.name}
</div>
<InfoBox company={company} key={index +10} style={{ gridColumn: gp?.colI , gridRow: gp?.rowI }} />
</>);
})}
</div>
<style jsx>{`
.company-grid-container {
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-template-rows: repeat(4, 1fr);
gap: 5px;
width: 100%;
height: 500px;
}
.company-item {
border-radius: 8px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.company-image-container {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
.company-image {
object-fit: contain;
height : 100px;
}
.info-box {
border: 1px solid #3F415A;
border-radius: 10px;
height: max-content;
align-self : center;
justify-self : center;
padding : .2rem 1.2rem;
min-width : 8rem;
background-color: transparent;
}
.info-box-content {
display: flex;
flex-direction: column;
justify-content: center;
}
.info-row {
position : relative;
margin: .1rem 0;
display: flex;
gap : .5rem;
justify-content : space-between;
direction: rtl;
&:has(.info-value.revenue) {border-bottom: 1px solid #3AEA83;}
&:has(.info-value.cost) {border-bottom: 1px solid #F76276;}
}
.info-label {
color: #FFFFFF;
font-size: 11px;
font-weight: 300;
text-align: right;
margin : auto 0;
}
.info-value {
color: #34D399;
font-size: 14px;
font-weight: 500;
text-align: right;
margin-bottom : .5rem;
}
.info-value.revenue { color: #fff;}
.info-value.cost { color: #fff; }
.info-value.cost2 { color: #fff; }
.info-value.capacity { color: #fff; }
.info-unit {
position: absolute;
left: 0;
bottom: 2px;
color: #ACACAC;
font-size: 6px;
font-weight: 400;
}
`}</style>
</div>
);
}

View File

@ -641,16 +641,31 @@ export function DashboardHome() {
<TabsContent value="canvas" className="w-ful h-full"> <TabsContent value="canvas" className="w-ful h-full">
<div className="p-4 h-full w-full"> <div className="p-4 h-full w-full">
<D3ImageInfo <D3ImageInfo
//پتروشیمی بندر امام
// companies={companyChartData.map((item) => {
// const imageMap: Record<string, string> = {
// بسپاران: "/besparan.png",
// خوارزمی: "/khwarazmi.png",
// "فراورش 1": "/faravash1.png",
// "فراورش 2": "/faravash2.png",
// کیمیا: "/kimia.png",
// "آب نیرو": "/abniro.png",
// };
//پتروشیمی آپادانا
companies={companyChartData.map((item) => { companies={companyChartData.map((item) => {
const imageMap: Record<string, string> = { const imageMap: Record<string, string> = {
بسپاران: "/besparan.png", "واحد 100": "/abniro.png" ,
خوارزمی: "/khwarazmi.png", "واحد 200": "/besparan.png" ,
"فراورش 1": "/faravash1.png", "واحد 300": "/khwarazmi.png" ,
"فراورش 2": "/faravash2.png", "واحد 400": "/faravash1.png"
کیمیا: "/kimia.png",
"آب نیرو": "/abniro.png",
}; };
return { return {
id: item.category, id: item.category,
name: item.category, name: item.category,