feat: 가스켓 카테고리 개선 및 엑셀 내보내기 최적화
Some checks failed
SonarQube Analysis / SonarQube Scan (push) Has been cancelled
Some checks failed
SonarQube Analysis / SonarQube Scan (push) Has been cancelled
- 가스켓 카테고리 정렬 오류 수정 (FilterableHeader props 추가) - 가스켓 엑셀 내보내기 개선: * 품목명을 BOM 페이지 타입과 동일하게 표시 (SPIRAL WOUND GASKET 등) * 재질을 재질1/재질2로 분리 (SS304/GRAPHITE → 재질1: SS304/GRAPHITE, 재질2: /SS304/SS304) * originalDescription에서 4개 재질 패턴 우선 추출 * P열 납기일 규칙 준수 - 프로젝트 비활성화 기능 수정 (localStorage 영구 저장) - 모든 카테고리 정렬 함수 안전성 강화
This commit is contained in:
@@ -422,37 +422,43 @@ const formatMaterialForExcel = (material, includeComparison = false) => {
|
||||
}
|
||||
}
|
||||
} else if (category === 'GASKET') {
|
||||
// 가스켓 상세 타입 표시
|
||||
// BOM 페이지의 타입을 따라가도록 - 프론트엔드 parseGasketInfo와 동일한 로직
|
||||
const gasketDetails = material.gasket_details || {};
|
||||
const gasketType = gasketDetails.gasket_type || '';
|
||||
const gasketSubtype = gasketDetails.gasket_subtype || '';
|
||||
|
||||
if (gasketType === 'SPIRAL_WOUND') {
|
||||
itemName = '스파이럴 워운드 가스켓';
|
||||
} else if (gasketType === 'RING_JOINT') {
|
||||
itemName = '링 조인트 가스켓';
|
||||
} else if (gasketType === 'FULL_FACE') {
|
||||
itemName = '풀 페이스 가스켓';
|
||||
} else if (gasketType === 'RAISED_FACE') {
|
||||
itemName = '레이즈드 페이스 가스켓';
|
||||
} else if (gasketSubtype && gasketSubtype !== gasketType) {
|
||||
itemName = gasketSubtype;
|
||||
} else if (gasketType) {
|
||||
itemName = gasketType;
|
||||
// 가스켓 타입 매핑 (프론트엔드와 동일)
|
||||
const gasketTypeMap = {
|
||||
'SWG': 'SPIRAL WOUND GASKET',
|
||||
'SPIRAL_WOUND': 'SPIRAL WOUND GASKET',
|
||||
'RTJ': 'RING TYPE JOINT GASKET',
|
||||
'RING_JOINT': 'RING TYPE JOINT GASKET',
|
||||
'FF': 'FULL FACE GASKET',
|
||||
'FULL_FACE': 'FULL FACE GASKET',
|
||||
'RF': 'RAISED FACE GASKET',
|
||||
'RAISED_FACE': 'RAISED FACE GASKET'
|
||||
};
|
||||
|
||||
// Description에서 가스켓 타입 추출
|
||||
const descUpper = cleanDescription.toUpperCase();
|
||||
let extractedType = '';
|
||||
|
||||
if (descUpper.includes('SWG') || descUpper.includes('SPIRAL')) {
|
||||
extractedType = 'SWG';
|
||||
} else if (descUpper.includes('RTJ') || descUpper.includes('RING')) {
|
||||
extractedType = 'RTJ';
|
||||
} else if (descUpper.includes('FF') || descUpper.includes('FULL FACE')) {
|
||||
extractedType = 'FF';
|
||||
} else if (descUpper.includes('RF') || descUpper.includes('RAISED')) {
|
||||
extractedType = 'RF';
|
||||
}
|
||||
|
||||
// 풀네임으로 변환
|
||||
if (gasketType && gasketTypeMap[gasketType]) {
|
||||
itemName = gasketTypeMap[gasketType];
|
||||
} else if (extractedType && gasketTypeMap[extractedType]) {
|
||||
itemName = gasketTypeMap[extractedType];
|
||||
} else {
|
||||
// gasket_details가 없으면 description에서 추출
|
||||
const desc = cleanDescription.toUpperCase();
|
||||
if (desc.includes('SWG') || desc.includes('SPIRAL')) {
|
||||
itemName = '스파이럴 워운드 가스켓';
|
||||
} else if (desc.includes('RTJ') || desc.includes('RING')) {
|
||||
itemName = '링 조인트 가스켓';
|
||||
} else if (desc.includes('FF') || desc.includes('FULL FACE')) {
|
||||
itemName = '풀 페이스 가스켓';
|
||||
} else if (desc.includes('RF') || desc.includes('RAISED')) {
|
||||
itemName = '레이즈드 페이스 가스켓';
|
||||
} else {
|
||||
itemName = '가스켓';
|
||||
}
|
||||
itemName = 'GASKET';
|
||||
}
|
||||
} else if (category === 'BOLT') {
|
||||
// 볼트 상세 타입 표시
|
||||
@@ -660,28 +666,33 @@ const formatMaterialForExcel = (material, includeComparison = false) => {
|
||||
|
||||
detailInfo = surfaceTreatments.join(', ') || '-';
|
||||
} else if (category === 'GASKET') {
|
||||
// 실제 재질 구성 정보 (SS304/GRAPHITE/SS304/SS304)
|
||||
if (material.gasket_details) {
|
||||
const materialType = material.gasket_details.material_type || '';
|
||||
const fillerMaterial = material.gasket_details.filler_material || '';
|
||||
|
||||
if (materialType && fillerMaterial) {
|
||||
// DB에서 가져온 정보로 구성
|
||||
gasketMaterial = `${materialType}/${fillerMaterial}`;
|
||||
}
|
||||
}
|
||||
|
||||
// gasket_details가 없거나 불완전하면 description에서 추출
|
||||
if (!gasketMaterial) {
|
||||
// SS304/GRAPHITE/SS304/SS304 패턴 추출
|
||||
const fullMaterialMatch = cleanDescription.match(/SS304\/GRAPHITE\/SS304\/SS304/i);
|
||||
if (fullMaterialMatch) {
|
||||
gasketMaterial = 'SS304/GRAPHITE/SS304/SS304';
|
||||
// 실제 재질 구성 정보 - description에서 우선 추출
|
||||
// SS304/GRAPHITE/SS304/SS304 패턴 먼저 찾기
|
||||
const fullMaterialMatch = cleanDescription.match(/SS304\/GRAPHITE\/SS304\/SS304/i);
|
||||
if (fullMaterialMatch) {
|
||||
gasketMaterial = 'SS304/GRAPHITE/SS304/SS304';
|
||||
} else {
|
||||
// 4개 재질 패턴 (다양한 재질 조합)
|
||||
const fourMaterialMatch = cleanDescription.match(/(SS\d+|304|316|CS)\/(GRAPHITE|PTFE|VITON|EPDM)\/(SS\d+|304|316|CS)\/(SS\d+|304|316|CS)/i);
|
||||
if (fourMaterialMatch) {
|
||||
gasketMaterial = `${fourMaterialMatch[1]}/${fourMaterialMatch[2]}/${fourMaterialMatch[3]}/${fourMaterialMatch[4]}`;
|
||||
} else {
|
||||
// 간단한 패턴 (SS304/GRAPHITE)
|
||||
const simpleMaterialMatch = cleanDescription.match(/(SS\d+|304|316)\s*[\/+]\s*(GRAPHITE|PTFE|VITON|EPDM)/i);
|
||||
if (simpleMaterialMatch) {
|
||||
gasketMaterial = `${simpleMaterialMatch[1]}/${simpleMaterialMatch[2]}`;
|
||||
// DB에서 가져온 정보로 구성 (fallback)
|
||||
if (material.gasket_details) {
|
||||
const materialType = material.gasket_details.material_type || '';
|
||||
const fillerMaterial = material.gasket_details.filler_material || '';
|
||||
|
||||
if (materialType && fillerMaterial) {
|
||||
gasketMaterial = `${materialType}/${fillerMaterial}`;
|
||||
}
|
||||
}
|
||||
|
||||
// 마지막으로 간단한 패턴
|
||||
if (!gasketMaterial) {
|
||||
const simpleMaterialMatch = cleanDescription.match(/(SS\d+|304|316)\s*[\/+]\s*(GRAPHITE|PTFE|VITON|EPDM)/i);
|
||||
if (simpleMaterialMatch) {
|
||||
gasketMaterial = `${simpleMaterialMatch[1]}/${simpleMaterialMatch[2]}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -794,17 +805,41 @@ const formatMaterialForExcel = (material, includeComparison = false) => {
|
||||
base['관리항목4'] = ''; // N열
|
||||
base['관리항목5'] = ''; // O열
|
||||
} else if (category === 'GASKET') {
|
||||
// 가스켓 전용 컬럼 (F~O) - 타입 제거, 품목명에 포함됨
|
||||
// 가스켓 전용 컬럼 (F~O) - 재질을 2개로 분리
|
||||
// 재질 분리 로직: SS304/GRAPHITE/SS304/SS304 → 재질1: SS304/GRAPHITE, 재질2: /SS304/SS304
|
||||
let material1 = '-';
|
||||
let material2 = '-';
|
||||
|
||||
if (gasketMaterial && gasketMaterial.includes('/')) {
|
||||
const materialParts = gasketMaterial.split('/');
|
||||
|
||||
if (materialParts.length >= 4) {
|
||||
// 4개 재질인 경우: SS304/GRAPHITE/SS304/SS304
|
||||
material1 = `${materialParts[0]}/${materialParts[1]}`;
|
||||
material2 = `/${materialParts[2]}/${materialParts[3]}`;
|
||||
} else if (materialParts.length === 3) {
|
||||
// 3개 재질인 경우: SS304/GRAPHITE/SS304
|
||||
material1 = `${materialParts[0]}/${materialParts[1]}`;
|
||||
material2 = `/${materialParts[2]}`;
|
||||
} else if (materialParts.length === 2) {
|
||||
// 2개 재질인 경우: SS304/GRAPHITE
|
||||
material1 = gasketMaterial;
|
||||
material2 = '-';
|
||||
}
|
||||
} else if (gasketMaterial) {
|
||||
material1 = gasketMaterial;
|
||||
}
|
||||
|
||||
base['크기'] = material.size_spec || '-'; // F열
|
||||
base['압력등급'] = pressure; // G열
|
||||
base['구조'] = grade; // H열: H/F/I/O, SWG 등 (타입 정보 제거)
|
||||
base['재질'] = gasketMaterial || '-'; // I열: SS304/GRAPHITE/SS304/SS304
|
||||
base['두께'] = gasketThickness || '-'; // J열: 4.5mm
|
||||
base['사용자요구'] = material.user_requirement || ''; // K열
|
||||
base['관리항목1'] = ''; // L열
|
||||
base['관리항목2'] = ''; // M열
|
||||
base['관리항목3'] = ''; // N열
|
||||
base['관리항목4'] = ''; // O열
|
||||
base['구조'] = grade; // H열: H/F/I/O, SWG 등
|
||||
base['재질1'] = material1; // I열: SS304/GRAPHITE
|
||||
base['재질2'] = material2; // J열: SS304/SS304
|
||||
base['두께'] = gasketThickness || '-'; // K열: 4.5mm
|
||||
base['사용자요구'] = material.user_requirement || ''; // L열
|
||||
base['관리항목1'] = ''; // M열
|
||||
base['관리항목2'] = ''; // N열
|
||||
base['관리항목3'] = ''; // O열
|
||||
} else if (category === 'BOLT') {
|
||||
// 볼트 전용 컬럼 (F~O) - 타입 제거, 품목명에 포함됨
|
||||
base['크기'] = material.size_spec || '-'; // F열
|
||||
@@ -1077,7 +1112,7 @@ export const createExcelBlob = async (materials, filename, options = {}) => {
|
||||
'FITTING': ['크기', '압력등급', '스케줄', '재질', '사용자요구', '추가요청사항', '관리항목1', '관리항목2', '관리항목3', '관리항목4'],
|
||||
'FLANGE': ['크기', '페이싱', '압력등급', '스케줄', '재질', '추가요구사항', '관리항목1', '관리항목2', '관리항목3', '관리항목4'],
|
||||
'VALVE': ['크기', '압력등급', '재질', '상세내역', '사용자요구', '관리항목1', '관리항목2', '관리항목3', '관리항목4'],
|
||||
'GASKET': ['크기', '압력등급', '구조', '재질', '두께', '사용자요구', '관리항목1', '관리항목2', '관리항목3', '관리항목4'],
|
||||
'GASKET': ['크기', '압력등급', '구조', '재질1', '재질2', '두께', '사용자요구', '관리항목1', '관리항목2', '관리항목3'],
|
||||
'BOLT': ['크기', '압력등급', '길이', '재질', '추가요구', '사용자요구', '관리항목1', '관리항목2', '관리항목3', '관리항목4'],
|
||||
'SUPPORT': ['크기', '압력등급', '재질', '상세내역', '사용자요구', '관리항목1', '관리항목2', '관리항목3', '관리항목4'],
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user