const { useState, useEffect } = React; function Project() { // 상태 관리 const [projects, setProjects] = useState([]); const [filteredProjects, setFilteredProjects] = useState([]); const [isLoading, setIsLoading] = useState(false); const [currentUser, setCurrentUser] = useState('사용자'); const [currentPage, setCurrentPage] = useState(1); const [itemsPerPage] = useState(10); // 모달 상태 const [showProjectModal, setShowProjectModal] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false); const [currentProjectIdx, setCurrentProjectIdx] = useState(null); // 필터 상태 const [filters, setFilters] = useState({ status: '진행', search: '', manager: 'my' }); // UI 상태 const [showFilters, setShowFilters] = useState(false); const [showColumnDropdown, setShowColumnDropdown] = useState(false); const [visibleColumns, setVisibleColumns] = useState({ serial: false, plant: false, line: false, package: false, staff: false, process: false, expire: false, delivery: false, design: false, electric: false, program: false, budgetDue: false, budget: false, jasmin: false }); // 프로젝트 폼 상태 const [projectForm, setProjectForm] = useState({ idx: 0, name: '', process: '', sdate: '', edate: '', ddate: '', odate: '', userManager: '', status: '진행', memo: '' }); // 통계 상태 const [statusCounts, setStatusCounts] = useState({ 진행: 0, 완료: 0, 대기: 0, 중단: 0 }); // 컴포넌트 마운트시 초기화 useEffect(() => { getCurrentUser(); loadProjects(); }, []); // 필터 변경시 프로젝트 목록 새로 로드 useEffect(() => { loadProjects(); }, [filters.status, filters.manager]); // 검색어 변경시 필터링 useEffect(() => { filterData(); }, [filters.search, projects]); // 현재 사용자 정보 가져오기 const getCurrentUser = async () => { try { const response = await fetch('/Common/GetCurrentUser'); const data = await response.json(); if (data.Success && data.Data) { const userName = data.Data.userName || data.Data.name || '사용자'; setCurrentUser(userName); } } catch (error) { console.error('Error getting current user:', error); } }; // 프로젝트 목록 로드 const loadProjects = async () => { setIsLoading(true); try { const response = await fetch(`/Project/GetProjects?status=${filters.status}&userFilter=${filters.manager}`); const data = await response.json(); if (data.Success) { const projectData = data.Data || []; setProjects(projectData); setFilteredProjects(projectData); updateStatusCounts(projectData); if (data.CurrentUser) { setCurrentUser(data.CurrentUser); } } else { console.error('Error:', data.Message); showNotification('데이터를 불러오는데 실패했습니다.', 'error'); } } catch (error) { console.error('Error:', error); showNotification('데이터를 불러오는데 실패했습니다.', 'error'); } finally { setIsLoading(false); } }; // 상태별 카운트 업데이트 const updateStatusCounts = (projectData) => { const counts = { 진행: 0, 완료: 0, 대기: 0, 중단: 0 }; projectData.forEach(project => { const status = project.상태 || '진행'; counts[status] = (counts[status] || 0) + 1; }); setStatusCounts(counts); }; // 데이터 필터링 const filterData = () => { if (!filters.search.trim()) { setFilteredProjects(projects); setCurrentPage(1); return; } const searchTerm = filters.search.toLowerCase(); const filtered = projects.filter(project => { return (project.프로젝트명 && project.프로젝트명.toLowerCase().includes(searchTerm)) || (project.프로젝트공정 && project.프로젝트공정.toLowerCase().includes(searchTerm)) || (project.자산번호 && project.자산번호.toLowerCase().includes(searchTerm)) || (project.장비모델 && project.장비모델.toLowerCase().includes(searchTerm)) || (project.시리얼번호 && project.시리얼번호.toLowerCase().includes(searchTerm)) || (project.프로젝트관리자 && project.프로젝트관리자.toLowerCase().includes(searchTerm)) || (project.설계담당 && project.설계담당.toLowerCase().includes(searchTerm)) || (project.전장담당 && project.전장담당.toLowerCase().includes(searchTerm)) || (project.프로그램담당 && project.프로그램담당.toLowerCase().includes(searchTerm)); }); setFilteredProjects(filtered); setCurrentPage(1); }; // 프로젝트 추가 모달 표시 const showAddProjectModal = () => { setCurrentProjectIdx(null); setProjectForm({ idx: 0, name: '', process: '', sdate: '', edate: '', ddate: '', odate: '', userManager: '', status: '진행', memo: '' }); setShowProjectModal(true); }; // 프로젝트 편집 const editProject = async (idx) => { setCurrentProjectIdx(idx); setIsLoading(true); try { const response = await fetch(`/Project/GetProject?id=${idx}`); const data = await response.json(); if (data.Success && data.Data) { const project = data.Data; setProjectForm({ idx: project.idx, name: project.프로젝트명 || '', process: project.프로젝트공정 || '', sdate: project.시작일 || '', edate: project.완료일 || '', ddate: project.만료일 || '', odate: project.출고일 || '', userManager: project.프로젝트관리자 || '', status: project.상태 || '진행', memo: project.memo || '' }); setShowProjectModal(true); } else { showNotification('프로젝트 정보를 불러오는데 실패했습니다: ' + data.Message, 'error'); } } catch (error) { console.error('Error:', error); showNotification('프로젝트 정보를 불러오는데 실패했습니다.', 'error'); } finally { setIsLoading(false); } }; // 프로젝트 저장 (추가/수정) const saveProject = async (e) => { e.preventDefault(); setIsLoading(true); const projectData = { ...projectForm, idx: currentProjectIdx ? parseInt(projectForm.idx) : 0, sdate: projectForm.sdate || null, edate: projectForm.edate || null, ddate: projectForm.ddate || null, odate: projectForm.odate || null }; const url = currentProjectIdx ? '/Project/UpdateProject' : '/Project/CreateProject'; const method = currentProjectIdx ? 'PUT' : 'POST'; try { const response = await fetch(url, { method: method, headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(projectData) }); const data = await response.json(); if (data.Success) { showNotification(data.Message || (currentProjectIdx ? '프로젝트가 수정되었습니다.' : '프로젝트가 추가되었습니다.'), 'success'); setShowProjectModal(false); loadProjects(); } else { showNotification('오류: ' + data.Message, 'error'); } } catch (error) { console.error('Error:', error); showNotification('저장 중 오류가 발생했습니다.', 'error'); } finally { setIsLoading(false); } }; // 프로젝트 삭제 const deleteProject = async () => { if (!currentProjectIdx) return; setIsLoading(true); try { const response = await fetch(`/Project/DeleteProject?id=${currentProjectIdx}`, { method: 'DELETE' }); const data = await response.json(); if (data.Success) { showNotification(data.Message || '프로젝트가 삭제되었습니다.', 'success'); setShowDeleteModal(false); setShowProjectModal(false); loadProjects(); } else { showNotification('오류: ' + data.Message, 'error'); } } catch (error) { console.error('Error:', error); showNotification('삭제 중 오류가 발생했습니다.', 'error'); } finally { setIsLoading(false); } }; // 필터 초기화 const clearFilters = () => { setFilters({ status: '진행', search: '', manager: 'my' }); }; // 엑셀 다운로드 const exportToExcel = () => { if (filteredProjects.length === 0) { showNotification('내보낼 데이터가 없습니다.', 'warning'); return; } const headers = ['상태', '자산번호', '장비모델', '시리얼번호', '우선순위', '요청국가', '요청공장', '요청라인', '요청부서패키지', '요청자', '프로젝트공정', '시작일', '완료일', '만료일', '출고일', '프로젝트명', '프로젝트관리자', '설계담당', '전장담당', '프로그램담당', '예산만기일', '예산', '웹관리번호']; const csvContent = [ headers.join(','), ...filteredProjects.map(project => [ project.상태 || '', project.자산번호 || '', project.장비모델 || '', project.시리얼번호 || '', project.우선순위 || '', project.요청국가 || '', project.요청공장 || '', project.요청라인 || '', project.요청부서패키지 || '', project.요청자 || '', project.프로젝트공정 || '', project.시작일 || '', project.완료일 || '', project.만료일 || '', project.출고일 || '', project.프로젝트명 || '', project.프로젝트관리자 || '', project.설계담당 || '', project.전장담당 || '', project.프로그램담당 || '', project.예산만기일 || '', project.예산 || '', project.웹관리번호 || '' ].join(',')) ].join('\n'); const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' }); const link = document.createElement('a'); const url = URL.createObjectURL(blob); link.setAttribute('href', url); link.setAttribute('download', `프로젝트목록_${new Date().toISOString().split('T')[0]}.csv`); link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); }; // 유틸리티 함수들 const getStatusClass = (status) => { switch(status) { case '진행': return 'bg-blue-500/20 text-blue-300'; case '완료': return 'bg-green-500/20 text-green-300'; case '대기': return 'bg-yellow-500/20 text-yellow-300'; case '중단': return 'bg-red-500/20 text-red-300'; default: return 'bg-gray-500/20 text-gray-300'; } }; const formatDateToMonthDay = (dateString) => { if (!dateString) return ''; try { const date = new Date(dateString); if (isNaN(date.getTime())) return dateString; const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${month}-${day}`; } catch (error) { return dateString; } }; // 알림 표시 함수 const showNotification = (message, type = 'info') => { const colors = { info: 'bg-blue-500/90 backdrop-blur-sm', success: 'bg-green-500/90 backdrop-blur-sm', warning: 'bg-yellow-500/90 backdrop-blur-sm', error: 'bg-red-500/90 backdrop-blur-sm' }; const notification = document.createElement('div'); notification.className = `fixed top-4 right-4 ${colors[type]} text-white px-4 py-3 rounded-lg z-50 transition-all duration-300 transform translate-x-0 opacity-100 shadow-lg border border-white/20`; notification.innerHTML = `
${message}
`; notification.style.transform = 'translateX(100%)'; notification.style.opacity = '0'; document.body.appendChild(notification); setTimeout(() => { notification.style.transform = 'translateX(0)'; notification.style.opacity = '1'; }, 10); setTimeout(() => { notification.style.transform = 'translateX(100%)'; notification.style.opacity = '0'; setTimeout(() => notification.remove(), 300); }, 3000); }; // 페이지네이션 계산 const totalPages = Math.ceil(filteredProjects.length / itemsPerPage); const startIndex = (currentPage - 1) * itemsPerPage; const endIndex = startIndex + itemsPerPage; const paginatedProjects = filteredProjects.slice(startIndex, endIndex); const changePage = (page) => { if (page >= 1 && page <= totalPages) { setCurrentPage(page); } }; return (
{/* 프로젝트 목록 */}

프로젝트 목록

{/* 상태별 카드 */}
{statusCounts.진행}
진행
{statusCounts.완료}
완료
{statusCounts.대기}
대기
{statusCounts.중단}
중단
{/* 필터 영역 */} {showFilters && (
{/* 좌측: 필터 컨트롤 */}
setFilters({...filters, search: e.target.value})} placeholder="프로젝트명 검색..." className="w-full bg-white/20 border border-white/30 rounded-md px-2 py-1 text-white placeholder-white/60 focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent text-xs" />
{/* 우측: 액션 버튼들 */}
{showColumnDropdown && (
표시할 컬럼 선택
{Object.entries({ serial: '시리얼번호', plant: '요청공장', line: '요청라인', package: '요청부서패키지', staff: '요청자', process: '프로젝트공정', expire: '만료일', delivery: '출고일', design: '설계담당', electric: '전장담당', program: '프로그램담당', budgetDue: '예산만기일', budget: '예산', jasmin: '웹관리번호' }).map(([key, label]) => ( ))}
)}
)} {/* 데이터 테이블 */}
프로젝트 현황
{visibleColumns.serial && } {visibleColumns.plant && } {visibleColumns.line && } {visibleColumns.package && } {visibleColumns.staff && } {visibleColumns.process && } {visibleColumns.expire && } {visibleColumns.delivery && } {visibleColumns.design && } {visibleColumns.electric && } {visibleColumns.program && } {visibleColumns.budgetDue && } {visibleColumns.budget && } {visibleColumns.jasmin && } {isLoading ? ( ) : paginatedProjects.length === 0 ? ( ) : ( paginatedProjects.map(project => ( editProject(project.idx)} className="hover:bg-white/10 cursor-pointer transition-colors"> {visibleColumns.serial && } {visibleColumns.plant && } {visibleColumns.line && } {visibleColumns.package && } {visibleColumns.staff && } {visibleColumns.process && } {visibleColumns.expire && } {visibleColumns.delivery && } {visibleColumns.design && } {visibleColumns.electric && } {visibleColumns.program && } {visibleColumns.budgetDue && } {visibleColumns.budget && } {visibleColumns.jasmin && ( )} )) )}
상태 프로젝트명 자산번호 장비모델 우선순위 요청국가 프로젝트관리자 시작일 완료일시리얼번호요청공장요청라인요청부서패키지요청자프로젝트공정만료일출고일설계담당전장담당프로그램담당예산만기일예산웹관리번호
데이터를 불러오는 중...
데이터가 없습니다.
{project.상태 || '진행'} {project.프로젝트명 || ''} {project.자산번호 || ''} {project.장비모델 || ''} {project.우선순위 || ''} {project.요청국가 || ''} {project.프로젝트관리자 || ''} {formatDateToMonthDay(project.시작일)} {formatDateToMonthDay(project.완료일)}{project.시리얼번호 || ''}{project.요청공장 || ''}{project.요청라인 || ''}{project.요청부서패키지 || ''}{project.요청자 || ''}{project.프로젝트공정 || ''}{formatDateToMonthDay(project.만료일)}{formatDateToMonthDay(project.출고일)}{project.설계담당 || ''}{project.전장담당 || ''}{project.프로그램담당 || ''}{formatDateToMonthDay(project.예산만기일)}{project.예산 || ''} {project.웹관리번호 ? ( {project.웹관리번호} ) : ''}
{/* 페이징 */}
총 {filteredProjects.length}개 중 {startIndex + 1}-{Math.min(endIndex, filteredProjects.length)}개 표시
{Array.from({length: Math.min(5, totalPages)}, (_, i) => { const pageNum = Math.max(1, currentPage - 2) + i; if (pageNum > totalPages) return null; return ( ); })}
{/* 프로젝트 추가/편집 모달 */} {showProjectModal && (

{currentProjectIdx ? '프로젝트 편집' : '프로젝트 추가'}

setProjectForm({...projectForm, name: e.target.value})} required className="w-full bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white placeholder-white/60 focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent" />
setProjectForm({...projectForm, process: e.target.value})} className="w-full bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white placeholder-white/60 focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent" />
setProjectForm({...projectForm, sdate: e.target.value})} className="w-full bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent" />
setProjectForm({...projectForm, edate: e.target.value})} className="w-full bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent" />
setProjectForm({...projectForm, ddate: e.target.value})} className="w-full bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent" />
setProjectForm({...projectForm, odate: e.target.value})} className="w-full bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent" />
setProjectForm({...projectForm, userManager: e.target.value})} className="w-full bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white placeholder-white/60 focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent" />
{currentProjectIdx && ( )}
)} {/* 삭제 확인 모달 */} {showDeleteModal && (

삭제 확인

선택한 프로젝트를 삭제하시겠습니까?
이 작업은 되돌릴 수 없습니다.

)} {/* 로딩 인디케이터 */} {isLoading && (
처리 중...
)} {/* 외부 클릭시 드롭다운 닫기 */} {showColumnDropdown && (
setShowColumnDropdown(false)} >
)}
); }