diff options
Diffstat (limited to 'lib/po/vendor-table/vendor-po-items-dialog.tsx')
| -rw-r--r-- | lib/po/vendor-table/vendor-po-items-dialog.tsx | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/lib/po/vendor-table/vendor-po-items-dialog.tsx b/lib/po/vendor-table/vendor-po-items-dialog.tsx new file mode 100644 index 00000000..d3b33371 --- /dev/null +++ b/lib/po/vendor-table/vendor-po-items-dialog.tsx @@ -0,0 +1,199 @@ +"use client" + +import * as React from "react" +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table" +import { Badge } from "@/components/ui/badge" +import { Skeleton } from "@/components/ui/skeleton" +import { VendorPO, VendorPOItem } from "./types" +import { getVendorPOItemsByContractNo } from "./service" + +interface VendorPOItemsDialogProps { + open: boolean + onOpenChange: (open: boolean) => void + po: VendorPO | null +} + +export function VendorPOItemsDialog({ open, onOpenChange, po }: VendorPOItemsDialogProps) { + const [items, setItems] = React.useState<VendorPOItem[]>([]) + const [loading, setLoading] = React.useState(false) + const [error, setError] = React.useState<string | null>(null) + + // 상세품목 데이터 로드 + React.useEffect(() => { + if (!open || !po) { + setItems([]) + setError(null) + return + } + + const loadItems = async () => { + setLoading(true) + setError(null) + try { + const vendorPOItems = await getVendorPOItemsByContractNo(po.contractNo) + setItems(vendorPOItems) + } catch (err) { + console.error("Failed to load vendor PO items:", err) + setError("상세품목을 불러오는 중 오류가 발생했습니다.") + } finally { + setLoading(false) + } + } + + loadItems() + }, [open, po]) + + if (!po) return null + + return ( + <Dialog open={open} onOpenChange={onOpenChange}> + <DialogContent className="max-w-[95vw] max-h-[90vh] w-full flex flex-col"> + <DialogHeader className="flex-shrink-0"> + <DialogTitle className="text-lg font-semibold"> + 상세품목 현황 - {po.contractNo} + </DialogTitle> + <DialogDescription> + {po.contractName} ({items.length}개 품목) + </DialogDescription> + </DialogHeader> + + <div className="flex-1 overflow-hidden"> + {loading ? ( + <div className="space-y-4"> + <div className="text-center py-4 text-muted-foreground"> + 상세품목을 불러오는 중... + </div> + <div className="space-y-2"> + {Array.from({ length: 3 }).map((_, i) => ( + <Skeleton key={i} className="h-12 w-full" /> + ))} + </div> + </div> + ) : error ? ( + <div className="text-center py-8 text-destructive"> + {error} + </div> + ) : items.length === 0 ? ( + <div className="text-center py-8 text-muted-foreground"> + 등록된 상세품목이 없습니다. + </div> + ) : ( + <div className="overflow-auto max-h-[60vh]"> + <Table> + <TableHeader className="sticky top-0 bg-background z-10"> + <TableRow> + <TableHead className="min-w-[120px] whitespace-nowrap">PO/계약번호</TableHead> + <TableHead className="min-w-[100px] whitespace-nowrap">품번</TableHead> + <TableHead className="min-w-[100px] whitespace-nowrap">P/R번호</TableHead> + <TableHead className="min-w-[120px] whitespace-nowrap">자재그룹(명)</TableHead> + <TableHead className="min-w-[100px] whitespace-nowrap">단가기준</TableHead> + <TableHead className="min-w-[100px] whitespace-nowrap">자재번호</TableHead> + <TableHead className="min-w-[200px] whitespace-nowrap">품목/자재내역</TableHead> + <TableHead className="min-w-[200px] whitespace-nowrap">자재내역사양</TableHead> + <TableHead className="min-w-[120px] whitespace-nowrap">설계자재번호</TableHead> + <TableHead className="min-w-[100px] whitespace-nowrap">Fitting No.</TableHead> + <TableHead className="min-w-[80px] whitespace-nowrap">Cert.</TableHead> + <TableHead className="min-w-[80px] whitespace-nowrap">재질</TableHead> + <TableHead className="min-w-[150px] whitespace-nowrap">규격</TableHead> + <TableHead className="min-w-[80px] text-right whitespace-nowrap">수량</TableHead> + <TableHead className="min-w-[80px] whitespace-nowrap">수량단위</TableHead> + <TableHead className="min-w-[80px] text-right whitespace-nowrap">중량</TableHead> + <TableHead className="min-w-[80px] whitespace-nowrap">중량단위</TableHead> + <TableHead className="min-w-[100px] text-right whitespace-nowrap">총중량</TableHead> + <TableHead className="min-w-[100px] text-right whitespace-nowrap">단가기준</TableHead> + <TableHead className="min-w-[80px] whitespace-nowrap">단가단위</TableHead> + <TableHead className="min-w-[100px] whitespace-nowrap">가격단위값</TableHead> + <TableHead className="min-w-[120px] text-right whitespace-nowrap">PO계약금액</TableHead> + <TableHead className="min-w-[100px] text-right whitespace-nowrap">조정금액</TableHead> + <TableHead className="min-w-[100px] whitespace-nowrap">납기일자</TableHead> + <TableHead className="min-w-[80px] whitespace-nowrap">VAT구분</TableHead> + <TableHead className="min-w-[120px] whitespace-nowrap">철의장 SPEC</TableHead> + <TableHead className="min-w-[100px] whitespace-nowrap">P/R 담당자</TableHead> + </TableRow> + </TableHeader> + <TableBody> + {items.map((item, index) => ( + <TableRow key={`${item.contractNo}-${item.itemNo}-${index}`}> + <TableCell className="font-medium">{item.contractNo || '-'}</TableCell> + <TableCell>{item.itemNo || '-'}</TableCell> + <TableCell>{item.prNo || '-'}</TableCell> + <TableCell>{item.materialGroup || '-'}</TableCell> + <TableCell>{item.priceStandard || '-'}</TableCell> + <TableCell className="font-mono text-sm">{item.materialNo || '-'}</TableCell> + <TableCell className="max-w-[200px]"> + <div className="truncate" title={item.itemDescription || ''}> + {item.itemDescription || '-'} + </div> + </TableCell> + <TableCell className="max-w-[200px]"> + <div className="truncate" title={item.materialSpec || ''}> + {item.materialSpec || '-'} + </div> + </TableCell> + <TableCell>{item.designMaterialNo || '-'}</TableCell> + <TableCell>{item.fittingNo || '-'}</TableCell> + <TableCell>{item.cert || '-'}</TableCell> + <TableCell>{item.material || '-'}</TableCell> + <TableCell>{item.specification || '-'}</TableCell> + <TableCell className="text-right font-mono"> + {item.quantity?.toLocaleString() || '-'} + </TableCell> + <TableCell>{item.quantityUnit || '-'}</TableCell> + <TableCell className="text-right font-mono"> + {item.weight ? item.weight.toLocaleString() : '-'} + </TableCell> + <TableCell>{item.weightUnit || '-'}</TableCell> + <TableCell className="text-right font-mono"> + {item.totalWeight ? item.totalWeight.toLocaleString() : '-'} + </TableCell> + <TableCell className="text-right font-mono"> + {item.unitPrice?.toLocaleString() || '-'} + </TableCell> + <TableCell>{item.priceUnit || '-'}</TableCell> + <TableCell>{item.priceUnitValue || '-'}</TableCell> + <TableCell className="text-right font-mono font-semibold"> + {item.contractAmount?.toLocaleString() || '-'} + </TableCell> + <TableCell className="text-right font-mono"> + {item.adjustmentAmount ? item.adjustmentAmount.toLocaleString() : '-'} + </TableCell> + <TableCell>{item.deliveryDate || '-'}</TableCell> + <TableCell>{item.vatType || '-'}</TableCell> + <TableCell>{item.steelSpec || '-'}</TableCell> + <TableCell>{item.prManager || '-'}</TableCell> + </TableRow> + ))} + </TableBody> + </Table> + </div> + )} + </div> + + {items.length > 0 && ( + <div className="flex justify-between items-center pt-4 border-t flex-shrink-0"> + <div className="text-sm text-muted-foreground"> + 총 {items.length}개 품목 + </div> + <div className="text-sm font-medium"> + 총 계약금액: {items.reduce((sum, item) => sum + item.contractAmount, 0).toLocaleString()} 원 + </div> + </div> + )} + </DialogContent> + </Dialog> + ) +} |
