Enhance logistics and production pages with additional mappings and data aggregation
- Added Korean labels for `shipmentInstruction` and `purchase_detail` in the logistics pages to improve clarity. - Introduced a new constant `WOPR_TABLE` in the production result page for better data management. - Implemented daily aggregation of `work_order_process_result` data to enrich the `work_order_process` rows, enhancing data accuracy and user experience. These updates improve the usability and data handling in the logistics and production modules.
This commit is contained in:
@@ -123,6 +123,7 @@ const getStatusColor = (status: string) => OUTBOUND_STATUS_OPTIONS.find((s) => s
|
||||
// 소스 테이블 한글명 매핑
|
||||
const SOURCE_TYPE_LABEL: Record<string, string> = {
|
||||
shipment_instruction_detail: "출하지시",
|
||||
shipmentInstruction: "출하지시",
|
||||
purchase_order_mng: "발주",
|
||||
item_info: "품목",
|
||||
};
|
||||
|
||||
@@ -259,6 +259,7 @@ const getStatusVariant = (status: string): "default" | "secondary" | "outline" |
|
||||
// 소스 테이블 한글명 매핑
|
||||
const SOURCE_TABLE_LABEL: Record<string, string> = {
|
||||
purchase_order_mng: "발주",
|
||||
purchase_detail: "발주",
|
||||
shipment_instruction_detail: "출하",
|
||||
item_info: "품목",
|
||||
};
|
||||
|
||||
@@ -33,6 +33,7 @@ import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSea
|
||||
|
||||
const WI_TABLE = "work_instruction";
|
||||
const WOP_TABLE = "work_order_process";
|
||||
const WOPR_TABLE = "work_order_process_result";
|
||||
|
||||
const fmtNum = (v: any) => {
|
||||
const n = Number(v);
|
||||
@@ -194,7 +195,36 @@ export default function ProductionResultPage() {
|
||||
autoFilter: true,
|
||||
sort: { columnName: "seq_no", order: "asc" },
|
||||
});
|
||||
setProcessData(res.data?.data?.data || res.data?.data?.rows || []);
|
||||
const wopRows: any[] = res.data?.data?.data || res.data?.data?.rows || [];
|
||||
|
||||
// wopr 일별 실적 집계 → wop별 합산하여 wop row에 덮어씀
|
||||
const woprAgg = new Map<string, { good: number; defect: number; input: number }>();
|
||||
for (const w of wopRows) {
|
||||
if (!w.id) continue;
|
||||
try {
|
||||
const wr = await apiClient.post(`/table-management/tables/${WOPR_TABLE}/data`, {
|
||||
page: 1, size: 0,
|
||||
dataFilter: { enabled: true, filters: [{ columnName: "wop_id", operator: "equals", value: w.id }] },
|
||||
autoFilter: true,
|
||||
});
|
||||
const rows: any[] = wr.data?.data?.data || wr.data?.data?.rows || [];
|
||||
const sum = rows.reduce(
|
||||
(a, r) => ({
|
||||
good: a.good + (Number(r.good_qty) || 0),
|
||||
defect: a.defect + (Number(r.defect_qty) || 0),
|
||||
input: a.input + (Number(r.input_qty) || 0),
|
||||
}),
|
||||
{ good: 0, defect: 0, input: 0 },
|
||||
);
|
||||
if (sum.good > 0 || sum.defect > 0 || sum.input > 0) woprAgg.set(w.id, sum);
|
||||
} catch { /* skip */ }
|
||||
}
|
||||
const enriched = wopRows.map((w) => {
|
||||
const agg = woprAgg.get(w.id);
|
||||
if (!agg) return w;
|
||||
return { ...w, good_qty: agg.good, defect_qty: agg.defect, input_qty: agg.input };
|
||||
});
|
||||
setProcessData(enriched);
|
||||
} catch { setProcessData([]); }
|
||||
finally { setProcessLoading(false); }
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
|
||||
import { Sheet, SheetContent, SheetTrigger, SheetHeader, SheetTitle } from "@/components/ui/sheet";
|
||||
import { Menu } from "lucide-react";
|
||||
import { MenuItem } from "@/types/menu";
|
||||
import { LAYOUT_CONFIG } from "@/constants/layout";
|
||||
@@ -44,6 +44,9 @@ export function SideMenu({
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent side="left" className="w-64 p-0">
|
||||
<SheetHeader className="sr-only">
|
||||
<SheetTitle>메뉴</SheetTitle>
|
||||
</SheetHeader>
|
||||
<div className="flex h-full flex-col">
|
||||
<div className="border-b p-4">
|
||||
<h2 className="font-semibold">{LAYOUT_CONFIG.COMPANY_NAME}</h2>
|
||||
|
||||
@@ -35,11 +35,12 @@ function CommandDialog({
|
||||
}) {
|
||||
return (
|
||||
<Dialog {...props}>
|
||||
<DialogHeader className="sr-only">
|
||||
<DialogTitle>{title}</DialogTitle>
|
||||
<DialogDescription>{description}</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogContent className={cn("overflow-hidden p-0", className)} showCloseButton={showCloseButton}>
|
||||
{/* DialogTitle은 DialogContent 내부에 있어야 Radix UI가 a11y 인식 (sr-only로 시각적 숨김) */}
|
||||
<DialogHeader className="sr-only">
|
||||
<DialogTitle>{title}</DialogTitle>
|
||||
<DialogDescription>{description}</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Command className="[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
||||
{children}
|
||||
</Command>
|
||||
|
||||
Reference in New Issue
Block a user