🔧 자재 분류기 개선 및 ELL 키워드 분류 문제 해결 (테스트 필요 - 안되는거 같음)
분류기 개선사항: 1. ELL-O-LET vs 일반 엘보 분류 개선 - OLET 우선순위 확인 로직 추가 - ELL 키워드 충돌 문제 해결 2. 엘보 서브타입 강화 - 90DEG_LONG_RADIUS, 90DEG_SHORT_RADIUS 등 조합형 추가 - 더 구체적인 키워드 패턴 지원 3. 레듀스 플랜지 분류 개선 - REDUCING FLANGE가 FITTING이 아닌 FLANGE로 분류되도록 수정 - 특별 우선순위 로직 추가 4. 90 ELL SW 분류 문제 해결 - fitting_keywords에 ELL 키워드 추가 - ELBOW description_keywords에 ELL, 90 ELL, 45 ELL 추가 기술적 개선: - 키워드 우선순위 체계 강화 - 구체적인 패턴 매칭 개선 - 분류 신뢰도 향상 플랜지 카테고리 개선: - 타입 풀네임 표시 (WN → WELD NECK FLANGE) - 끝단처리 별도 컬럼 추가 (RF → RAISED FACE) - 엑셀 내보내기 구조 개선 (P열 납기일, 관리항목 4개)
This commit is contained in:
@@ -939,7 +939,7 @@ function App() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)} {/* adminFeatures 조건문 닫기 */}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -638,6 +638,38 @@ const NewMaterialsPage = ({
|
||||
// 스웨이지: 타입 명시
|
||||
const swageType = fittingSubtype || '';
|
||||
displayType = `SWAGE ${swageType}`.trim();
|
||||
} else if (fittingType === 'OLET') {
|
||||
// OLET: 풀네임으로 표시
|
||||
const oletSubtype = fittingSubtype || '';
|
||||
let oletDisplayName = '';
|
||||
|
||||
switch (oletSubtype) {
|
||||
case 'SOCKOLET':
|
||||
oletDisplayName = 'SOCK-O-LET';
|
||||
break;
|
||||
case 'WELDOLET':
|
||||
oletDisplayName = 'WELD-O-LET';
|
||||
break;
|
||||
case 'ELLOLET':
|
||||
oletDisplayName = 'ELL-O-LET';
|
||||
break;
|
||||
case 'THREADOLET':
|
||||
oletDisplayName = 'THREAD-O-LET';
|
||||
break;
|
||||
case 'ELBOLET':
|
||||
oletDisplayName = 'ELB-O-LET';
|
||||
break;
|
||||
case 'NIPOLET':
|
||||
oletDisplayName = 'NIP-O-LET';
|
||||
break;
|
||||
case 'COUPOLET':
|
||||
oletDisplayName = 'COUP-O-LET';
|
||||
break;
|
||||
default:
|
||||
oletDisplayName = 'OLET';
|
||||
}
|
||||
|
||||
displayType = oletDisplayName;
|
||||
} else if (!displayType) {
|
||||
// 기타 피팅 타입
|
||||
displayType = fittingType || 'FITTING';
|
||||
@@ -738,9 +770,83 @@ const NewMaterialsPage = ({
|
||||
};
|
||||
} else if (category === 'FLANGE') {
|
||||
const description = material.original_description || '';
|
||||
const flangeDetails = material.flange_details || {};
|
||||
|
||||
// 백엔드에서 개선된 플랜지 타입 제공 (WN RF, SO FF 등)
|
||||
const displayType = material.flange_details?.flange_type || '-';
|
||||
// 플랜지 타입 풀네임 매핑 (영어)
|
||||
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',
|
||||
'BL': 'BLIND FLANGE',
|
||||
'BLIND': 'BLIND FLANGE',
|
||||
'RED': 'REDUCING 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': 'FULL FACE',
|
||||
'FULL_FACE': 'FULL FACE',
|
||||
'RTJ': 'RING JOINT',
|
||||
'RING_JOINT': 'RING JOINT',
|
||||
'MALE': 'MALE',
|
||||
'FEMALE': 'FEMALE'
|
||||
};
|
||||
|
||||
// 백엔드에서 제공된 타입 정보
|
||||
const rawFlangeType = flangeDetails.flange_type || '';
|
||||
const rawFacingType = flangeDetails.facing_type || '';
|
||||
|
||||
// 풀네임으로 변환
|
||||
let displayType = flangeTypeMap[rawFlangeType] || rawFlangeType || '-';
|
||||
let facingType = facingTypeMap[rawFacingType] || rawFacingType || '-';
|
||||
|
||||
// 백엔드 데이터가 없으면 description에서 추출
|
||||
if (displayType === '-') {
|
||||
const upperDesc = description.toUpperCase();
|
||||
if (upperDesc.includes('WN') || upperDesc.includes('WELD NECK')) {
|
||||
displayType = 'WELD NECK FLANGE';
|
||||
} else if (upperDesc.includes('SO') || upperDesc.includes('SLIP ON')) {
|
||||
displayType = 'SLIP ON FLANGE';
|
||||
} else if (upperDesc.includes('SW') || upperDesc.includes('SOCKET')) {
|
||||
displayType = 'SOCKET WELD FLANGE';
|
||||
} else if (upperDesc.includes('BLIND') || upperDesc.includes('BL')) {
|
||||
displayType = 'BLIND FLANGE';
|
||||
} else if (upperDesc.includes('REDUCING') || upperDesc.includes('RED')) {
|
||||
displayType = 'REDUCING FLANGE';
|
||||
} else if (upperDesc.includes('ORIFICE')) {
|
||||
displayType = 'ORIFICE FLANGE';
|
||||
} else if (upperDesc.includes('SPECTACLE')) {
|
||||
displayType = 'SPECTACLE BLIND';
|
||||
} else if (upperDesc.includes('PADDLE')) {
|
||||
displayType = 'PADDLE BLIND';
|
||||
} else if (upperDesc.includes('SPACER')) {
|
||||
displayType = 'SPACER';
|
||||
} else {
|
||||
displayType = 'FLANGE';
|
||||
}
|
||||
}
|
||||
|
||||
// 끝단처리 정보가 없으면 description에서 추출
|
||||
if (facingType === '-') {
|
||||
const upperDesc = description.toUpperCase();
|
||||
if (upperDesc.includes(' RF') || upperDesc.includes('RAISED')) {
|
||||
facingType = 'RAISED FACE';
|
||||
} else if (upperDesc.includes(' FF') || upperDesc.includes('FULL FACE')) {
|
||||
facingType = 'FULL FACE';
|
||||
} else if (upperDesc.includes('RTJ') || upperDesc.includes('RING')) {
|
||||
facingType = 'RING JOINT';
|
||||
}
|
||||
}
|
||||
|
||||
// 원본 설명에서 스케줄 추출
|
||||
let schedule = '-';
|
||||
@@ -756,11 +862,12 @@ const NewMaterialsPage = ({
|
||||
|
||||
return {
|
||||
type: 'FLANGE',
|
||||
subtype: displayType, // 백엔드에서 개선된 타입 정보 제공 (WN RF, SO FF 등)
|
||||
subtype: displayType, // 풀네임 플랜지 타입
|
||||
facing: facingType, // 새로 추가: 끝단처리 정보
|
||||
size: material.size_spec || '-',
|
||||
pressure: material.flange_details?.pressure_rating || '-',
|
||||
pressure: flangeDetails.pressure_rating || '-',
|
||||
schedule: schedule,
|
||||
grade: material.full_material_grade || material.material_grade || '-', // 전체 재질명 우선 사용
|
||||
grade: material.full_material_grade || material.material_grade || '-',
|
||||
quantity: Math.round(material.quantity || 0),
|
||||
unit: '개',
|
||||
isFlange: true // 플랜지 구분용 플래그
|
||||
@@ -1734,6 +1841,7 @@ const NewMaterialsPage = ({
|
||||
<div>선택</div>
|
||||
<FilterableHeader sortKey="type" filterKey="type">종류</FilterableHeader>
|
||||
<FilterableHeader sortKey="subtype" filterKey="subtype">타입</FilterableHeader>
|
||||
<FilterableHeader sortKey="facing" filterKey="facing">끝단처리</FilterableHeader>
|
||||
<FilterableHeader sortKey="size" filterKey="size">크기</FilterableHeader>
|
||||
<div>압력(파운드)</div>
|
||||
<FilterableHeader sortKey="schedule" filterKey="schedule">스케줄</FilterableHeader>
|
||||
@@ -2262,6 +2370,11 @@ const NewMaterialsPage = ({
|
||||
<span className="subtype-text">{info.subtype}</span>
|
||||
</div>
|
||||
|
||||
{/* 끝단처리 (플랜지 전용) */}
|
||||
<div className="material-cell">
|
||||
<span className="facing-text">{info.facing || '-'}</span>
|
||||
</div>
|
||||
|
||||
{/* 크기 */}
|
||||
<div className="material-cell">
|
||||
<span className="size-text">{info.size}</span>
|
||||
|
||||
@@ -156,79 +156,247 @@ const formatMaterialForExcel = (material, includeComparison = false) => {
|
||||
let gasketMaterial = '';
|
||||
let gasketThickness = '';
|
||||
if (category === 'PIPE') {
|
||||
itemName = material.pipe_details?.manufacturing_method || 'PIPE';
|
||||
} else if (category === 'FITTING') {
|
||||
itemName = material.fitting_details?.fitting_type || 'FITTING';
|
||||
} else if (category === 'FLANGE') {
|
||||
// 플랜지는 품목명만 간단하게 (상세내역에 타입 정보)
|
||||
itemName = 'FLANGE';
|
||||
// 파이프 상세 타입 표시 개선
|
||||
const pipeDetails = material.pipe_details || {};
|
||||
const manufacturingMethod = pipeDetails.manufacturing_method || '';
|
||||
const endPreparation = pipeDetails.end_preparation || '';
|
||||
|
||||
// 특수 플랜지는 구분
|
||||
const desc = cleanDescription.toUpperCase();
|
||||
if (desc.includes('ORIFICE')) {
|
||||
itemName = 'ORIFICE FLANGE';
|
||||
} else if (desc.includes('SPECTACLE')) {
|
||||
itemName = 'SPECTACLE BLIND';
|
||||
} else if (desc.includes('PADDLE')) {
|
||||
itemName = 'PADDLE BLIND';
|
||||
} else if (desc.includes('SPACER')) {
|
||||
itemName = 'SPACER';
|
||||
} else if (desc.includes('BLIND')) {
|
||||
itemName = 'BLIND FLANGE';
|
||||
// 제조방법과 끝단처리 조합으로 상세 타입 생성
|
||||
if (manufacturingMethod && endPreparation) {
|
||||
itemName = `${manufacturingMethod} PIPE (${endPreparation})`;
|
||||
} else if (manufacturingMethod) {
|
||||
itemName = `${manufacturingMethod} PIPE`;
|
||||
} else if (endPreparation) {
|
||||
itemName = `PIPE (${endPreparation})`;
|
||||
} else {
|
||||
// description에서 제조방법 추출 시도
|
||||
const desc = cleanDescription.toUpperCase();
|
||||
if (desc.includes('SEAMLESS')) {
|
||||
itemName = 'SEAMLESS PIPE';
|
||||
} else if (desc.includes('WELDED')) {
|
||||
itemName = 'WELDED PIPE';
|
||||
} else if (desc.includes('ERW')) {
|
||||
itemName = 'ERW PIPE';
|
||||
} else if (desc.includes('SMLS')) {
|
||||
itemName = 'SEAMLESS PIPE';
|
||||
} else {
|
||||
itemName = 'PIPE';
|
||||
}
|
||||
}
|
||||
} else if (category === 'FITTING') {
|
||||
// 피팅 상세 타입 표시 (OLET 등 풀네임)
|
||||
const fittingDetails = material.fitting_details || {};
|
||||
const fittingType = fittingDetails.fitting_type || '';
|
||||
const fittingSubtype = fittingDetails.fitting_subtype || '';
|
||||
|
||||
if (fittingType === 'OLET') {
|
||||
// OLET 풀네임 표시
|
||||
switch (fittingSubtype) {
|
||||
case 'SOCKOLET':
|
||||
itemName = 'SOCK-O-LET';
|
||||
break;
|
||||
case 'WELDOLET':
|
||||
itemName = 'WELD-O-LET';
|
||||
break;
|
||||
case 'ELLOLET':
|
||||
itemName = 'ELL-O-LET';
|
||||
break;
|
||||
case 'THREADOLET':
|
||||
itemName = 'THREAD-O-LET';
|
||||
break;
|
||||
case 'ELBOLET':
|
||||
itemName = 'ELB-O-LET';
|
||||
break;
|
||||
case 'NIPOLET':
|
||||
itemName = 'NIP-O-LET';
|
||||
break;
|
||||
case 'COUPOLET':
|
||||
itemName = 'COUP-O-LET';
|
||||
break;
|
||||
default:
|
||||
itemName = 'OLET';
|
||||
}
|
||||
} else if (fittingType === 'ELBOW') {
|
||||
// 엘보 각도 표시
|
||||
const angle = fittingSubtype === '90DEG' ? '90도' : fittingSubtype === '45DEG' ? '45도' : '';
|
||||
itemName = `엘보 ${angle}`.trim();
|
||||
} else if (fittingType === 'TEE') {
|
||||
// 티 타입 표시
|
||||
const teeType = fittingSubtype === 'EQUAL' ? '등경' : fittingSubtype === 'REDUCING' ? '축소' : '';
|
||||
itemName = `티 ${teeType}`.trim();
|
||||
} else if (fittingType === 'REDUCER') {
|
||||
// 리듀서 타입 표시
|
||||
const reducerType = fittingSubtype === 'CONCENTRIC' ? '동심' : fittingSubtype === 'ECCENTRIC' ? '편심' : '';
|
||||
itemName = `리듀서 ${reducerType}`.trim();
|
||||
} else {
|
||||
itemName = fittingType || 'FITTING';
|
||||
}
|
||||
} else if (category === 'FLANGE') {
|
||||
// 플랜지 상세 타입 표시
|
||||
const flangeDetails = material.flange_details || {};
|
||||
const flangeType = flangeDetails.flange_type || '';
|
||||
const facingType = flangeDetails.facing_type || '';
|
||||
|
||||
if (flangeType === 'WELD_NECK') {
|
||||
itemName = '웰드넥 플랜지';
|
||||
} else if (flangeType === 'SLIP_ON') {
|
||||
itemName = '슬립온 플랜지';
|
||||
} else if (flangeType === 'SOCKET_WELD') {
|
||||
itemName = '소켓웰드 플랜지';
|
||||
} else if (flangeType === 'BLIND') {
|
||||
itemName = '블라인드 플랜지';
|
||||
} else if (flangeType === 'REDUCING') {
|
||||
itemName = '축소 플랜지';
|
||||
} else {
|
||||
// 특수 플랜지는 구분
|
||||
const desc = cleanDescription.toUpperCase();
|
||||
if (desc.includes('ORIFICE')) {
|
||||
itemName = '오리피스 플랜지';
|
||||
} else if (desc.includes('SPECTACLE')) {
|
||||
itemName = '스펙터클 블라인드';
|
||||
} else if (desc.includes('PADDLE')) {
|
||||
itemName = '패들 블라인드';
|
||||
} else if (desc.includes('SPACER')) {
|
||||
itemName = '스페이서';
|
||||
} else {
|
||||
itemName = '플랜지';
|
||||
}
|
||||
}
|
||||
|
||||
// 상세내역에 플랜지 타입 정보 저장 (줄임말 사용)
|
||||
if (material.flange_details && material.flange_details.flange_type) {
|
||||
detailInfo = material.flange_details.flange_type; // WN RF, SO RF 등
|
||||
// 상세내역에 플랜지 타입 정보 저장
|
||||
if (flangeDetails.flange_type) {
|
||||
detailInfo = `${flangeType} ${facingType}`.trim();
|
||||
} else {
|
||||
// description에서 추출 (전체 이름 그대로 사용)
|
||||
// description에서 추출
|
||||
const flangeTypeMatch = cleanDescription.match(/FLG\s+([^,]+?)(?=\s*SCH|\s*,\s*\d+LB|$)/i);
|
||||
if (flangeTypeMatch) {
|
||||
detailInfo = flangeTypeMatch[1].trim(); // WELD NECK RF 등 그대로
|
||||
detailInfo = flangeTypeMatch[1].trim();
|
||||
}
|
||||
}
|
||||
} else if (category === 'VALVE') {
|
||||
itemName = 'VALVE';
|
||||
} else if (category === 'GASKET') {
|
||||
// 가스켓 상세 타입 추출
|
||||
if (material.gasket_details) {
|
||||
const gasketType = material.gasket_details.gasket_type || '';
|
||||
const gasketSubtype = material.gasket_details.gasket_subtype || '';
|
||||
|
||||
if (gasketSubtype && gasketSubtype !== gasketType) {
|
||||
itemName = gasketSubtype;
|
||||
} else if (gasketType) {
|
||||
itemName = gasketType;
|
||||
// 밸브 상세 타입 표시
|
||||
const valveDetails = material.valve_details || {};
|
||||
const valveType = valveDetails.valve_type || '';
|
||||
|
||||
if (valveType === 'GATE') {
|
||||
itemName = '게이트 밸브';
|
||||
} else if (valveType === 'BALL') {
|
||||
itemName = '볼 밸브';
|
||||
} else if (valveType === 'GLOBE') {
|
||||
itemName = '글로브 밸브';
|
||||
} else if (valveType === 'CHECK') {
|
||||
itemName = '체크 밸브';
|
||||
} else if (valveType === 'BUTTERFLY') {
|
||||
itemName = '버터플라이 밸브';
|
||||
} else if (valveType === 'NEEDLE') {
|
||||
itemName = '니들 밸브';
|
||||
} else if (valveType === 'RELIEF') {
|
||||
itemName = '릴리프 밸브';
|
||||
} else {
|
||||
// description에서 추출
|
||||
const desc = cleanDescription.toUpperCase();
|
||||
if (desc.includes('GATE')) {
|
||||
itemName = '게이트 밸브';
|
||||
} else if (desc.includes('BALL')) {
|
||||
itemName = '볼 밸브';
|
||||
} else if (desc.includes('GLOBE')) {
|
||||
itemName = '글로브 밸브';
|
||||
} else if (desc.includes('CHECK')) {
|
||||
itemName = '체크 밸브';
|
||||
} else if (desc.includes('BUTTERFLY')) {
|
||||
itemName = '버터플라이 밸브';
|
||||
} else if (desc.includes('NEEDLE')) {
|
||||
itemName = '니들 밸브';
|
||||
} else if (desc.includes('RELIEF')) {
|
||||
itemName = '릴리프 밸브';
|
||||
} else {
|
||||
itemName = 'GASKET';
|
||||
itemName = '밸브';
|
||||
}
|
||||
}
|
||||
} else if (category === 'GASKET') {
|
||||
// 가스켓 상세 타입 표시
|
||||
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;
|
||||
} else {
|
||||
// gasket_details가 없으면 description에서 추출
|
||||
if (cleanDescription.includes('SWG') || cleanDescription.includes('SPIRAL')) {
|
||||
itemName = 'SWG';
|
||||
} else if (cleanDescription.includes('RTJ') || cleanDescription.includes('RING')) {
|
||||
itemName = 'RTJ';
|
||||
} else if (cleanDescription.includes('FF') || cleanDescription.includes('FULL FACE')) {
|
||||
itemName = 'FF';
|
||||
} else if (cleanDescription.includes('RF') || cleanDescription.includes('RAISED')) {
|
||||
itemName = 'RF';
|
||||
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 = 'GASKET';
|
||||
itemName = '가스켓';
|
||||
}
|
||||
}
|
||||
} else if (category === 'BOLT') {
|
||||
itemName = 'BOLT';
|
||||
// 볼트 상세 타입 표시
|
||||
const boltDetails = material.bolt_details || {};
|
||||
const boltType = boltDetails.bolt_type || '';
|
||||
|
||||
if (boltType === 'HEX_BOLT') {
|
||||
itemName = '육각 볼트';
|
||||
} else if (boltType === 'STUD_BOLT') {
|
||||
itemName = '스터드 볼트';
|
||||
} else if (boltType === 'U_BOLT') {
|
||||
itemName = '유볼트';
|
||||
} else if (boltType === 'FLANGE_BOLT') {
|
||||
itemName = '플랜지 볼트';
|
||||
} else if (boltType === 'PSV_BOLT') {
|
||||
itemName = 'PSV 볼트';
|
||||
} else if (boltType === 'LT_BOLT') {
|
||||
itemName = '저온용 볼트';
|
||||
} else if (boltType === 'CK_BOLT') {
|
||||
itemName = '체크밸브용 볼트';
|
||||
} else {
|
||||
// description에서 추출
|
||||
const desc = cleanDescription.toUpperCase();
|
||||
if (desc.includes('PSV')) {
|
||||
itemName = 'PSV 볼트';
|
||||
} else if (desc.includes('LT')) {
|
||||
itemName = '저온용 볼트';
|
||||
} else if (desc.includes('CK')) {
|
||||
itemName = '체크밸브용 볼트';
|
||||
} else if (desc.includes('STUD')) {
|
||||
itemName = '스터드 볼트';
|
||||
} else if (desc.includes('U-BOLT') || desc.includes('U BOLT')) {
|
||||
itemName = '유볼트';
|
||||
} else {
|
||||
itemName = '볼트';
|
||||
}
|
||||
}
|
||||
} else if (category === 'SUPPORT' || category === 'U_BOLT') {
|
||||
// SUPPORT 카테고리: 타입별 구분
|
||||
// 서포트 상세 타입 표시
|
||||
const desc = cleanDescription.toUpperCase();
|
||||
if (desc.includes('URETHANE') || desc.includes('BLOCK SHOE')) {
|
||||
itemName = 'URETHANE BLOCK SHOE';
|
||||
itemName = '우레탄 블록 슈';
|
||||
} else if (desc.includes('CLAMP')) {
|
||||
itemName = 'CLAMP';
|
||||
itemName = '클램프';
|
||||
} else if (desc.includes('U-BOLT') || desc.includes('U BOLT')) {
|
||||
itemName = 'U-BOLT';
|
||||
itemName = '유볼트';
|
||||
} else if (desc.includes('HANGER')) {
|
||||
itemName = '행거';
|
||||
} else if (desc.includes('SPRING')) {
|
||||
itemName = '스프링 서포트';
|
||||
} else {
|
||||
itemName = 'SUPPORT';
|
||||
itemName = '서포트';
|
||||
}
|
||||
} else {
|
||||
itemName = category || 'UNKNOWN';
|
||||
@@ -445,54 +613,138 @@ const formatMaterialForExcel = (material, includeComparison = false) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 새로운 엑셀 양식에 맞춘 데이터 구조
|
||||
// 새로운 엑셀 양식: A~E 고정, F~O 카테고리별, P 납기일
|
||||
const base = {
|
||||
'TAGNO': '', // 비워둠
|
||||
'품목명': itemName,
|
||||
'수량': quantity,
|
||||
'통화구분': 'KRW', // 기본값
|
||||
'단가': 1, // 일괄 1로 설정
|
||||
'크기': material.size_spec || '-',
|
||||
'압력등급': pressure
|
||||
'TAGNO': '', // A열: 비워둠
|
||||
'품목명': itemName, // B열: 카테고리별 상세 타입
|
||||
'수량': quantity, // C열: 수량
|
||||
'통화구분': 'KRW', // D열: 기본값
|
||||
'단가': 1 // E열: 일괄 1로 설정
|
||||
};
|
||||
|
||||
// 카테고리별 전용 컬럼 구성
|
||||
if (category === 'GASKET') {
|
||||
// 가스켓 전용 컬럼 순서
|
||||
base['타입/구조'] = grade; // H/F/I/O, SWG 등 (스케줄 대신)
|
||||
base['재질'] = gasketMaterial || '-'; // SS304/GRAPHITE/SS304/SS304
|
||||
base['두께'] = gasketThickness || '-'; // 4.5mm
|
||||
base['사용자요구'] = material.user_requirement || '';
|
||||
base['관리항목8'] = ''; // 빈칸
|
||||
base['관리항목9'] = ''; // 빈칸
|
||||
base['관리항목10'] = ''; // 빈칸
|
||||
base['납기일(YYYY-MM-DD)'] = new Date().toISOString().split('T')[0]; // 가장 마지막
|
||||
} else if (category === 'BOLT') {
|
||||
// 볼트 전용 컬럼 순서 (스케줄 → 길이)
|
||||
base['길이'] = schedule; // 볼트는 길이 정보
|
||||
base['재질'] = grade;
|
||||
base['추가요구'] = detailInfo || '-'; // 상세내역 → 추가요구로 변경
|
||||
base['사용자요구'] = material.user_requirement || '';
|
||||
base['관리항목1'] = ''; // 빈칸
|
||||
base['관리항목7'] = ''; // 빈칸
|
||||
base['관리항목8'] = ''; // 빈칸
|
||||
base['관리항목9'] = ''; // 빈칸
|
||||
base['관리항목10'] = ''; // 빈칸
|
||||
base['납기일(YYYY-MM-DD)'] = new Date().toISOString().split('T')[0]; // 가장 마지막
|
||||
} else {
|
||||
// 다른 카테고리는 기존 방식
|
||||
base['스케줄'] = schedule;
|
||||
base['재질'] = grade;
|
||||
base['상세내역'] = detailInfo || '-';
|
||||
base['사용자요구'] = material.user_requirement || '';
|
||||
base['관리항목1'] = ''; // 빈칸
|
||||
base['관리항목7'] = ''; // 빈칸
|
||||
base['관리항목8'] = ''; // 빈칸
|
||||
base['관리항목9'] = ''; // 빈칸
|
||||
base['관리항목10'] = ''; // 빈칸
|
||||
base['납기일(YYYY-MM-DD)'] = new Date().toISOString().split('T')[0]; // 가장 마지막
|
||||
// F~O열: 카테고리별 전용 컬럼 구성 (10개 컬럼)
|
||||
if (category === 'PIPE') {
|
||||
// 파이프 전용 컬럼 (F~O)
|
||||
base['크기'] = material.size_spec || '-'; // F열
|
||||
base['압력등급'] = pressure; // G열
|
||||
base['스케줄'] = schedule; // H열
|
||||
base['재질'] = grade; // I열
|
||||
base['제조방법'] = material.pipe_details?.manufacturing_method || '-'; // J열
|
||||
base['끝단처리'] = material.pipe_details?.end_preparation || '-'; // K열
|
||||
base['사용자요구'] = material.user_requirement || ''; // L열
|
||||
base['관리항목1'] = ''; // M열
|
||||
base['관리항목2'] = ''; // N열
|
||||
base['관리항목3'] = ''; // O열
|
||||
} else if (category === 'FITTING') {
|
||||
// 피팅 전용 컬럼 (F~O)
|
||||
base['크기'] = material.size_spec || '-'; // F열
|
||||
base['압력등급'] = pressure; // G열
|
||||
base['타입'] = material.fitting_details?.fitting_type || '-'; // H열
|
||||
base['재질'] = grade; // I열
|
||||
base['상세내역'] = detailInfo || '-'; // J열
|
||||
base['사용자요구'] = material.user_requirement || ''; // K열
|
||||
base['관리항목1'] = ''; // L열
|
||||
base['관리항목2'] = ''; // M열
|
||||
base['관리항목3'] = ''; // N열
|
||||
base['관리항목4'] = ''; // O열
|
||||
} else if (category === 'FLANGE') {
|
||||
// 플랜지 타입 풀네임 매핑 (영어)
|
||||
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',
|
||||
'BL': 'BLIND FLANGE',
|
||||
'BLIND': 'BLIND FLANGE',
|
||||
'RED': 'REDUCING 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': 'FULL FACE',
|
||||
'FULL_FACE': 'FULL FACE',
|
||||
'RTJ': 'RING JOINT',
|
||||
'RING_JOINT': 'RING JOINT',
|
||||
'MALE': 'MALE',
|
||||
'FEMALE': 'FEMALE'
|
||||
};
|
||||
|
||||
const rawFlangeType = material.flange_details?.flange_type || '';
|
||||
const rawFacingType = material.flange_details?.facing_type || '';
|
||||
|
||||
// 플랜지 전용 컬럼 (F~O)
|
||||
base['크기'] = material.size_spec || '-'; // F열
|
||||
base['압력등급'] = pressure; // G열
|
||||
base['타입'] = flangeTypeMap[rawFlangeType] || rawFlangeType || 'FLANGE'; // H열
|
||||
base['재질'] = grade; // I열
|
||||
base['페이싱'] = facingTypeMap[rawFacingType] || rawFacingType || '-'; // J열
|
||||
base['사용자요구'] = material.user_requirement || ''; // K열
|
||||
base['관리항목1'] = ''; // L열
|
||||
base['관리항목2'] = ''; // M열
|
||||
base['관리항목3'] = ''; // N열
|
||||
base['관리항목4'] = ''; // O열
|
||||
} else if (category === 'VALVE') {
|
||||
// 밸브 전용 컬럼 (F~O)
|
||||
base['크기'] = material.size_spec || '-'; // F열
|
||||
base['압력등급'] = pressure; // G열
|
||||
base['타입'] = material.valve_details?.valve_type || '-'; // H열
|
||||
base['재질'] = grade; // I열
|
||||
base['상세내역'] = detailInfo || '-'; // J열
|
||||
base['사용자요구'] = material.user_requirement || ''; // K열
|
||||
base['관리항목1'] = ''; // L열
|
||||
base['관리항목2'] = ''; // M열
|
||||
base['관리항목3'] = ''; // N열
|
||||
base['관리항목4'] = ''; // O열
|
||||
} else if (category === 'GASKET') {
|
||||
// 가스켓 전용 컬럼 (F~O)
|
||||
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열
|
||||
} else if (category === 'BOLT') {
|
||||
// 볼트 전용 컬럼 (F~O)
|
||||
base['크기'] = material.size_spec || '-'; // F열
|
||||
base['압력등급'] = pressure; // G열
|
||||
base['길이'] = schedule; // H열: 볼트는 길이 정보
|
||||
base['재질'] = grade; // I열
|
||||
base['추가요구'] = detailInfo || '-'; // J열: 표면처리 등
|
||||
base['사용자요구'] = material.user_requirement || ''; // K열
|
||||
base['관리항목1'] = ''; // L열
|
||||
base['관리항목2'] = ''; // M열
|
||||
base['관리항목3'] = ''; // N열
|
||||
base['관리항목4'] = ''; // O열
|
||||
} else {
|
||||
// 기타 카테고리 기본 컬럼 (F~O)
|
||||
base['크기'] = material.size_spec || '-'; // F열
|
||||
base['압력등급'] = pressure; // G열
|
||||
base['스케줄'] = schedule; // H열
|
||||
base['재질'] = grade; // I열
|
||||
base['상세내역'] = detailInfo || '-'; // J열
|
||||
base['사용자요구'] = material.user_requirement || ''; // K열
|
||||
base['관리항목1'] = ''; // L열
|
||||
base['관리항목2'] = ''; // M열
|
||||
base['관리항목3'] = ''; // N열
|
||||
base['관리항목4'] = ''; // O열
|
||||
}
|
||||
|
||||
// P열: 납기일 (고정)
|
||||
base['납기일(YYYY-MM-DD)'] = new Date().toISOString().split('T')[0];
|
||||
|
||||
// 비교 모드인 경우 추가 정보
|
||||
if (includeComparison) {
|
||||
if (material.previous_quantity !== undefined) {
|
||||
|
||||
Reference in New Issue
Block a user