✅ 주요 개선사항: • 엘보 90도/45도 각도 표시 개선 (ELBOW 90° LR BW 형태) • RL/SL (Long/Short Radius) 표시 추가 • 엘보 서브타입 분류 로직 강화 (90DEG_LONG_RADIUS, 90DEG_SHORT_RADIUS) • REDUCING FLANGE 분류 개선 (RED 키워드 제거로 피팅 오분류 방지) • 구매신청 엑셀 중복 생성 문제 해결 🎯 분류기 개선: • fitting_classifier.py: 엘보 조합 키워드 우선 확인 로직 추가 • integrated_classifier.py: FITTING 키워드에서 RED 제거 • NewMaterialsPage.jsx: 엘보 상세 표시 로직 개선 📊 테스트 완료: • 엘보 각도 및 반경 정보 정확 표시 • REDUCING FLANGE → FLANGE 분류 확인 • 구매신청 엑셀 단일 생성 확인
This commit is contained in:
@@ -513,18 +513,77 @@ def classify_fitting_subtype(fitting_type: str, description: str,
|
|||||||
main_nom: str, red_nom: str, type_data: Dict) -> Dict:
|
main_nom: str, red_nom: str, type_data: Dict) -> Dict:
|
||||||
"""피팅 서브타입 분류"""
|
"""피팅 서브타입 분류"""
|
||||||
|
|
||||||
|
desc_upper = description.upper()
|
||||||
subtypes = type_data.get("subtypes", {})
|
subtypes = type_data.get("subtypes", {})
|
||||||
|
|
||||||
# 1. 키워드 기반 서브타입 분류 (우선)
|
# 1. 키워드 기반 서브타입 분류 (우선) - 대소문자 구분 없이
|
||||||
for subtype, keywords in subtypes.items():
|
for subtype, keywords in subtypes.items():
|
||||||
for keyword in keywords:
|
for keyword in keywords:
|
||||||
if keyword in description:
|
if keyword.upper() in desc_upper:
|
||||||
return {
|
return {
|
||||||
"subtype": subtype,
|
"subtype": subtype,
|
||||||
"confidence": 0.9,
|
"confidence": 0.9,
|
||||||
"evidence": [f"SUBTYPE_KEYWORD: {keyword}"]
|
"evidence": [f"SUBTYPE_KEYWORD: {keyword}"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 1.5. ELBOW 특별 처리 - 조합 키워드 우선 확인
|
||||||
|
if fitting_type == "ELBOW":
|
||||||
|
# 90도 + 반경 조합
|
||||||
|
if ("90" in desc_upper or "90°" in desc_upper or "90DEG" in desc_upper):
|
||||||
|
if ("LR" in desc_upper or "LONG RADIUS" in desc_upper or "장반경" in desc_upper):
|
||||||
|
return {
|
||||||
|
"subtype": "90DEG_LONG_RADIUS",
|
||||||
|
"confidence": 0.95,
|
||||||
|
"evidence": ["90DEG + LONG_RADIUS"]
|
||||||
|
}
|
||||||
|
elif ("SR" in desc_upper or "SHORT RADIUS" in desc_upper or "단반경" in desc_upper):
|
||||||
|
return {
|
||||||
|
"subtype": "90DEG_SHORT_RADIUS",
|
||||||
|
"confidence": 0.95,
|
||||||
|
"evidence": ["90DEG + SHORT_RADIUS"]
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return {
|
||||||
|
"subtype": "90DEG",
|
||||||
|
"confidence": 0.85,
|
||||||
|
"evidence": ["90DEG_DETECTED"]
|
||||||
|
}
|
||||||
|
|
||||||
|
# 45도 + 반경 조합
|
||||||
|
elif ("45" in desc_upper or "45°" in desc_upper or "45DEG" in desc_upper):
|
||||||
|
if ("LR" in desc_upper or "LONG RADIUS" in desc_upper or "장반경" in desc_upper):
|
||||||
|
return {
|
||||||
|
"subtype": "45DEG_LONG_RADIUS",
|
||||||
|
"confidence": 0.95,
|
||||||
|
"evidence": ["45DEG + LONG_RADIUS"]
|
||||||
|
}
|
||||||
|
elif ("SR" in desc_upper or "SHORT RADIUS" in desc_upper or "단반경" in desc_upper):
|
||||||
|
return {
|
||||||
|
"subtype": "45DEG_SHORT_RADIUS",
|
||||||
|
"confidence": 0.95,
|
||||||
|
"evidence": ["45DEG + SHORT_RADIUS"]
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return {
|
||||||
|
"subtype": "45DEG",
|
||||||
|
"confidence": 0.85,
|
||||||
|
"evidence": ["45DEG_DETECTED"]
|
||||||
|
}
|
||||||
|
|
||||||
|
# 반경만 있는 경우 (기본 90도 가정)
|
||||||
|
elif ("LR" in desc_upper or "LONG RADIUS" in desc_upper or "장반경" in desc_upper):
|
||||||
|
return {
|
||||||
|
"subtype": "90DEG_LONG_RADIUS",
|
||||||
|
"confidence": 0.8,
|
||||||
|
"evidence": ["LONG_RADIUS_DEFAULT_90DEG"]
|
||||||
|
}
|
||||||
|
elif ("SR" in desc_upper or "SHORT RADIUS" in desc_upper or "단반경" in desc_upper):
|
||||||
|
return {
|
||||||
|
"subtype": "90DEG_SHORT_RADIUS",
|
||||||
|
"confidence": 0.8,
|
||||||
|
"evidence": ["SHORT_RADIUS_DEFAULT_90DEG"]
|
||||||
|
}
|
||||||
|
|
||||||
# 2. 사이즈 분석이 필요한 경우 (TEE, REDUCER 등)
|
# 2. 사이즈 분석이 필요한 경우 (TEE, REDUCER 등)
|
||||||
if type_data.get("size_analysis"):
|
if type_data.get("size_analysis"):
|
||||||
if red_nom and str(red_nom).strip() and red_nom != main_nom:
|
if red_nom and str(red_nom).strip() and red_nom != main_nom:
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ LEVEL1_TYPE_KEYWORDS = {
|
|||||||
"VALVE": ["VALVE", "GATE", "BALL", "GLOBE", "CHECK", "BUTTERFLY", "NEEDLE", "RELIEF", "밸브", "게이트", "볼", "글로브", "체크", "버터플라이", "니들", "릴리프"],
|
"VALVE": ["VALVE", "GATE", "BALL", "GLOBE", "CHECK", "BUTTERFLY", "NEEDLE", "RELIEF", "밸브", "게이트", "볼", "글로브", "체크", "버터플라이", "니들", "릴리프"],
|
||||||
"FLANGE": ["FLG", "FLANGE", "플랜지", "프랜지", "ORIFICE", "SPECTACLE", "PADDLE", "SPACER", "BLIND", "REDUCING FLANGE", "RED FLANGE"],
|
"FLANGE": ["FLG", "FLANGE", "플랜지", "프랜지", "ORIFICE", "SPECTACLE", "PADDLE", "SPACER", "BLIND", "REDUCING FLANGE", "RED FLANGE"],
|
||||||
"PIPE": ["PIPE", "TUBE", "파이프", "배관", "SMLS", "SEAMLESS"],
|
"PIPE": ["PIPE", "TUBE", "파이프", "배관", "SMLS", "SEAMLESS"],
|
||||||
"FITTING": ["SOCK-O-LET", "WELD-O-LET", "ELL-O-LET", "THREAD-O-LET", "ELB-O-LET", "NIP-O-LET", "COUP-O-LET", "SOCKOLET", "WELDOLET", "ELLOLET", "THREADOLET", "ELBOLET", "NIPOLET", "COUPOLET", "OLET", "ELBOW", "ELL", "TEE", "REDUCER", "RED", "CAP", "COUPLING", "NIPPLE", "SWAGE", "PLUG", "엘보", "티", "리듀서", "캡", "니플", "커플링", "플러그", "CONC", "ECC"],
|
"FITTING": ["SOCK-O-LET", "WELD-O-LET", "ELL-O-LET", "THREAD-O-LET", "ELB-O-LET", "NIP-O-LET", "COUP-O-LET", "SOCKOLET", "WELDOLET", "ELLOLET", "THREADOLET", "ELBOLET", "NIPOLET", "COUPOLET", "OLET", "ELBOW", "ELL", "TEE", "REDUCER", "CAP", "COUPLING", "NIPPLE", "SWAGE", "PLUG", "엘보", "티", "리듀서", "캡", "니플", "커플링", "플러그", "CONC", "ECC"],
|
||||||
"GASKET": ["GASKET", "GASK", "가스켓", "SWG", "SPIRAL"],
|
"GASKET": ["GASKET", "GASK", "가스켓", "SWG", "SPIRAL"],
|
||||||
"INSTRUMENT": ["GAUGE", "TRANSMITTER", "SENSOR", "THERMOMETER", "계기", "게이지", "트랜스미터", "센서"],
|
"INSTRUMENT": ["GAUGE", "TRANSMITTER", "SENSOR", "THERMOMETER", "계기", "게이지", "트랜스미터", "센서"],
|
||||||
"SUPPORT": ["URETHANE BLOCK", "URETHANE", "BLOCK SHOE", "CLAMP", "SUPPORT", "HANGER", "SPRING", "우레탄", "블록", "클램프", "서포트", "행거", "스프링"]
|
"SUPPORT": ["URETHANE BLOCK", "URETHANE", "BLOCK SHOE", "CLAMP", "SUPPORT", "HANGER", "SPRING", "우레탄", "블록", "클램프", "서포트", "행거", "스프링"]
|
||||||
|
|||||||
1836
backend/exports/PR-20251015-003.json
Normal file
1836
backend/exports/PR-20251015-003.json
Normal file
File diff suppressed because it is too large
Load Diff
BIN
backend/exports/PR-20251015-003.xlsx
Normal file
BIN
backend/exports/PR-20251015-003.xlsx
Normal file
Binary file not shown.
@@ -940,6 +940,7 @@ function App() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{/* adminFeatures 조건문 닫기 */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -620,10 +620,36 @@ const NewMaterialsPage = ({
|
|||||||
|
|
||||||
displayType = nippleType;
|
displayType = nippleType;
|
||||||
} else if (fittingType === 'ELBOW') {
|
} else if (fittingType === 'ELBOW') {
|
||||||
// 엘보: 각도와 연결 방식
|
// 엘보: 각도, 반경, 연결 방식 상세 표시
|
||||||
const angle = fittingSubtype === '90DEG' ? '90°' : fittingSubtype === '45DEG' ? '45°' : '';
|
let elbowDetails = [];
|
||||||
const connection = description.includes('SW') ? 'SW' : description.includes('BW') ? 'BW' : '';
|
|
||||||
displayType = `ELBOW ${angle} ${connection}`.trim();
|
// 각도 정보 추출
|
||||||
|
if (fittingSubtype.includes('90DEG') || description.includes('90') || description.includes('90°')) {
|
||||||
|
elbowDetails.push('90°');
|
||||||
|
} else if (fittingSubtype.includes('45DEG') || description.includes('45') || description.includes('45°')) {
|
||||||
|
elbowDetails.push('45°');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 반경 정보 추출 (Long Radius / Short Radius)
|
||||||
|
if (fittingSubtype.includes('LONG_RADIUS') || description.toUpperCase().includes('LR') || description.toUpperCase().includes('LONG RADIUS')) {
|
||||||
|
elbowDetails.push('LR');
|
||||||
|
} else if (fittingSubtype.includes('SHORT_RADIUS') || description.toUpperCase().includes('SR') || description.toUpperCase().includes('SHORT RADIUS')) {
|
||||||
|
elbowDetails.push('SR');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 연결 방식
|
||||||
|
if (description.includes('SW')) {
|
||||||
|
elbowDetails.push('SW');
|
||||||
|
} else if (description.includes('BW')) {
|
||||||
|
elbowDetails.push('BW');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 기본값 설정 (각도가 없으면 90도로 가정)
|
||||||
|
if (!elbowDetails.some(detail => detail.includes('°'))) {
|
||||||
|
elbowDetails.unshift('90°');
|
||||||
|
}
|
||||||
|
|
||||||
|
displayType = `ELBOW ${elbowDetails.join(' ')}`.trim();
|
||||||
} else if (fittingType === 'TEE') {
|
} else if (fittingType === 'TEE') {
|
||||||
// 티: 타입과 연결 방식
|
// 티: 타입과 연결 방식
|
||||||
const teeType = fittingSubtype === 'EQUAL' ? 'EQ' : fittingSubtype === 'REDUCING' ? 'RED' : '';
|
const teeType = fittingSubtype === 'EQUAL' ? 'EQ' : fittingSubtype === 'REDUCING' ? 'RED' : '';
|
||||||
@@ -1493,12 +1519,8 @@ const NewMaterialsPage = ({
|
|||||||
const timestamp = new Date().toISOString().split('T')[0];
|
const timestamp = new Date().toISOString().split('T')[0];
|
||||||
const fileName = `${jobNo}_${selectedCategory}_${timestamp}.xlsx`;
|
const fileName = `${jobNo}_${selectedCategory}_${timestamp}.xlsx`;
|
||||||
|
|
||||||
// 기존 엑셀 내보내기 함수 사용
|
// 엑셀 파일명 설정
|
||||||
await exportMaterialsToExcel(
|
const excelFileName = fileName;
|
||||||
dataWithRequirements,
|
|
||||||
fileName,
|
|
||||||
userRequirements
|
|
||||||
);
|
|
||||||
|
|
||||||
// 2단계: 생성된 엑셀을 서버에 업로드 (구매신청과 함께)
|
// 2단계: 생성된 엑셀을 서버에 업로드 (구매신청과 함께)
|
||||||
// 서버에 구매신청 생성
|
// 서버에 구매신청 생성
|
||||||
@@ -1583,7 +1605,7 @@ const NewMaterialsPage = ({
|
|||||||
// 실패해도 엑셀은 내보내기
|
// 실패해도 엑셀은 내보내기
|
||||||
}
|
}
|
||||||
|
|
||||||
// 개선된 엑셀 내보내기 함수 사용
|
// 엑셀 내보내기 (한 번만 실행)
|
||||||
const additionalInfo = {
|
const additionalInfo = {
|
||||||
filename: filename || bomName,
|
filename: filename || bomName,
|
||||||
jobNo: jobNo,
|
jobNo: jobNo,
|
||||||
@@ -1591,8 +1613,6 @@ const NewMaterialsPage = ({
|
|||||||
uploadDate: new Date().toLocaleDateString()
|
uploadDate: new Date().toLocaleDateString()
|
||||||
};
|
};
|
||||||
|
|
||||||
const excelFileName = `${selectedCategory}_${jobNo || 'export'}_${new Date().toISOString().split('T')[0]}.xlsx`;
|
|
||||||
|
|
||||||
exportMaterialsToExcel(dataWithRequirements, excelFileName, additionalInfo);
|
exportMaterialsToExcel(dataWithRequirements, excelFileName, additionalInfo);
|
||||||
|
|
||||||
console.log('✅ 엑셀 내보내기 성공');
|
console.log('✅ 엑셀 내보내기 성공');
|
||||||
|
|||||||
Reference in New Issue
Block a user