246 lines
8.1 KiB
JavaScript
246 lines
8.1 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
|
import {
|
|
Typography,
|
|
Box,
|
|
Card,
|
|
CardContent,
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableContainer,
|
|
TableHead,
|
|
TableRow,
|
|
Paper,
|
|
TablePagination,
|
|
CircularProgress,
|
|
Alert,
|
|
Chip
|
|
} from '@mui/material';
|
|
import { Inventory } from '@mui/icons-material';
|
|
|
|
function MaterialList({ selectedProject }) {
|
|
const [materials, setMaterials] = useState([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState('');
|
|
const [page, setPage] = useState(0);
|
|
const [rowsPerPage, setRowsPerPage] = useState(25);
|
|
const [totalCount, setTotalCount] = useState(0);
|
|
|
|
useEffect(() => {
|
|
if (selectedProject) {
|
|
fetchMaterials();
|
|
} else {
|
|
setMaterials([]);
|
|
setTotalCount(0);
|
|
}
|
|
}, [selectedProject, page, rowsPerPage]);
|
|
|
|
const fetchMaterials = async () => {
|
|
setLoading(true);
|
|
setError('');
|
|
|
|
try {
|
|
const skip = page * rowsPerPage;
|
|
const response = await fetch(
|
|
`http://localhost:8000/api/files/materials?project_id=${selectedProject.id}&skip=${skip}&limit=${rowsPerPage}`
|
|
);
|
|
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
setMaterials(data.materials || []);
|
|
setTotalCount(data.total_count || 0);
|
|
} else {
|
|
setError('자재 데이터를 불러오는데 실패했습니다.');
|
|
}
|
|
} catch (error) {
|
|
console.error('자재 조회 실패:', error);
|
|
setError('네트워크 오류가 발생했습니다.');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleChangePage = (event, newPage) => {
|
|
setPage(newPage);
|
|
};
|
|
|
|
const handleChangeRowsPerPage = (event) => {
|
|
setRowsPerPage(parseInt(event.target.value, 10));
|
|
setPage(0);
|
|
};
|
|
|
|
const getItemTypeColor = (itemType) => {
|
|
const colors = {
|
|
'PIPE': 'primary',
|
|
'FITTING': 'secondary',
|
|
'VALVE': 'success',
|
|
'FLANGE': 'warning',
|
|
'BOLT': 'info',
|
|
'OTHER': 'default'
|
|
};
|
|
return colors[itemType] || 'default';
|
|
};
|
|
|
|
if (!selectedProject) {
|
|
return (
|
|
<Box>
|
|
<Typography variant="h4" gutterBottom>
|
|
📋 자재 목록
|
|
</Typography>
|
|
<Card>
|
|
<CardContent sx={{ textAlign: 'center', py: 4 }}>
|
|
<Inventory sx={{ fontSize: 64, color: 'secondary.main', mb: 2 }} />
|
|
<Typography variant="h6" gutterBottom>
|
|
프로젝트를 선택해주세요
|
|
</Typography>
|
|
<Typography variant="body2" color="textSecondary">
|
|
프로젝트 관리 탭에서 프로젝트를 선택하면 자재 목록을 확인할 수 있습니다.
|
|
</Typography>
|
|
</CardContent>
|
|
</Card>
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Box>
|
|
<Typography variant="h4" gutterBottom>
|
|
📋 자재 목록 (그룹핑)
|
|
</Typography>
|
|
|
|
<Typography variant="h6" color="primary" sx={{ mb: 2 }}>
|
|
{selectedProject.project_name} ({selectedProject.official_project_code})
|
|
</Typography>
|
|
|
|
{error && (
|
|
<Alert severity="error" sx={{ mb: 2 }}>
|
|
{error}
|
|
</Alert>
|
|
)}
|
|
|
|
{loading ? (
|
|
<Card>
|
|
<CardContent sx={{ textAlign: 'center', py: 4 }}>
|
|
<CircularProgress size={60} />
|
|
<Typography variant="h6" sx={{ mt: 2 }}>
|
|
자재 데이터 로딩 중...
|
|
</Typography>
|
|
</CardContent>
|
|
</Card>
|
|
) : materials.length === 0 ? (
|
|
<Card>
|
|
<CardContent sx={{ textAlign: 'center', py: 4 }}>
|
|
<Inventory sx={{ fontSize: 64, color: 'secondary.main', mb: 2 }} />
|
|
<Typography variant="h6" gutterBottom>
|
|
자재 데이터가 없습니다
|
|
</Typography>
|
|
<Typography variant="body2" color="textSecondary">
|
|
파일 업로드 탭에서 BOM 파일을 업로드해주세요.
|
|
</Typography>
|
|
</CardContent>
|
|
</Card>
|
|
) : (
|
|
<Card>
|
|
<CardContent>
|
|
<Box display="flex" justifyContent="space-between" alignItems="center" mb={2}>
|
|
<Typography variant="h6">
|
|
총 {totalCount.toLocaleString()}개 자재 그룹
|
|
</Typography>
|
|
<Chip
|
|
label={`${materials.length}개 표시 중`}
|
|
color="primary"
|
|
variant="outlined"
|
|
/>
|
|
</Box>
|
|
|
|
<TableContainer component={Paper} variant="outlined">
|
|
<Table>
|
|
<TableHead>
|
|
<TableRow sx={{ bgcolor: 'grey.50' }}>
|
|
<TableCell><strong>번호</strong></TableCell>
|
|
<TableCell><strong>유형</strong></TableCell>
|
|
<TableCell><strong>자재명</strong></TableCell>
|
|
<TableCell align="center"><strong>총 수량</strong></TableCell>
|
|
<TableCell align="center"><strong>단위</strong></TableCell>
|
|
<TableCell align="center"><strong>사이즈</strong></TableCell>
|
|
<TableCell><strong>재질</strong></TableCell>
|
|
<TableCell align="center"><strong>라인 수</strong></TableCell>
|
|
</TableRow>
|
|
</TableHead>
|
|
<TableBody>
|
|
{materials.map((material, index) => (
|
|
<TableRow
|
|
key={material.id}
|
|
sx={{ '&:hover': { bgcolor: 'grey.50' } }}
|
|
>
|
|
<TableCell>
|
|
{page * rowsPerPage + index + 1}
|
|
</TableCell>
|
|
<TableCell>
|
|
<Chip
|
|
label={material.item_type || 'OTHER'}
|
|
size="small"
|
|
color={getItemTypeColor(material.item_type)}
|
|
/>
|
|
</TableCell>
|
|
<TableCell>
|
|
<Typography variant="body2" sx={{ maxWidth: 300 }}>
|
|
{material.original_description}
|
|
</Typography>
|
|
</TableCell>
|
|
<TableCell align="center">
|
|
<Typography variant="h6" color="primary">
|
|
{material.quantity.toLocaleString()}
|
|
</Typography>
|
|
</TableCell>
|
|
<TableCell align="center">
|
|
<Chip label={material.unit} size="small" />
|
|
</TableCell>
|
|
<TableCell align="center">
|
|
<Chip
|
|
label={material.size_spec || '-'}
|
|
size="small"
|
|
color="secondary"
|
|
/>
|
|
</TableCell>
|
|
<TableCell>
|
|
<Typography variant="body2" color="primary">
|
|
{material.material_grade || '-'}
|
|
</Typography>
|
|
</TableCell>
|
|
<TableCell align="center">
|
|
<Chip
|
|
label={`${material.line_count || 1}개 라인`}
|
|
size="small"
|
|
variant="outlined"
|
|
title={material.line_numbers_str}
|
|
/>
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
</TableContainer>
|
|
|
|
<TablePagination
|
|
component="div"
|
|
count={totalCount}
|
|
page={page}
|
|
onPageChange={handleChangePage}
|
|
rowsPerPage={rowsPerPage}
|
|
onRowsPerPageChange={handleChangeRowsPerPage}
|
|
rowsPerPageOptions={[10, 25, 50, 100]}
|
|
labelRowsPerPage="페이지당 행 수:"
|
|
labelDisplayedRows={({ from, to, count }) =>
|
|
`${from}-${to} / 총 ${count !== -1 ? count : to} 개`
|
|
}
|
|
/>
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
export default MaterialList;
|