Phase 1: 도면 자재 분석 업로드 페이지 구현

This commit is contained in:
Hyungi Ahn
2025-07-14 14:20:54 +09:00
parent 13c375477a
commit f3189dc050
10 changed files with 1595 additions and 0 deletions

View File

@@ -0,0 +1,187 @@
import React, { useState } from 'react';
import {
Typography,
Box,
Card,
CardContent,
Button,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
TextField,
Alert,
CircularProgress
} from '@mui/material';
import { Add, Assignment } from '@mui/icons-material';
function ProjectManager({ projects, selectedProject, setSelectedProject, onProjectsChange }) {
const [dialogOpen, setDialogOpen] = useState(false);
const [projectCode, setProjectCode] = useState('');
const [projectName, setProjectName] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const handleCreateProject = async () => {
if (!projectCode.trim() || !projectName.trim()) {
setError('프로젝트 코드와 이름을 모두 입력해주세요.');
return;
}
setLoading(true);
setError('');
try {
const response = await fetch('http://localhost:8000/api/projects', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
official_project_code: projectCode.trim(),
project_name: projectName.trim(),
design_project_code: projectCode.trim(),
is_code_matched: true,
status: 'active'
})
});
if (response.ok) {
const newProject = await response.json();
onProjectsChange();
setSelectedProject(newProject);
setDialogOpen(false);
setProjectCode('');
setProjectName('');
setError('');
} else {
const errorData = await response.json();
setError(errorData.detail || '프로젝트 생성에 실패했습니다.');
}
} catch (error) {
console.error('프로젝트 생성 실패:', error);
setError('네트워크 오류가 발생했습니다. 백엔드 서버가 실행 중인지 확인해주세요.');
} finally {
setLoading(false);
}
};
const handleCloseDialog = () => {
setDialogOpen(false);
setProjectCode('');
setProjectName('');
setError('');
};
return (
<Box>
<Box display="flex" justifyContent="space-between" alignItems="center" mb={2}>
<Typography variant="h4">
🗂 프로젝트 관리
</Typography>
<Button
variant="contained"
startIcon={<Add />}
onClick={() => setDialogOpen(true)}
>
프로젝트
</Button>
</Box>
{projects.length === 0 ? (
<Card>
<CardContent sx={{ textAlign: 'center', py: 4 }}>
<Assignment sx={{ fontSize: 64, color: 'primary.main', mb: 2 }} />
<Typography variant="h6" gutterBottom>
프로젝트가 없습니다
</Typography>
<Typography variant="body2" color="textSecondary" sx={{ mb: 3 }}>
프로젝트를 생성하여 시작하세요!
</Typography>
<Button
variant="contained"
startIcon={<Add />}
onClick={() => setDialogOpen(true)}
>
번째 프로젝트 생성
</Button>
</CardContent>
</Card>
) : (
<Box>
{projects.map((project) => (
<Card
key={project.id}
sx={{
mb: 2,
cursor: 'pointer',
border: selectedProject?.id === project.id ? 2 : 1,
borderColor: selectedProject?.id === project.id ? 'primary.main' : 'divider'
}}
onClick={() => setSelectedProject(project)}
>
<CardContent>
<Typography variant="h6">
{project.project_name || project.official_project_code}
</Typography>
<Typography variant="body2" color="primary" sx={{ mb: 1 }}>
코드: {project.official_project_code}
</Typography>
<Typography variant="body2" color="textSecondary">
상태: {project.status} | 생성일: {new Date(project.created_at).toLocaleDateString()}
</Typography>
</CardContent>
</Card>
))}
</Box>
)}
<Dialog open={dialogOpen} onClose={handleCloseDialog} maxWidth="sm" fullWidth>
<DialogTitle> 프로젝트 생성</DialogTitle>
<DialogContent>
{error && (
<Alert severity="error" sx={{ mb: 2 }}>
{error}
</Alert>
)}
<TextField
autoFocus
margin="dense"
label="프로젝트 코드"
placeholder="예: MP7-PIPING-R3"
fullWidth
variant="outlined"
value={projectCode}
onChange={(e) => setProjectCode(e.target.value)}
sx={{ mb: 2 }}
/>
<TextField
margin="dense"
label="프로젝트명"
placeholder="예: MP7 PIPING PROJECT Rev.3"
fullWidth
variant="outlined"
value={projectName}
onChange={(e) => setProjectName(e.target.value)}
/>
</DialogContent>
<DialogActions>
<Button onClick={handleCloseDialog} disabled={loading}>
취소
</Button>
<Button
onClick={handleCreateProject}
variant="contained"
disabled={loading}
startIcon={loading ? <CircularProgress size={20} /> : null}
>
{loading ? '생성 중...' : '생성'}
</Button>
</DialogActions>
</Dialog>
</Box>
);
}
export default ProjectManager;