fix: [생산지시] BOM 공정 분류 UI 수정 + 접이식 카드
- BOM types/actions: 필드 매핑 수정 (unit, quantity, unitPrice, totalPrice, nodeName)
- BOM UI: 접이식(collapsible) Card + ChevronDown 토글
- 테이블 컬럼 변경: 품목코드, 품목명, 규격, 단위, 수량, 단가, 금액, 개소
- 중복 key 수정: `${item.id}-${idx}` 패턴 적용
This commit is contained in:
@@ -30,6 +30,7 @@ import {
|
||||
Circle,
|
||||
Activity,
|
||||
Play,
|
||||
ChevronDown,
|
||||
} from "lucide-react";
|
||||
import { PageLayout } from "@/components/organisms/PageLayout";
|
||||
import { PageHeader } from "@/components/organisms/PageHeader";
|
||||
@@ -200,6 +201,7 @@ export default function ProductionOrderDetailPage() {
|
||||
const [isCreateWorkOrderDialogOpen, setIsCreateWorkOrderDialogOpen] = useState(false);
|
||||
const [isSuccessDialogOpen, setIsSuccessDialogOpen] = useState(false);
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
const [bomOpen, setBomOpen] = useState(false);
|
||||
|
||||
// 데이터 로드
|
||||
const loadDetail = async () => {
|
||||
@@ -335,68 +337,69 @@ export default function ProductionOrderDetailPage() {
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* BOM 품목별 공정 분류 */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">BOM 품목별 공정 분류</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-6">
|
||||
{detail.bomProcessGroups.length === 0 ? (
|
||||
<div className="text-center py-8">
|
||||
<p className="text-muted-foreground text-sm">
|
||||
BOM 계산 결과가 없습니다.
|
||||
</p>
|
||||
{/* BOM 품목별 공정 분류 (접이식) */}
|
||||
{detail.bomProcessGroups.length > 0 && (
|
||||
<Card>
|
||||
<CardHeader
|
||||
className="cursor-pointer select-none"
|
||||
onClick={() => setBomOpen((prev) => !prev)}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<CardTitle className="text-base">
|
||||
BOM 품목별 공정 분류
|
||||
<span className="ml-2 text-sm font-normal text-muted-foreground">
|
||||
({detail.bomProcessGroups.length}개 공정)
|
||||
</span>
|
||||
</CardTitle>
|
||||
<ChevronDown
|
||||
className={`h-5 w-5 text-muted-foreground transition-transform ${
|
||||
bomOpen ? "rotate-180" : ""
|
||||
}`}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<p className="text-sm font-medium text-muted-foreground border-b pb-2">
|
||||
절곡 부품 전개도 정보
|
||||
</p>
|
||||
|
||||
</CardHeader>
|
||||
{bomOpen && (
|
||||
<CardContent className="space-y-6 pt-0">
|
||||
{detail.bomProcessGroups.map((group) => (
|
||||
<div key={group.processName} className="space-y-2">
|
||||
<h4 className="text-sm font-semibold">
|
||||
{group.processName}
|
||||
{group.sizeSpec && (
|
||||
<span className="ml-2 text-muted-foreground font-normal">
|
||||
{group.sizeSpec}
|
||||
</span>
|
||||
)}
|
||||
<h4 className="text-sm font-semibold flex items-center gap-2">
|
||||
<Badge variant="outline">{group.processName}</Badge>
|
||||
<span className="text-muted-foreground font-normal text-xs">
|
||||
{group.items.length}건
|
||||
</span>
|
||||
</h4>
|
||||
|
||||
<div className="border rounded-lg overflow-hidden">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow className="bg-gray-50">
|
||||
<TableHead className="w-[60px] text-center">항목코드</TableHead>
|
||||
<TableHead>세부품명</TableHead>
|
||||
<TableHead>품목코드</TableHead>
|
||||
<TableHead>품목명</TableHead>
|
||||
<TableHead>규격</TableHead>
|
||||
<TableHead>LOT NO</TableHead>
|
||||
<TableHead className="text-right">필요수량</TableHead>
|
||||
<TableHead className="text-center w-[60px]">수량</TableHead>
|
||||
<TableHead className="text-center">단위</TableHead>
|
||||
<TableHead className="text-right">수량</TableHead>
|
||||
<TableHead className="text-right">단가</TableHead>
|
||||
<TableHead className="text-right">금액</TableHead>
|
||||
<TableHead>개소</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{group.items.map((item, idx) => (
|
||||
<TableRow key={`${item.id}-${idx}`}>
|
||||
<TableCell className="text-center font-medium">
|
||||
{item.itemCode}
|
||||
<TableCell>
|
||||
<code className="text-xs bg-gray-100 px-1.5 py-0.5 rounded">
|
||||
{item.itemCode}
|
||||
</code>
|
||||
</TableCell>
|
||||
<TableCell>{item.itemName}</TableCell>
|
||||
<TableCell className="text-muted-foreground">
|
||||
{item.spec || "-"}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{item.lotNo ? (
|
||||
<code className="text-xs bg-gray-100 px-1.5 py-0.5 rounded">
|
||||
{item.lotNo}
|
||||
</code>
|
||||
) : "-"}
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
{item.requiredQty > 0 ? formatNumber(item.requiredQty) : "-"}
|
||||
</TableCell>
|
||||
<TableCell className="text-center">{item.qty}</TableCell>
|
||||
<TableCell className="text-center">{item.unit || "-"}</TableCell>
|
||||
<TableCell className="text-right">{formatNumber(item.quantity)}</TableCell>
|
||||
<TableCell className="text-right">{formatNumber(item.unitPrice)}</TableCell>
|
||||
<TableCell className="text-right">{formatNumber(item.totalPrice)}</TableCell>
|
||||
<TableCell className="text-muted-foreground text-xs">{item.nodeName || "-"}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
@@ -404,10 +407,10 @@ export default function ProductionOrderDetailPage() {
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
</CardContent>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* 작업지시서 목록 */}
|
||||
<Card>
|
||||
|
||||
@@ -68,10 +68,12 @@ function transformDetailApiToFrontend(data: ApiProductionOrderDetail): Productio
|
||||
id: item.id,
|
||||
itemCode: item.item_code,
|
||||
itemName: item.item_name,
|
||||
spec: item.spec,
|
||||
lotNo: item.lot_no,
|
||||
requiredQty: item.required_qty,
|
||||
qty: item.qty,
|
||||
spec: item.spec || item.specification || '',
|
||||
unit: item.unit || '',
|
||||
quantity: item.quantity ?? 0,
|
||||
unitPrice: item.unit_price ?? 0,
|
||||
totalPrice: item.total_price ?? 0,
|
||||
nodeName: item.node_name || '',
|
||||
})),
|
||||
})),
|
||||
};
|
||||
|
||||
@@ -90,9 +90,11 @@ export interface ApiBomItem {
|
||||
item_code: string;
|
||||
item_name: string;
|
||||
spec: string;
|
||||
lot_no: string;
|
||||
required_qty: number;
|
||||
qty: number;
|
||||
unit: string;
|
||||
quantity: number;
|
||||
unit_price: number;
|
||||
total_price: number;
|
||||
node_name: string;
|
||||
}
|
||||
|
||||
// 프론트 상세 타입
|
||||
@@ -121,9 +123,11 @@ export interface BomItem {
|
||||
itemCode: string;
|
||||
itemName: string;
|
||||
spec: string;
|
||||
lotNo: string;
|
||||
requiredQty: number;
|
||||
qty: number;
|
||||
unit: string;
|
||||
quantity: number;
|
||||
unitPrice: number;
|
||||
totalPrice: number;
|
||||
nodeName: string;
|
||||
}
|
||||
|
||||
// 조회 파라미터
|
||||
|
||||
Reference in New Issue
Block a user