import React, { useState } from 'react'; import { exportMaterialsToExcel } from '../../../utils/excelExport'; import api from '../../../api'; import { FilterableHeader } from '../shared'; const BoltMaterialsView = ({ materials, selectedMaterials, setSelectedMaterials, userRequirements, setUserRequirements, purchasedMaterials, fileId, user }) => { const [sortConfig, setSortConfig] = useState({ key: null, direction: 'asc' }); const [columnFilters, setColumnFilters] = useState({}); const [showFilterDropdown, setShowFilterDropdown] = useState(null); // 볼트 추가요구사항 추출 함수 const extractBoltAdditionalRequirements = (description) => { const additionalReqs = []; // 표면처리 패턴 확인 const surfacePatterns = { 'ELEC.GALV': 'ELEC.GALV', 'ELEC GALV': 'ELEC.GALV', 'GALVANIZED': 'GALVANIZED', 'GALV': 'GALV', 'HOT DIP GALV': 'HDG', 'HDG': 'HDG', 'ZINC PLATED': 'ZINC PLATED', 'ZINC': 'ZINC', 'PLAIN': 'PLAIN' }; for (const [pattern, treatment] of Object.entries(surfacePatterns)) { if (description.includes(pattern)) { additionalReqs.push(treatment); break; // 첫 번째 매치만 사용 } } return additionalReqs.join(', ') || '-'; }; const parseBoltInfo = (material) => { const qty = Math.round(material.quantity || 0); const safetyQty = Math.ceil(qty * 1.05); // 5% 여유율 const purchaseQty = Math.ceil(safetyQty / 4) * 4; // 4의 배수 // 볼트 상세 정보 우선 사용 const boltDetails = material.bolt_details || {}; // 길이 정보 (bolt_details 우선, 없으면 원본 설명에서 추출) let boltLength = '-'; if (boltDetails.length && boltDetails.length !== '-') { boltLength = boltDetails.length; } else { // 원본 설명에서 길이 추출 const description = material.original_description || ''; const lengthPatterns = [ /(\d+(?:\.\d+)?)\s*LG/i, // 75 LG, 90.0000 LG /(\d+(?:\.\d+)?)\s*mm/i, // 50mm /(\d+(?:\.\d+)?)\s*MM/i, // 50MM /LG[,\s]*(\d+(?:\.\d+)?)/i // LG, 75 형태 ]; for (const pattern of lengthPatterns) { const match = description.match(pattern); if (match) { let lengthValue = match[1]; // 소수점 제거 (145.0000 → 145) if (lengthValue.includes('.') && lengthValue.endsWith('.0000')) { lengthValue = lengthValue.split('.')[0]; } else if (lengthValue.includes('.') && /\.0+$/.test(lengthValue)) { lengthValue = lengthValue.split('.')[0]; } boltLength = `${lengthValue}mm`; break; } } } // 재질 정보 (bolt_details 우선, 없으면 기본 필드 사용) let boltGrade = '-'; if (boltDetails.material_standard && boltDetails.material_grade) { // bolt_details에서 완전한 재질 정보 구성 if (boltDetails.material_grade !== 'UNKNOWN' && boltDetails.material_grade !== boltDetails.material_standard) { boltGrade = `${boltDetails.material_standard} ${boltDetails.material_grade}`; } else { boltGrade = boltDetails.material_standard; } } else if (material.full_material_grade && material.full_material_grade !== '-') { boltGrade = material.full_material_grade; } else if (material.material_grade && material.material_grade !== '-') { boltGrade = material.material_grade; } // 볼트 타입 (PSV_BOLT, LT_BOLT 등) let boltSubtype = 'BOLT_GENERAL'; if (boltDetails.bolt_type && boltDetails.bolt_type !== 'UNKNOWN') { boltSubtype = boltDetails.bolt_type; } else { // 원본 설명에서 특수 볼트 타입 추출 const description = material.original_description || ''; const upperDesc = description.toUpperCase(); if (upperDesc.includes('PSV')) { boltSubtype = 'PSV_BOLT'; } else if (upperDesc.includes('LT')) { boltSubtype = 'LT_BOLT'; } else if (upperDesc.includes('CK')) { boltSubtype = 'CK_BOLT'; } } // 추가요구사항 추출 (ELEC.GALV 등) const additionalReq = extractBoltAdditionalRequirements(material.original_description || ''); return { type: 'BOLT', subtype: boltSubtype, size: material.size_spec || material.main_nom || '-', pressure: '-', // 볼트는 압력 등급 없음 schedule: boltLength, // 길이 정보 grade: boltGrade, additionalReq: additionalReq, // 추가요구사항 quantity: purchaseQty, unit: 'SETS' }; }; // 정렬 처리 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 = parseBoltInfo(material); const value = info[key]?.toString().toLowerCase() || ''; return value.includes(filterValue.toLowerCase()); }); }); if (sortConfig.key) { filtered.sort((a, b) => { const aInfo = parseBoltInfo(a); const bInfo = parseBoltInfo(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(); const selectableMaterials = filteredMaterials.filter(m => !purchasedMaterials.has(m.id)); if (selectedMaterials.size === selectableMaterials.length) { setSelectedMaterials(new Set()); } else { setSelectedMaterials(new Set(selectableMaterials.map(m => m.id))); } }; // 개별 선택 (구매신청된 자재는 선택 불가) const handleMaterialSelect = (materialId) => { if (purchasedMaterials.has(materialId)) { return; // 구매신청된 자재는 선택 불가 } 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 = `BOLT_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: 'BOLT', materials: dataWithRequirements, filename: excelFileName, user_id: user?.id }); exportMaterialsToExcel(dataWithRequirements, excelFileName, { category: 'BOLT', filename: excelFileName, uploadDate: new Date().toLocaleDateString() }); alert('엑셀 파일이 생성되고 서버에 저장되었습니다.'); } catch (error) { console.error('엑셀 저장 실패:', error); exportMaterialsToExcel(dataWithRequirements, excelFileName, { category: 'BOLT', filename: excelFileName, uploadDate: new Date().toLocaleDateString() }); } }; const filteredMaterials = getFilteredAndSortedMaterials(); return (
{filteredMaterials.length} items • {selectedMaterials.size} selected