feat: 자재 리비전 비교 및 구매 목록 시스템 구현

- 자재 리비전간 비교 기능 추가 (MaterialComparisonPage) - 버그 해결 필요
- 리비전간 추가 구매 필요 자재 분석 페이지 추가 (RevisionPurchasePage)
- 자재 비교 결과 컴포넌트 구현 (MaterialComparisonResult)
- 자재 비교 API 라우터 추가 (material_comparison.py) - 로직 개선 필요
- 자재 비교 시스템 데이터베이스 스키마 추가
- FileManager, FileUpload 컴포넌트 개선
- BOMManagerPage 제거 및 새로운 구조로 리팩토링
- 자재 분류기 및 스키마 개선

TODO: 자재 비교 알고리즘 정확도 향상 및 예외 처리 강화 필요
This commit is contained in:
Hyungi Ahn
2025-07-22 15:56:40 +09:00
parent 6ca1cd17e2
commit 534015cc7c
16 changed files with 2577 additions and 267 deletions

View File

@@ -137,7 +137,7 @@ const BOMStatusPage = () => {
formData.append('bom_name', revisionDialog.bomName);
formData.append('bom_type', 'excel');
formData.append('description', '');
formData.append('parent_bom_id', revisionDialog.parentId);
formData.append('parent_file_id', revisionDialog.parentId);
const response = await uploadFileApi(formData);
@@ -189,7 +189,7 @@ const BOMStatusPage = () => {
<Button variant="outlined" onClick={() => navigate('/')} sx={{ mb: 2 }}>
뒤로가기
</Button>
<Typography variant="h4" gutterBottom>BOM 업로드 현황</Typography>
<Typography variant="h4" gutterBottom>📊 BOM 관리 시스템</Typography>
{jobNo && jobName && (
<Typography variant="h6" color="primary" sx={{ mb: 3 }}>
{jobNo} - {jobName}
@@ -257,30 +257,46 @@ const BOMStatusPage = () => {
{Object.entries(groupFilesByBOM()).map(([bomKey, bomFiles]) => (
bomFiles.map((file, index) => (
<TableRow key={file.id} sx={{
backgroundColor: index === 0 ? 'rgba(25, 118, 210, 0.08)' : 'inherit'
backgroundColor: index === 0 ? 'rgba(25, 118, 210, 0.08)' : 'rgba(0, 0, 0, 0.02)'
}}>
<TableCell>
<Typography variant="body2" fontWeight={index === 0 ? 'bold' : 'normal'}>
{file.bom_name || bomKey}
</Typography>
{index === 0 && bomFiles.length > 1 && (
<Typography variant="caption" color="textSecondary">
<Typography variant="caption" color="primary">
(최신 리비전)
</Typography>
)}
{index > 0 && (
<Typography variant="caption" color="textSecondary">
(이전 버전)
</Typography>
)}
</TableCell>
<TableCell>
<Typography variant="body2" color={index === 0 ? 'textPrimary' : 'textSecondary'}>
{file.filename || file.original_filename}
</Typography>
</TableCell>
<TableCell>{file.filename || file.original_filename}</TableCell>
<TableCell>
<Typography
variant="body2"
color={index === 0 ? 'primary' : 'textSecondary'}
fontWeight={index === 0 ? 'bold' : 'normal'}
>
{file.revision || 'Rev.0'}
</Typography>
</TableCell>
<TableCell>{file.parsed_count || '-'}</TableCell>
<TableCell>
{file.upload_date ? new Date(file.upload_date).toLocaleString('ko-KR') : '-'}
<Typography variant="body2" color={index === 0 ? 'textPrimary' : 'textSecondary'}>
{file.parsed_count || 0}
</Typography>
</TableCell>
<TableCell>
<Typography variant="body2" color={index === 0 ? 'textPrimary' : 'textSecondary'}>
{file.upload_date ? new Date(file.upload_date).toLocaleString('ko-KR') : '-'}
</Typography>
</TableCell>
<TableCell>
<Button
@@ -306,6 +322,28 @@ const BOMStatusPage = () => {
리비전
</Button>
)}
{file.revision !== 'Rev.0' && index < 3 && (
<>
<Button
size="small"
variant="outlined"
color="secondary"
onClick={() => navigate(`/material-comparison?job_no=${jobNo}&revision=${file.revision}&filename=${encodeURIComponent(file.original_filename)}`)}
sx={{ mr: 1 }}
>
비교
</Button>
<Button
size="small"
variant="outlined"
color="success"
onClick={() => navigate(`/revision-purchase?job_no=${jobNo}&current_revision=${file.revision}&bom_name=${encodeURIComponent(file.bom_name || bomKey)}`)}
sx={{ mr: 1 }}
>
구매 필요
</Button>
</>
)}
<Button
size="small"
color="error"