feat(tkeg, gateway): tkeg 대시보드 리디자인 + gateway 구매관리 네이밍 수정
- tkeg: MUI 기반 대시보드 전면 리디자인 (theme, 메트릭 카드, 프로젝트 Autocomplete, Quick Action, 관리자 섹션) - gateway: tkpurchase 카드 "소모품 관리" → "구매관리"로 복원 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
224
tkeg/web/src/App.jsx
Normal file
224
tkeg/web/src/App.jsx
Normal file
@@ -0,0 +1,224 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import DashboardPage from './pages/dashboard/DashboardPage';
|
||||
import { UserMenu, ErrorBoundary } from './components/common';
|
||||
import NewMaterialsPage from './pages/NewMaterialsPage';
|
||||
import BOMManagementPage from './pages/BOMManagementPage';
|
||||
import UnifiedBOMPage from './pages/UnifiedBOMPage';
|
||||
import SystemSettingsPage from './pages/SystemSettingsPage';
|
||||
import PurchaseBatchPage from './pages/PurchaseBatchPage';
|
||||
import PurchaseRequestPage from './pages/PurchaseRequestPage';
|
||||
import SystemLogsPage from './pages/SystemLogsPage';
|
||||
import LogMonitoringPage from './pages/LogMonitoringPage';
|
||||
import InactiveProjectsPage from './pages/InactiveProjectsPage';
|
||||
import api from './api';
|
||||
import { config } from './config';
|
||||
import './App.css';
|
||||
|
||||
function getSSOToken() {
|
||||
const match = document.cookie.match(/sso_token=([^;]*)/);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
||||
function parseJwt(token) {
|
||||
try {
|
||||
const base64Url = token.split('.')[1];
|
||||
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
||||
return JSON.parse(atob(base64));
|
||||
} catch { return null; }
|
||||
}
|
||||
|
||||
function App() {
|
||||
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [user, setUser] = useState(null);
|
||||
const [currentPage, setCurrentPage] = useState('dashboard');
|
||||
const [pageParams, setPageParams] = useState({});
|
||||
const [projects, setProjects] = useState([]);
|
||||
const [editingProject, setEditingProject] = useState(null);
|
||||
const [editedProjectName, setEditedProjectName] = useState('');
|
||||
const [showCreateProject, setShowCreateProject] = useState(false);
|
||||
const [newProjectCode, setNewProjectCode] = useState('');
|
||||
const [newProjectName, setNewProjectName] = useState('');
|
||||
const [newClientName, setNewClientName] = useState('');
|
||||
const [inactiveProjects, setInactiveProjects] = useState(() => {
|
||||
try {
|
||||
const saved = localStorage.getItem('tkeg_inactiveProjects');
|
||||
return saved ? new Set(JSON.parse(saved)) : new Set();
|
||||
} catch { return new Set(); }
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
localStorage.setItem('tkeg_inactiveProjects', JSON.stringify(Array.from(inactiveProjects)));
|
||||
} catch {}
|
||||
}, [inactiveProjects]);
|
||||
|
||||
const loadProjects = async () => {
|
||||
try {
|
||||
const response = await api.get('/jobs/');
|
||||
if (response.data?.jobs) {
|
||||
setProjects(response.data.jobs);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('프로젝트 목록 로드 실패:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleActivateProject = (project) => {
|
||||
const projectId = project.job_no || project.id;
|
||||
setInactiveProjects(prev => {
|
||||
const newSet = new Set(prev);
|
||||
newSet.delete(projectId);
|
||||
return newSet;
|
||||
});
|
||||
};
|
||||
|
||||
// SSO 인증 확인
|
||||
useEffect(() => {
|
||||
const token = getSSOToken();
|
||||
if (!token) {
|
||||
window.location.href = config.ssoLoginUrl(window.location.href);
|
||||
return;
|
||||
}
|
||||
const payload = parseJwt(token);
|
||||
if (!payload) {
|
||||
window.location.href = config.ssoLoginUrl();
|
||||
return;
|
||||
}
|
||||
setUser({
|
||||
user_id: payload.user_id,
|
||||
username: payload.sub || payload.username,
|
||||
name: payload.name || payload.username || payload.sub,
|
||||
role: payload.role || 'user',
|
||||
department: payload.department,
|
||||
});
|
||||
setIsAuthenticated(true);
|
||||
setIsLoading(false);
|
||||
loadProjects();
|
||||
}, []);
|
||||
|
||||
const navigateToPage = (page, params = {}) => {
|
||||
setCurrentPage(page);
|
||||
setPageParams(params);
|
||||
};
|
||||
|
||||
const handleLogout = () => {
|
||||
document.cookie = `sso_token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/${config.cookieDomain}`;
|
||||
window.location.href = config.ssoLoginUrl();
|
||||
};
|
||||
|
||||
const renderCurrentPage = () => {
|
||||
switch (currentPage) {
|
||||
case 'dashboard':
|
||||
return (
|
||||
<DashboardPage
|
||||
user={user}
|
||||
projects={projects}
|
||||
pendingSignupCount={0}
|
||||
navigateToPage={navigateToPage}
|
||||
loadProjects={loadProjects}
|
||||
createProject={() => {}}
|
||||
updateProjectName={() => {}}
|
||||
deleteProject={() => {}}
|
||||
editingProject={editingProject}
|
||||
setEditingProject={setEditingProject}
|
||||
editedProjectName={editedProjectName}
|
||||
setEditedProjectName={setEditedProjectName}
|
||||
showCreateProject={showCreateProject}
|
||||
setShowCreateProject={setShowCreateProject}
|
||||
newProjectCode={newProjectCode}
|
||||
setNewProjectCode={setNewProjectCode}
|
||||
newProjectName={newProjectName}
|
||||
setNewProjectName={setNewProjectName}
|
||||
newClientName={newClientName}
|
||||
setNewClientName={setNewClientName}
|
||||
inactiveProjects={inactiveProjects}
|
||||
setInactiveProjects={setInactiveProjects}
|
||||
/>
|
||||
);
|
||||
case 'unified-bom':
|
||||
return <UnifiedBOMPage onNavigate={navigateToPage} selectedProject={pageParams.selectedProject} user={user} />;
|
||||
case 'materials':
|
||||
return (
|
||||
<BOMManagementPage
|
||||
onNavigate={navigateToPage}
|
||||
user={user}
|
||||
selectedProject={pageParams.selectedProject}
|
||||
fileId={pageParams.file_id}
|
||||
jobNo={pageParams.jobNo}
|
||||
bomName={pageParams.bomName}
|
||||
revision={pageParams.revision}
|
||||
filename={pageParams.filename}
|
||||
/>
|
||||
);
|
||||
case 'purchase-batch':
|
||||
return <PurchaseBatchPage onNavigate={navigateToPage} user={user} selectedProject={pageParams.selectedProject} />;
|
||||
case 'purchase-request':
|
||||
return <PurchaseRequestPage onNavigate={navigateToPage} user={user} selectedProject={pageParams.selectedProject} />;
|
||||
case 'system-settings':
|
||||
return <SystemSettingsPage onNavigate={navigateToPage} user={user} />;
|
||||
case 'system-logs':
|
||||
return <SystemLogsPage onNavigate={navigateToPage} user={user} />;
|
||||
case 'log-monitoring':
|
||||
return <LogMonitoringPage onNavigate={navigateToPage} user={user} />;
|
||||
case 'inactive-projects':
|
||||
return (
|
||||
<InactiveProjectsPage
|
||||
onNavigate={navigateToPage}
|
||||
user={user}
|
||||
projects={projects}
|
||||
inactiveProjects={inactiveProjects}
|
||||
onActivateProject={handleActivateProject}
|
||||
onDeleteProject={() => {}}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh', background: '#f7fafc' }}>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<div style={{ fontSize: '16px', color: '#718096' }}>알 수 없는 페이지입니다.</div>
|
||||
<button onClick={() => navigateToPage('dashboard')} style={{ background: '#4299e1', color: 'white', border: 'none', borderRadius: '6px', padding: '12px 24px', cursor: 'pointer', marginTop: '16px' }}>
|
||||
대시보드로 돌아가기
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh', background: '#f7fafc' }}>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<div style={{ fontSize: '16px', color: '#718096' }}>로딩 중...</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!isAuthenticated) return null;
|
||||
|
||||
return (
|
||||
<ErrorBoundary errorContext={{ user, currentPage, pageParams }}>
|
||||
<div style={{ minHeight: '100vh', background: '#f7fafc' }}>
|
||||
<div style={{
|
||||
background: 'white', borderBottom: '1px solid #e2e8f0',
|
||||
padding: '16px 32px', display: 'flex', justifyContent: 'space-between', alignItems: 'center'
|
||||
}}>
|
||||
<div>
|
||||
<h1 style={{ fontSize: '24px', fontWeight: '700', color: '#2d3748', margin: 0 }}>
|
||||
TK-EG BOM Management System
|
||||
</h1>
|
||||
<p style={{ color: '#718096', fontSize: '14px', margin: '4px 0 0 0' }}>
|
||||
{user?.name || user?.username}님 환영합니다
|
||||
</p>
|
||||
</div>
|
||||
<UserMenu user={user} onNavigate={navigateToPage} onLogout={handleLogout} />
|
||||
</div>
|
||||
{renderCurrentPage()}
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
Reference in New Issue
Block a user