diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-18 00:23:40 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-18 00:23:40 +0000 |
| commit | cf8dac0c6490469dab88a560004b0c07dbd48612 (patch) | |
| tree | b9e76061e80d868331e6b4277deecb9086f845f3 /lib/itb/table/items-dialog.tsx | |
| parent | e5745fc0268bbb5770bc14a55fd58a0ec30b466e (diff) | |
(대표님) rfq, 계약, 서명 등
Diffstat (limited to 'lib/itb/table/items-dialog.tsx')
| -rw-r--r-- | lib/itb/table/items-dialog.tsx | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/lib/itb/table/items-dialog.tsx b/lib/itb/table/items-dialog.tsx new file mode 100644 index 00000000..dd688ce9 --- /dev/null +++ b/lib/itb/table/items-dialog.tsx @@ -0,0 +1,167 @@ +// components/purchase-requests/items-dialog.tsx +"use client"; + +import * as React from "react"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, + TableFooter, +} from "@/components/ui/table"; +import { Badge } from "@/components/ui/badge"; +import { Package } from "lucide-react"; + +interface Item { + id: string; + itemCode: string; + itemName: string; + specification: string; + quantity: number; + unit: string; + estimatedUnitPrice?: number; + remarks?: string; +} + +interface ItemsDialogProps { + requestId: number; + requestCode: string; + items: Item[] | any; + open: boolean; + onOpenChange: (open: boolean) => void; +} + +export function ItemsDialog({ + requestId, + requestCode, + items, + open, + onOpenChange, +}: ItemsDialogProps) { + // items가 없거나 배열이 아닌 경우 처리 + const itemList = React.useMemo(() => { + if (!items || !Array.isArray(items)) return []; + return items; + }, [items]); + + // 총액 계산 + const totalAmount = React.useMemo(() => { + return itemList.reduce((sum, item) => { + const subtotal = (item.quantity || 0) * (item.estimatedUnitPrice || 0); + return sum + subtotal; + }, 0); + }, [itemList]); + + // 총 수량 계산 + const totalQuantity = React.useMemo(() => { + return itemList.reduce((sum, item) => sum + (item.quantity || 0), 0); + }, [itemList]); + + return ( + <Dialog open={open} onOpenChange={onOpenChange}> + <DialogContent className="max-w-5xl max-h-[80vh] overflow-hidden flex flex-col"> + <DialogHeader> + <DialogTitle className="flex items-center gap-2"> + <Package className="h-5 w-5" /> + 품목 상세 정보 + </DialogTitle> + <DialogDescription> + 요청번호: {requestCode} | 총 {itemList.length}개 품목 + </DialogDescription> + </DialogHeader> + + <div className="flex-1 overflow-auto"> + {itemList.length === 0 ? ( + <div className="flex items-center justify-center h-32"> + <p className="text-muted-foreground">등록된 품목이 없습니다.</p> + </div> + ) : ( + <Table> + <TableHeader className="sticky top-0 bg-background"> + <TableRow> + <TableHead className="w-[50px]">번호</TableHead> + <TableHead className="w-[120px]">아이템 코드</TableHead> + <TableHead>아이템명</TableHead> + <TableHead>사양</TableHead> + <TableHead className="text-right w-[80px]">수량</TableHead> + <TableHead className="w-[60px]">단위</TableHead> + <TableHead className="text-right w-[120px]">예상 단가</TableHead> + <TableHead className="text-right w-[140px]">예상 금액</TableHead> + <TableHead className="w-[150px]">비고</TableHead> + </TableRow> + </TableHeader> + <TableBody> + {itemList.map((item, index) => { + const subtotal = (item.quantity || 0) * (item.estimatedUnitPrice || 0); + return ( + <TableRow key={item.id || index}> + <TableCell className="text-center text-muted-foreground"> + {index + 1} + </TableCell> + <TableCell className="font-mono text-sm"> + {item.itemCode} + </TableCell> + <TableCell className="font-medium"> + {item.itemName} + </TableCell> + <TableCell className="text-sm"> + {item.specification || "-"} + </TableCell> + <TableCell className="text-right font-medium"> + {item.quantity?.toLocaleString('ko-KR')} + </TableCell> + <TableCell className="text-center"> + {item.unit} + </TableCell> + <TableCell className="text-right"> + {item.estimatedUnitPrice + ? new Intl.NumberFormat('ko-KR').format(item.estimatedUnitPrice) + : "-"} + </TableCell> + <TableCell className="text-right font-medium"> + {subtotal > 0 + ? new Intl.NumberFormat('ko-KR').format(subtotal) + : "-"} + </TableCell> + <TableCell className="text-sm text-muted-foreground"> + {item.remarks || "-"} + </TableCell> + </TableRow> + ); + })} + </TableBody> + <TableFooter> + <TableRow className="bg-muted/50"> + <TableCell colSpan={4} className="font-medium"> + 합계 + </TableCell> + <TableCell className="text-right font-bold"> + {totalQuantity.toLocaleString('ko-KR')} + </TableCell> + <TableCell></TableCell> + <TableCell></TableCell> + <TableCell className="text-right font-bold text-lg"> + {new Intl.NumberFormat('ko-KR', { + style: 'currency', + currency: 'KRW' + }).format(totalAmount)} + </TableCell> + <TableCell></TableCell> + </TableRow> + </TableFooter> + </Table> + )} + </div> + </DialogContent> + </Dialog> + ); +}
\ No newline at end of file |
