import React, { useState } from 'react'; import { exportMaterialsToExcel } from '../../../utils/excelExport'; import api from '../../../api'; import { FilterableHeader, MaterialTable } from '../shared'; const FlangeMaterialsView = ({ materials, selectedMaterials, setSelectedMaterials, userRequirements, setUserRequirements, purchasedMaterials, fileId, user, onNavigate }) => { const [sortConfig, setSortConfig] = useState({ key: null, direction: 'asc' }); const [columnFilters, setColumnFilters] = useState({}); const [showFilterDropdown, setShowFilterDropdown] = useState(null); // 플랜지 정보 파싱 const parseFlangeInfo = (material) => { const description = material.original_description || ''; const flangeDetails = material.flange_details || {}; const flangeTypeMap = { 'WN': 'WELD NECK FLANGE', 'WELD_NECK': 'WELD NECK FLANGE', 'SO': 'SLIP ON FLANGE', 'SLIP_ON': 'SLIP ON FLANGE', 'SW': 'SOCKET WELD FLANGE', 'SOCKET_WELD': 'SOCKET WELD FLANGE', 'BLIND': 'BLIND FLANGE', 'REDUCING': 'REDUCING FLANGE', 'ORIFICE': 'ORIFICE FLANGE', 'SPECTACLE': 'SPECTACLE BLIND', 'PADDLE': 'PADDLE BLIND', 'SPACER': 'SPACER' }; const facingTypeMap = { 'RF': 'RAISED FACE', 'RAISED_FACE': 'RAISED FACE', 'FF': 'FLAT FACE', 'FLAT_FACE': 'FLAT FACE', 'RTJ': 'RING TYPE JOINT', 'RING_TYPE_JOINT': 'RING TYPE JOINT' }; const rawFlangeType = flangeDetails.flange_type || ''; const rawFacingType = flangeDetails.facing_type || ''; let displayType = flangeTypeMap[rawFlangeType] || rawFlangeType || '-'; let facingType = facingTypeMap[rawFacingType] || rawFacingType || '-'; // Description에서 추출 if (displayType === '-') { const desc = description.toUpperCase(); if (desc.includes('ORIFICE')) { displayType = 'ORIFICE FLANGE'; } else if (desc.includes('SPECTACLE')) { displayType = 'SPECTACLE BLIND'; } else if (desc.includes('PADDLE')) { displayType = 'PADDLE BLIND'; } else if (desc.includes('SPACER')) { displayType = 'SPACER'; } else if (desc.includes('REDUCING') || desc.includes('RED')) { displayType = 'REDUCING FLANGE'; } else if (desc.includes('BLIND')) { displayType = 'BLIND FLANGE'; } else if (desc.includes('WN')) { displayType = 'WELD NECK FLANGE'; } else if (desc.includes('SO')) { displayType = 'SLIP ON FLANGE'; } else if (desc.includes('SW')) { displayType = 'SOCKET WELD FLANGE'; } else { displayType = 'FLANGE'; } } if (facingType === '-') { const desc = description.toUpperCase(); if (desc.includes('RF')) { facingType = 'RAISED FACE'; } else if (desc.includes('FF')) { facingType = 'FLAT FACE'; } else if (desc.includes('RTJ')) { facingType = 'RING TYPE JOINT'; } } // 원본 설명에서 스케줄 추출 let schedule = '-'; const upperDesc = description.toUpperCase(); // SCH 40, SCH 80 등의 패턴 찾기 if (upperDesc.includes('SCH')) { const schMatch = description.match(/SCH\s*(\d+[A-Z]*)/i); if (schMatch && schMatch[1]) { schedule = `SCH ${schMatch[1]}`; } } // 압력 등급 추출 let pressure = '-'; const pressureMatch = description.match(/(\d+)LB/i); if (pressureMatch) { pressure = `${pressureMatch[1]}LB`; } return { type: 'FLANGE', subtype: displayType, // 풀네임 플랜지 타입 facing: facingType, // 새로 추가: 끝단처리 정보 size: material.size_spec || '-', pressure: flangeDetails.pressure_rating || pressure, schedule: schedule, grade: material.full_material_grade || material.material_grade || '-', quantity: Math.round(material.quantity || 0), unit: '개', isFlange: true // 플랜지 구분용 플래그 }; }; // 정렬 처리 const handleSort = (key) => { let direction = 'asc'; if (sortConfig.key === key && sortConfig.direction === 'asc') { direction = 'desc'; } setSortConfig({ key, direction }); }; // 필터링된 및 정렬된 자재 목록 const getFilteredAndSortedMaterials = () => { let filtered = materials.filter(material => { return Object.entries(columnFilters).every(([key, filterValue]) => { if (!filterValue) return true; const info = parseFlangeInfo(material); const value = info[key]?.toString().toLowerCase() || ''; return value.includes(filterValue.toLowerCase()); }); }); if (sortConfig.key) { filtered.sort((a, b) => { const aInfo = parseFlangeInfo(a); const bInfo = parseFlangeInfo(b); const aValue = aInfo[sortConfig.key] || ''; const bValue = bInfo[sortConfig.key] || ''; if (sortConfig.direction === 'asc') { return aValue > bValue ? 1 : -1; } else { return aValue < bValue ? 1 : -1; } }); } return filtered; }; // 전체 선택/해제 const handleSelectAll = () => { const filteredMaterials = getFilteredAndSortedMaterials(); if (selectedMaterials.size === filteredMaterials.length) { setSelectedMaterials(new Set()); } else { setSelectedMaterials(new Set(filteredMaterials.map(m => m.id))); } }; // 개별 선택 const handleMaterialSelect = (materialId) => { const newSelected = new Set(selectedMaterials); if (newSelected.has(materialId)) { newSelected.delete(materialId); } else { newSelected.add(materialId); } setSelectedMaterials(newSelected); }; // 엑셀 내보내기 const handleExportToExcel = async () => { const selectedMaterialsData = materials.filter(m => selectedMaterials.has(m.id)); if (selectedMaterialsData.length === 0) { alert('내보낼 자재를 선택해주세요.'); return; } const timestamp = new Date().toISOString().slice(0, 19).replace(/:/g, '-'); const excelFileName = `FLANGE_Materials_${timestamp}.xlsx`; const dataWithRequirements = selectedMaterialsData.map(material => ({ ...material, user_requirement: userRequirements[material.id] || '' })); try { await api.post('/files/save-excel', { file_id: fileId, category: 'FLANGE', materials: dataWithRequirements, filename: excelFileName, user_id: user?.id }); exportMaterialsToExcel(dataWithRequirements, excelFileName, { category: 'FLANGE', filename: excelFileName, uploadDate: new Date().toLocaleDateString() }); alert('엑셀 파일이 생성되고 서버에 저장되었습니다.'); } catch (error) { console.error('엑셀 저장 실패:', error); exportMaterialsToExcel(dataWithRequirements, excelFileName, { category: 'FLANGE', filename: excelFileName, uploadDate: new Date().toLocaleDateString() }); } }; const filteredMaterials = getFilteredAndSortedMaterials(); // 필터 헤더 컴포넌트 const FilterableHeader = ({ sortKey, filterKey, children }) => (
{filteredMaterials.length} items • {selectedMaterials.size} selected