/** * 품목 상세 조회 Client Component * * 품목 정보를 읽기 전용으로 표시 */ 'use client'; import { useRouter } from 'next/navigation'; import type { ItemMaster } from '@/types/item'; import { ITEM_TYPE_LABELS, PART_TYPE_LABELS, PART_USAGE_LABELS, PRODUCT_CATEGORY_LABELS } from '@/types/item'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Label } from '@/components/ui/label'; import { Card, CardContent, CardHeader, CardTitle, } from '@/components/ui/card'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { ArrowLeft, Edit, Package, FileImage, Download, FileText, Check, Calendar } from 'lucide-react'; import { downloadFileById } from '@/lib/utils/fileDownload'; import { isNextRedirectError } from '@/lib/utils/redirect-error'; import { useMenuStore } from '@/store/menuStore'; interface ItemDetailClientProps { item: ItemMaster; } /** * 품목 유형별 Badge 반환 */ function getItemTypeBadge(itemType: string) { const badges: Record = { FG: { className: 'bg-purple-50 text-purple-700 border-purple-200' }, PT: { className: 'bg-orange-50 text-orange-700 border-orange-200' }, SM: { className: 'bg-green-50 text-green-700 border-green-200' }, RM: { className: 'bg-blue-50 text-blue-700 border-blue-200' }, CS: { className: 'bg-gray-50 text-gray-700 border-gray-200' }, }; const config = badges[itemType] || { className: '' }; return ( {ITEM_TYPE_LABELS[itemType as keyof typeof ITEM_TYPE_LABELS]} ); } /** * 조립품 품목코드 포맷팅 (하이픈 이후 제거) */ function formatItemCodeForAssembly(item: ItemMaster): string { return item.itemCode; } /** * 파일 다운로드 핸들러 (Blob 방식) */ async function handleFileDownload(fileId: number | undefined, fileName?: string): Promise { if (!fileId) return; try { await downloadFileById(fileId, fileName); } catch (error) { if (isNextRedirectError(error)) throw error; console.error('[ItemDetailClient] 다운로드 실패:', error); alert('파일 다운로드에 실패했습니다.'); } } /** * Storage 경로를 전체 URL로 변환 (전개도 이미지용) * - 이미 전체 URL인 경우 그대로 반환 * - 상대 경로인 경우 API URL + /storage/ 붙여서 반환 */ function getStorageUrl(path: string | undefined): string | null { if (!path) return null; // 이미 전체 URL인 경우 if (path.startsWith('http://') || path.startsWith('https://')) { return path; } // 상대 경로인 경우 const apiUrl = process.env.NEXT_PUBLIC_API_URL || ''; return `${apiUrl}/storage/${path}`; } export default function ItemDetailClient({ item }: ItemDetailClientProps) { const router = useRouter(); const sidebarCollapsed = useMenuStore((state) => state.sidebarCollapsed); return (
{/* 헤더 */}

품목 상세 정보

등록된 품목 정보를 확인합니다

{/* 기본 정보 */} 기본 정보

{formatItemCodeForAssembly(item)}

{item.itemName}

{getItemTypeBadge(item.itemType)}

{item.itemType === "PT" && item.partType && (

{item.partType === 'ASSEMBLY' ? '조립 부품' : item.partType === 'BENDING' ? '절곡 부품' : item.partType === 'PURCHASED' ? '구매 부품' : item.partType}

)} {item.itemType === "PT" && item.partType === "BENDING" && item.partUsage && (

{item.partUsage === "GUIDE_RAIL" ? "가이드레일용" : item.partUsage === "BOTTOM_FINISH" ? "하단마감재용" : item.partUsage === "CASE" ? "케이스용" : item.partUsage === "DOOR" ? "도어용" : item.partUsage === "BRACKET" ? "브라켓용" : item.partUsage === "GENERAL" ? "범용 (공통 부품)" : item.partUsage}

)} {item.itemType !== "FG" && item.partType !== 'ASSEMBLY' && item.specification && (

{item.specification}

)} {item.itemType !== "FG" && (

{item.unit}

)} {/* 버전 정보 */}
V{item.currentRevision || 0}

{(item.revisions?.length || 0)}회

{new Date(item.createdAt).toLocaleDateString('ko-KR')}

{/* 제품(FG) 전용 정보 - 내용이 있을 때만 표시 */} {item.itemType === 'FG' && (item.productCategory || item.lotAbbreviation || item.note) && ( 제품 정보
{item.productCategory && (

{PRODUCT_CATEGORY_LABELS[item.productCategory]}

)} {item.lotAbbreviation && (

{item.lotAbbreviation}

)}
{item.note && (

{item.note}

)}
)} {/* 조립 부품 세부 정보 */} {item.itemType === 'PT' && item.partType === 'ASSEMBLY' && ( 조립 부품 세부 정보
{/* 품목명 - itemName 표시 */}

{item.itemName}

{/* 설치 유형 */}

{item.installationType ? ( {item.installationType === 'wall' ? '벽면형 (R)' : item.installationType === 'side' ? '측면형 (S)' : item.installationType === 'steel' ? '스틸 (B)' : item.installationType === 'iron' ? '철재 (T)' : item.installationType} ) : ( - )}

{/* 마감 */}

{item.assemblyType ? ( {item.assemblyType} ) : ( - )}

{/* 길이 */}

{item.assemblyLength || item.length ? `${item.assemblyLength || item.length}mm` : '-'}

{/* 측면 규격 */}

{item.sideSpecWidth && item.sideSpecHeight ? `${item.sideSpecWidth} × ${item.sideSpecHeight}mm` : '-'}

{/* 재질 (있으면) */} {item.material && (

{item.material}

)}
)} {/* 가이드레일 세부 정보 */} {item.category3 === "가이드레일" && item.guideRailModelType && ( 가이드레일 세부 정보
{item.guideRailModelType && (

{item.guideRailModelType}

)} {item.guideRailModel && (

{item.guideRailModel}

)}
)} {/* 절곡품/조립품 전개도 정보 - 조립부품은 항상 표시 */} {item.itemType === 'PT' && (item.partType === 'BENDING' || item.partType === 'ASSEMBLY') && ( {item.partType === 'ASSEMBLY' ? '조립품 전개도 (바라시)' : '절곡품 전개도 (바라시)'} {/* 전개도 이미지 - 파일 ID가 있으면 프록시로 로드 */} {(item.bendingDiagramFileId || item.bendingDiagram) ? (
{/* eslint-disable-next-line @next/next/no-img-element */} 전개도 { const target = e.target as HTMLImageElement; target.style.display = 'none'; target.parentElement?.insertAdjacentHTML( 'beforeend', '

이미지를 불러올 수 없습니다

' ); }} />
{item.bendingDiagramFileId && (
)}
) : (
등록된 전개도 이미지가 없습니다.
)} {/* 전개도 상세 데이터 */} {item.bendingDetails && item.bendingDetails.length > 0 && (
번호 입력 연신율 연신율계산후 합계 음영 A각 {item.bendingDetails.map((detail, detailIndex) => { const calculated = detail.input + detail.elongation; let sum = 0; for (let i = 0; i <= detailIndex; i++) { const d = item.bendingDetails![i]; sum += d.input + d.elongation; } return ( {detail.no} {detail.input} {detail.elongation} {calculated} {sum} {detail.shaded ? : "-"} {detail.aAngle || "-"} ); })}

최종 전개 길이:{" "} {item.bendingDetails.reduce((sum, d) => sum + d.input + d.elongation, 0)} mm

)}
)} {/* 제품(FG) 인정 정보 및 첨부 파일 */} {item.itemType === 'FG' && (item.certificationNumber || item.specificationFile || item.certificationFile) && ( 인정 정보 및 첨부 파일 {/* 인정 정보 */} {item.certificationNumber && (

{item.certificationNumber}

{item.certificationStartDate && (

{new Date(item.certificationStartDate).toLocaleDateString('ko-KR')}

)} {item.certificationEndDate && (

{new Date(item.certificationEndDate).toLocaleDateString('ko-KR')}

)}
)} {/* 첨부 파일 */}
{/* 시방서 */}
{item.specificationFile ? (
{item.specificationFileName || '시방서 파일'}
) : (

등록된 시방서가 없습니다.

)}
{/* 인정서 */}
{item.certificationFile ? (
{item.certificationFileName || '인정서 파일'}
) : (

등록된 인정서가 없습니다.

)}
)} {/* BOM 정보 - 절곡 부품은 제외 */} {(item.itemType === 'FG' || (item.itemType === 'PT' && item.partType !== 'BENDING')) && item.bom && item.bom.length > 0 && (
부품 구성 (BOM) 총 {item.bom.length}개 품목
번호 품목코드 품목명 수량 단위 {item.bom.map((line, index) => ( {index + 1} {line.childItemCode}
{line.childItemName} {line.isBending && ( 절곡품 )}
{line.quantity} {line.unit}
))}
)} {/* 하단 액션 버튼 (sticky) */}
); }