chore: restore MVP dashboard components from backup
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
// ============================================================
|
||||
// ویجت ۴ — کنترل روزانه (امروز)
|
||||
// کارتهای KPI: بلیتهای خروج امروز، برگشت از سایت، ضایعات و پذیرش
|
||||
// + فهرست دقیق نام تحویلدهندهها/انجامدهندهها + ریز عملیات امروز.
|
||||
// هر ۶۰ ثانیه خودکار تازهسازی میشود (useDailyControl).
|
||||
// ============================================================
|
||||
|
||||
import {
|
||||
ArrowDownToLine,
|
||||
ArrowUpFromLine,
|
||||
PackageOpen,
|
||||
TriangleAlert,
|
||||
Users,
|
||||
type LucideIcon,
|
||||
} from "lucide-react";
|
||||
import { useDailyControl } from "../../hooks/useDashboardData";
|
||||
import { faNum, fmtDateTime } from "../../lib/formatters";
|
||||
import { isoToJalaliStr } from "../../lib/jalali";
|
||||
import { cn } from "../../lib/utils";
|
||||
import { Badge } from "../ui/badge";
|
||||
import { ChartCard, ChartEmpty, ChartLoading } from "./chartShared";
|
||||
|
||||
const TYPE_FA: Record<string, string> = {
|
||||
WITHDRAWAL: "برداشت از انبار",
|
||||
RETURN: "برگشت از سایت",
|
||||
DAMAGE: "آسیبدیده",
|
||||
WASTE: "اتلاف",
|
||||
LOSS: "مفقودی",
|
||||
PURCHASE: "پذیرش خرید",
|
||||
TRANSFER_IN: "انتقال ورودی",
|
||||
TRANSFER_OUT: "انتقال خروجی",
|
||||
FOUND: "پیدا شده",
|
||||
STOCK_COUNT: "انبارگردانی",
|
||||
};
|
||||
|
||||
const TYPE_STYLE: Record<string, string> = {
|
||||
WITHDRAWAL: "bg-blue-bg text-[#1d4ed8]",
|
||||
RETURN: "bg-amber-bg text-amber",
|
||||
DAMAGE: "bg-red-bg text-red",
|
||||
WASTE: "bg-red-bg text-red",
|
||||
LOSS: "bg-red-bg text-red",
|
||||
PURCHASE: "bg-green-bg text-green",
|
||||
};
|
||||
|
||||
function KpiCard({
|
||||
icon: Icon,
|
||||
label,
|
||||
tickets,
|
||||
qty,
|
||||
tone,
|
||||
}: {
|
||||
icon: LucideIcon;
|
||||
label: string;
|
||||
tickets: number;
|
||||
qty: number;
|
||||
tone: string;
|
||||
}) {
|
||||
return (
|
||||
<div className="flex items-center gap-3 rounded-xl border border-line bg-panel px-3 py-2.5">
|
||||
<span className={cn("flex h-9 w-9 shrink-0 items-center justify-center rounded-lg", tone)}>
|
||||
<Icon className="h-4.5 w-4.5" />
|
||||
</span>
|
||||
<div className="min-w-0">
|
||||
<div className="text-[11px] text-muted">{label}</div>
|
||||
<div className="flex items-baseline gap-1.5 tabular-nums">
|
||||
<span className="text-[17px] font-extrabold leading-6">{faNum(tickets)}</span>
|
||||
<span className="text-[10.5px] text-muted">بلیت</span>
|
||||
<span className="text-[11px] text-muted">·</span>
|
||||
<span className="text-[12px] font-bold">{faNum(qty.toLocaleString("en-US"))}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function DailyControlPanel() {
|
||||
const query = useDailyControl();
|
||||
const d = query.data;
|
||||
|
||||
return (
|
||||
<ChartCard
|
||||
title="کنترل روزانه — عملیات امروز"
|
||||
sub={d ? `تاریخ ${isoToJalaliStr(d.date) ?? d.date} — هر دقیقه بهروزرسانی میشود` : "هر دقیقه بهروزرسانی میشود"}
|
||||
>
|
||||
{query.isLoading ? (
|
||||
<ChartLoading />
|
||||
) : !d ? (
|
||||
<ChartEmpty message="دادهی امروز در دسترس نیست" />
|
||||
) : (
|
||||
<div className="flex flex-col gap-3">
|
||||
{/* KPI کارتها */}
|
||||
<div className="grid grid-cols-2 gap-2 lg:grid-cols-4">
|
||||
<KpiCard
|
||||
icon={ArrowUpFromLine}
|
||||
label="خروج به سایت (برداشت)"
|
||||
tickets={d.outbound.tickets}
|
||||
qty={d.outbound.qty}
|
||||
tone="bg-blue-bg text-[#1d4ed8]"
|
||||
/>
|
||||
<KpiCard
|
||||
icon={ArrowDownToLine}
|
||||
label="برگشت از سایت"
|
||||
tickets={d.returns.tickets}
|
||||
qty={d.returns.qty}
|
||||
tone="bg-amber-bg text-amber"
|
||||
/>
|
||||
<KpiCard
|
||||
icon={TriangleAlert}
|
||||
label="ضایعات / اتلاف / مفقودی"
|
||||
tickets={d.waste.tickets}
|
||||
qty={d.waste.qty}
|
||||
tone="bg-red-bg text-red"
|
||||
/>
|
||||
<KpiCard
|
||||
icon={PackageOpen}
|
||||
label="پذیرش خرید (ورود)"
|
||||
tickets={d.purchases.tickets}
|
||||
qty={d.purchases.qty}
|
||||
tone="bg-green-bg text-green"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3 lg:grid-cols-5">
|
||||
{/* نام دقیق انجامدهندهها */}
|
||||
<div className="rounded-xl border border-line p-3 lg:col-span-2">
|
||||
<h3 className="mb-2 flex items-center gap-1.5 text-[12.5px] font-extrabold">
|
||||
<Users className="h-4 w-4 text-muted" />
|
||||
تحویلدهندهها / انجامدهندههای امروز
|
||||
</h3>
|
||||
{d.performers.length === 0 ? (
|
||||
<p className="py-4 text-center text-[12px] text-muted">امروز عملیاتی ثبت نشده است</p>
|
||||
) : (
|
||||
<ul className="flex flex-col divide-y divide-line">
|
||||
{d.performers.map((p, i) => (
|
||||
<li key={i} className="flex items-center gap-2 py-1.5">
|
||||
<span className="flex h-7 w-7 items-center justify-center rounded-full bg-accent-bg text-[11px] font-extrabold text-accent">
|
||||
{faNum(i + 1)}
|
||||
</span>
|
||||
<span className="truncate text-[12.5px] font-bold">{p.name}</span>
|
||||
<span className="ms-auto shrink-0 text-[11px] tabular-nums text-muted">
|
||||
{faNum(p.tickets)} بلیت · {faNum(p.qty.toLocaleString("en-US"))}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* ریز عملیات امروز */}
|
||||
<div className="rounded-xl border border-line p-3 lg:col-span-3">
|
||||
<h3 className="mb-2 text-[12.5px] font-extrabold">ریز عملیات امروز</h3>
|
||||
{d.items.length === 0 ? (
|
||||
<p className="py-4 text-center text-[12px] text-muted">هنوز جابهجاییای امروز ثبت نشده است</p>
|
||||
) : (
|
||||
<ul className="max-h-56 flex flex-col divide-y divide-line overflow-y-auto pe-1">
|
||||
{d.items.map((it) => (
|
||||
<li key={it.id} className="flex items-center gap-2 py-1.5">
|
||||
<Badge
|
||||
className={cn(
|
||||
"shrink-0 px-2 py-0 text-[10px]",
|
||||
TYPE_STYLE[it.transaction_type] ?? "bg-slate-bg text-muted",
|
||||
)}
|
||||
>
|
||||
{TYPE_FA[it.transaction_type] ?? it.transaction_type}
|
||||
</Badge>
|
||||
<span className="truncate text-[12px] font-bold">{it.material}</span>
|
||||
<span className="shrink-0 text-[11px] tabular-nums text-muted">
|
||||
{faNum(it.quantity.toLocaleString("en-US"))} {it.unit_code}
|
||||
</span>
|
||||
<span className="ms-auto shrink-0 text-[10.5px] text-muted" title={it.warehouse}>
|
||||
{fmtDateTime(it.transaction_date)}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</ChartCard>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user