/** * 선택 개소 상세 정보 패널 * * - 제품 정보 (제품명, 오픈사이즈, 제작사이즈, 산출중량, 산출면적, 수량) * - 필수 설정 (가이드레일, 전원, 제어기) * - 탭: 본체(스크린/슬랫), 절곡품-가이드레일, 절곡품-케이스, 절곡품-하단마감재, 모터&제어기, 부자재 * - 탭별 품목 테이블 (각 탭마다 다른 컬럼 구조) */ "use client"; import { useState, useMemo } from "react"; import { Package, Settings, Plus, Trash2 } from "lucide-react"; import { Badge } from "../ui/badge"; import { Button } from "../ui/button"; import { Input } from "../ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "../ui/select"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "../ui/table"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs"; import { ItemSearchModal } from "./ItemSearchModal"; // 납품길이 옵션 const DELIVERY_LENGTH_OPTIONS = [ { value: "3000", label: "3000" }, { value: "4000", label: "4000" }, { value: "5000", label: "5000" }, { value: "6000", label: "6000" }, ]; // 목데이터 - 탭별 품목 아이템 (각 탭마다 다른 구조) const MOCK_BOM_ITEMS = { // 본체 (스크린/슬랫): 품목명, 제작사이즈, 수량, 작업 body: [ { id: "b1", item_name: "실리카 스크린", manufacture_size: "5280*3280", quantity: 1, unit: "EA", total_price: 1061676 }, ], // 절곡품 - 가이드레일: 품목명, 재질, 규격, 납품길이, 수량, 작업 "guide-rail": [ { id: "g1", item_name: "벽면형 마감재", material: "알루미늄", spec: "50mm", delivery_length: "4000", quantity: 2, unit: "EA", total_price: 84048 }, { id: "g2", item_name: "본체 가이드 레일", material: "스틸", spec: "20mm", delivery_length: "4000", quantity: 2, unit: "EA", total_price: 32508 }, ], // 절곡품 - 케이스: 품목명, 재질, 규격, 납품길이, 수량, 작업 case: [ { id: "c1", item_name: "전면부 케이스", material: "알루미늄", spec: "30mm", delivery_length: "4000", quantity: 1, unit: "EA", total_price: 30348 }, ], // 절곡품 - 하단마감재: 품목명, 재질, 규격, 납품길이, 수량, 작업 bottom: [ { id: "bt1", item_name: "하단 하우징", material: "스틸", spec: "40mm", delivery_length: "4000", quantity: 1, unit: "EA", total_price: 15420 }, ], // 모터 & 제어기: 품목명, 유형, 사양, 수량, 작업 motor: [ { id: "m1", item_name: "직류 모터", type: "220V", spec: "1/2HP", quantity: 1, unit: "EA", total_price: 250000 }, { id: "m2", item_name: "제어기", type: "디지털", spec: "", quantity: 1, unit: "EA", total_price: 150000 }, ], // 부자재: 품목명, 규격, 납품길이, 수량, 작업 accessory: [ { id: "a1", item_name: "각파이프 25mm", spec: "25*25*2.0t", delivery_length: "4000", quantity: 2, unit: "EA", total_price: 17000 }, { id: "a2", item_name: "플랫바 20mm", spec: "20*3.0t", delivery_length: "4000", quantity: 1, unit: "EA", total_price: 4200 }, ], }; import type { LocationItem } from "./QuoteRegistrationV2"; import type { FinishedGoods } from "./actions"; // ============================================================================= // 상수 // ============================================================================= // 가이드레일 설치 유형 const GUIDE_RAIL_TYPES = [ { value: "wall", label: "벽면형" }, { value: "floor", label: "측면형" }, ]; // 모터 전원 const MOTOR_POWERS = [ { value: "single", label: "단상(220V)" }, { value: "three", label: "삼상(380V)" }, ]; // 연동제어기 const CONTROLLERS = [ { value: "basic", label: "단독" }, { value: "smart", label: "연동" }, { value: "premium", label: "매립형-뒷박스포함" }, ]; // 탭 정의 (6개) const DETAIL_TABS = [ { value: "body", label: "본체 (스크린/슬랫)" }, { value: "guide-rail", label: "절곡품 - 가이드레일" }, { value: "case", label: "절곡품 - 케이스" }, { value: "bottom", label: "절곡품 - 하단마감재" }, { value: "motor", label: "모터 & 제어기" }, { value: "accessory", label: "부자재" }, ]; // ============================================================================= // Props // ============================================================================= interface LocationDetailPanelProps { location: LocationItem | null; onUpdateLocation: (locationId: string, updates: Partial) => void; finishedGoods: FinishedGoods[]; disabled?: boolean; } // ============================================================================= // 컴포넌트 // ============================================================================= export function LocationDetailPanel({ location, onUpdateLocation, finishedGoods, disabled = false, }: LocationDetailPanelProps) { // --------------------------------------------------------------------------- // 상태 // --------------------------------------------------------------------------- const [activeTab, setActiveTab] = useState("body"); const [itemSearchOpen, setItemSearchOpen] = useState(false); // --------------------------------------------------------------------------- // 계산된 값 // --------------------------------------------------------------------------- // 제품 정보 const product = useMemo(() => { if (!location?.productCode) return null; return finishedGoods.find((fg) => fg.item_code === location.productCode); }, [location?.productCode, finishedGoods]); // BOM 아이템을 탭별로 분류 (목데이터 사용) const bomItemsByTab = useMemo(() => { // bomResult가 없으면 목데이터 사용 if (!location?.bomResult?.items) { return MOCK_BOM_ITEMS; } const items = location.bomResult.items; const result: Record = { body: [], "guide-rail": [], case: [], bottom: [], }; items.forEach((item) => { const processGroup = item.process_group?.toLowerCase() || ""; if (processGroup.includes("본체") || processGroup.includes("스크린") || processGroup.includes("슬랫")) { result.body.push(item); } else if (processGroup.includes("가이드") || processGroup.includes("레일")) { result["guide-rail"].push(item); } else if (processGroup.includes("케이스")) { result.case.push(item); } else if (processGroup.includes("하단") || processGroup.includes("마감")) { result.bottom.push(item); } else { // 기타 항목은 본체에 포함 result.body.push(item); } }); return result; }, [location?.bomResult?.items]); // 탭별 소계 const tabSubtotals = useMemo(() => { const result: Record = {}; Object.entries(bomItemsByTab).forEach(([tab, items]) => { result[tab] = items.reduce((sum, item) => sum + (item.total_price || 0), 0); }); return result; }, [bomItemsByTab]); // --------------------------------------------------------------------------- // 핸들러 // --------------------------------------------------------------------------- const handleFieldChange = (field: keyof LocationItem, value: string | number) => { if (!location || disabled) return; onUpdateLocation(location.id, { [field]: value }); }; // --------------------------------------------------------------------------- // 렌더링: 빈 상태 // --------------------------------------------------------------------------- if (!location) { return (

개소를 선택해주세요

왼쪽 목록에서 개소를 선택하면 상세 정보가 표시됩니다

); } // --------------------------------------------------------------------------- // 렌더링: 상세 정보 // --------------------------------------------------------------------------- return (
{/* 헤더 */}

{location.floor} / {location.code}

제품명: {location.productCode} {location.bomResult && ( 산출완료 )}
{/* 제품 정보 */}
{/* 오픈사이즈 */}
오픈사이즈
handleFieldChange("openWidth", parseFloat(e.target.value) || 0)} disabled={disabled} className="w-24 h-8 text-center font-bold" /> × handleFieldChange("openHeight", parseFloat(e.target.value) || 0)} disabled={disabled} className="w-24 h-8 text-center font-bold" /> {!disabled && ( 수정 )}
{/* 제작사이즈, 산출중량, 산출면적, 수량 */}
제작사이즈

{location.manufactureWidth || location.openWidth + 280} × {location.manufactureHeight || location.openHeight + 280}

산출중량

{location.weight?.toFixed(1) || "-"} kg

산출면적

{location.area?.toFixed(1) || "-"}

수량 handleFieldChange("quantity", parseInt(e.target.value) || 1)} disabled={disabled} className="w-24 h-7 text-center font-semibold" />
{/* 필수 설정 (읽기 전용) */}

필수 설정

{GUIDE_RAIL_TYPES.find(t => t.value === location.guideRailType)?.label || location.guideRailType}
{MOTOR_POWERS.find(p => p.value === location.motorPower)?.label || location.motorPower}
{CONTROLLERS.find(c => c.value === location.controller)?.label || location.controller}
{/* 탭 및 품목 테이블 */}
{/* 탭 목록 - 스크롤 가능 */}
{DETAIL_TABS.map((tab) => ( {tab.label} ))}
{/* 본체 (스크린/슬랫) 탭 */}
품목명 제작사이즈 수량 작업 {bomItemsByTab.body.map((item: any) => ( {item.item_name} {item.manufacture_size || "-"} ))}
{/* 품목 추가 버튼 + 안내 */}
💡 금액은 아래 견적금액요약에서 확인하세요
{/* 절곡품 - 가이드레일, 케이스, 하단마감재 탭 */} {["guide-rail", "case", "bottom"].map((tabValue) => (
품목명 재질 규격 납품길이 수량 작업 {bomItemsByTab[tabValue]?.map((item: any) => ( {item.item_name} {item.material || "-"} {item.spec || "-"} ))}
{/* 품목 추가 버튼 + 안내 */}
💡 금액은 아래 견적금액요약에서 확인하세요
))} {/* 모터 & 제어기 탭 */}
품목명 유형 사양 수량 작업 {bomItemsByTab.motor?.map((item: any) => ( {item.item_name} {item.type || "-"} {item.spec || "-"} ))}
{/* 품목 추가 버튼 + 안내 */}
💡 금액은 아래 견적금액요약에서 확인하세요
{/* 부자재 탭 */}
품목명 규격 납품길이 수량 작업 {bomItemsByTab.accessory?.map((item: any) => ( {item.item_name} {item.spec || "-"} ))}
{/* 품목 추가 버튼 + 안내 */}
💡 금액은 아래 견적금액요약에서 확인하세요
{/* 금액 안내 */} {!location.bomResult && (
💡 금액은 아래 견적금액요약에서 확인하세요
)} {/* 품목 검색 모달 */} { console.log(`[테스트] 품목 선택: ${item.code} - ${item.name} (탭: ${activeTab})`); }} tabLabel={DETAIL_TABS.find((t) => t.value === activeTab)?.label} />
); }