// TK Project Demo - Main JavaScript // 전역 변수 let currentPage = 'project-management'; let selectedProject = null; let currentUser = { name: '김그룹장', role: '생산팀', avatar: '김' }; // 하드코딩된 데이터 const demoData = { projects: [ { jobNo: 'TK-2024-015', name: 'ABC 공장 배관공사', client: 'ABC 케미칼', contractAmount: '150,000,000', orderDate: '2024-01-15', deliveryDate: '2024-03-30', deliveryMethod: '현장납품', productionType: '자체제작', status: '승인완료' } ], processChart: { design: { progress: 100, status: '완료', dueDate: '2024-02-15', responsible: '박설계' }, procurement: { progress: 85, status: '진행중', dueDate: '2024-02-28', responsible: '김구매' }, production: { progress: 60, status: '진행중', dueDate: '2024-03-20', responsible: '이생산' }, inspection: { progress: 0, status: '대기', dueDate: '2024-03-25', responsible: '최품질' }, delivery: { progress: 0, status: '대기', dueDate: '2024-03-30', responsible: '박PM' } }, schedules: [ { date: '09/20', type: '외주출고', title: '도장 작업 출고', memo: 'A구역 파이프 20본, B구역 밸브 5개\n업체: 대한도장\n연락처: 010-1234-5678', responsible: '김구매', urgency: 'urgent' }, { date: '09/22', type: '검사일정', title: '압력시험', memo: '시험압력: 15bar, 30분간 유지\n검사자: 최품질, 이생산', responsible: '최품질', urgency: 'normal' } ], deliveries: [ { item: '파이프 4인치 x 50EA', date: '입고완료 - 09/10', status: 'completed' }, { item: '밸브 2인치 x 10EA', date: '입고예정 - 09/16', status: 'warning' }, { item: '엘보 4인치 x 20EA', date: '지연 - 09/12 → 09/18', status: 'delayed' } ], followUps: [ { priority: '긴급', title: '밸브 A 납기 지연 대응', description: '주 공급업체 생산 지연으로 대체 업체 검토 필요', responsible: '김구매', registeredDate: '09/10', expectedResolution: '09/17', status: '진행중', level: 'high' }, { priority: '높음', title: '용접 검사 일정 조정', description: '고객사 일정 변경으로 검사일 재조정 필요', responsible: '최품질', registeredDate: '09/12', expectedResolution: '09/20', status: '검토중', level: 'medium' } ], purchaseOrders: [ { poNumber: 'PO-2024-0156', project: 'TK-2024-015', item: '스테인리스 파이프 4인치 SCH40', qty: 50, unit: 'EA', supplier: '대한파이프', orderDate: '2024-09-01', expectedDate: '2024-09-15', buyer: '김구매', status: 'pending' }, { poNumber: 'PO-2024-0157', project: 'TK-2024-015', item: '게이트밸브 2인치 150LB', qty: 10, unit: 'EA', supplier: '코리아밸브', orderDate: '2024-09-05', expectedDate: '2024-09-16', buyer: '김구매', status: 'inspecting' } ], materials: [ { item: '파이프 4인치 SCH40', required: 50, status: 'available', location: 'A-3-상단', availableQty: 45, lastUpdate: '2024-09-14 09:00' }, { item: '엘보 4인치 150LB', required: 20, status: 'ordered', currentStage: '구매 진행 중', expectedDate: '2024-09-18', availableQty: 0 }, { item: '플랜지 4인치 150LB', required: 15, status: 'not-requested', currentStage: '설계팀 구매 요청 대기', availableQty: 0, note: '설계 변경으로 사양 확정 대기' }, { item: '밸브 2인치 150LB', required: 5, status: 'ready', location: 'B-2-중단', availableQty: 5, note: '인수 대기 중' } ], issues: [ { time: '14:30', type: '자재부족', description: '엘보 4인치 10EA 부족으로 작업 중단', urgency: '높음', solution: '구매팀에 긴급 요청, 대체재 검토', responsible: '김그룹장', photos: ['issue_001.jpg'] }, { time: '10:15', type: '품질이슈', description: '용접부 기공 발견, 재작업 필요', urgency: '보통', solution: '해당 부위 그라인딩 후 재용접', responsible: '이용접사', photos: ['quality_001.jpg'] } ] }; // DOM이 로드되면 초기화 document.addEventListener('DOMContentLoaded', function() { initializeApp(); setupEventListeners(); showPage(currentPage); }); // 앱 초기화 function initializeApp() { console.log('TK Project Demo 초기화 중...'); // 사용자 정보 업데이트 updateUserInfo(); // 데이터 로드 loadDemoData(); console.log('TK Project Demo 초기화 완료'); } // 이벤트 리스너 설정 function setupEventListeners() { // 네비게이션 클릭 이벤트 document.querySelectorAll('.nav-item').forEach(item => { item.addEventListener('click', function(e) { e.preventDefault(); const pageId = this.getAttribute('onclick').match(/'([^']+)'/)[1]; showPage(pageId); }); }); // 진행률 슬라이더 이벤트 const progressSlider = document.querySelector('.progress-slider'); if (progressSlider) { progressSlider.addEventListener('input', function() { const value = this.value; const display = document.querySelector('.progress-value'); if (display) { display.textContent = value + '%'; } }); } // 버튼 클릭 이벤트 setupButtonEvents(); // 폼 이벤트 setupFormEvents(); } // 버튼 이벤트 설정 function setupButtonEvents() { // 프로젝트 승인 버튼 const approveBtn = document.querySelector('.btn-primary'); if (approveBtn && approveBtn.textContent.includes('프로젝트 승인')) { approveBtn.addEventListener('click', function() { showNotification('프로젝트가 성공적으로 승인되었습니다!', 'success'); }); } // 검수 시작 버튼 document.querySelectorAll('.btn').forEach(btn => { if (btn.textContent.includes('검수 시작')) { btn.addEventListener('click', function() { showNotification('검수 프로세스를 시작합니다.', 'info'); // 버튼 상태 변경 this.textContent = '🔄 검수 진행중'; this.classList.remove('btn-primary'); this.classList.add('btn-warning'); }); } if (btn.textContent.includes('인수 처리')) { btn.addEventListener('click', function() { showNotification('자재 인수가 완료되었습니다.', 'success'); this.textContent = '✅ 인수완료'; this.classList.remove('btn-primary'); this.classList.add('btn-success'); this.disabled = true; }); } if (btn.textContent.includes('데일리 체크에 기록')) { btn.addEventListener('click', function() { showNotification('데일리 체크에 이슈가 등록되었습니다.', 'warning'); }); } }); // 선반 클릭 이벤트 document.querySelectorAll('.shelf.available').forEach(shelf => { shelf.addEventListener('click', function() { // 기존 선택 해제 document.querySelectorAll('.shelf').forEach(s => s.classList.remove('selected')); // 현재 선택 this.classList.add('selected'); // 선택된 위치 업데이트 const locationDisplay = document.querySelector('.selected-location .location'); if (locationDisplay) { locationDisplay.textContent = this.textContent + '-중단'; } showNotification(`${this.textContent} 선반이 선택되었습니다.`, 'info'); }); }); } // 폼 이벤트 설정 function setupFormEvents() { // BOM 조회 버튼 const bomSearchBtn = document.querySelector('.search-input .btn-primary'); if (bomSearchBtn && bomSearchBtn.textContent.includes('BOM 조회')) { bomSearchBtn.addEventListener('click', function() { const input = document.querySelector('.search-input .form-input'); const jobNo = input.value || 'TK-2024-015'; showNotification(`${jobNo} 프로젝트의 BOM 정보를 조회했습니다.`, 'success'); // 자재 리스트 업데이트 (이미 하드코딩되어 있음) animateElements('.material-item'); }); } } // 페이지 표시 function showPage(pageId) { // 모든 페이지 숨기기 document.querySelectorAll('.page').forEach(page => { page.classList.remove('active'); }); // 모든 네비게이션 아이템 비활성화 document.querySelectorAll('.nav-item').forEach(item => { item.classList.remove('active'); }); // 선택된 페이지 표시 const targetPage = document.getElementById(pageId); if (targetPage) { targetPage.classList.add('active'); targetPage.classList.add('fade-in'); // 네비게이션 아이템 활성화 const navItem = document.querySelector(`[onclick*="${pageId}"]`); if (navItem) { navItem.classList.add('active'); } currentPage = pageId; // 페이지별 초기화 initializePage(pageId); } } // 페이지별 초기화 function initializePage(pageId) { switch (pageId) { case 'project-registration': initializeProjectRegistration(); break; case 'production-meeting': initializeProductionMeeting(); break; case 'incoming-inspection': initializeIncomingInspection(); break; case 'production-work': initializeProductionWork(); break; case 'project-management': initializeProjectManagement(); break; } } // 프로젝트 관리 페이지 초기화 function initializeProjectManagement() { console.log('프로젝트 관리 페이지 초기화'); // 드롭다운 외부 클릭 이벤트 설정 setupDropdownOutsideClick(); // 애니메이션 효과 animateElements('.project-selector-header'); animateElements('.project-dropdown-container'); animateElements('.project-stats-simple'); } // 드롭다운 외부 클릭 설정 function setupDropdownOutsideClick() { document.addEventListener('click', function(e) { const dropdown = document.querySelector('.project-dropdown'); const dropdownMenu = document.getElementById('project-dropdown-menu'); const dropdownDisplay = document.querySelector('.dropdown-display'); if (!dropdown.contains(e.target)) { dropdownMenu.classList.remove('active'); dropdownDisplay.classList.remove('active'); } }); } // 프로젝트 드롭다운 토글 function toggleProjectDropdown() { const dropdownMenu = document.getElementById('project-dropdown-menu'); const dropdownDisplay = document.querySelector('.dropdown-display'); dropdownMenu.classList.toggle('active'); dropdownDisplay.classList.toggle('active'); // 검색 입력창에 포커스 if (dropdownMenu.classList.contains('active')) { setTimeout(() => { const searchInput = document.querySelector('.dropdown-search-input'); if (searchInput) { searchInput.focus(); } }, 100); } } // 드롭다운에서 프로젝트 선택 function selectProjectFromDropdown(jobNo) { const projectData = getProjectData(jobNo); if (!projectData) return; // 드롭다운 닫기 const dropdownMenu = document.getElementById('project-dropdown-menu'); const dropdownDisplay = document.querySelector('.dropdown-display'); dropdownMenu.classList.remove('active'); dropdownDisplay.classList.remove('active'); // 선택된 프로젝트 텍스트 업데이트 const selectedText = document.getElementById('selected-project-text'); selectedText.textContent = `${projectData.name} (${jobNo})`; // 프로젝트 정보 카드 표시 showProjectInfo(projectData); // 전역 변수 업데이트 selectedProject = jobNo; // 세션 스토리지에 저장 sessionStorage.setItem('selectedProject', JSON.stringify(projectData)); showNotification(`${projectData.name} 프로젝트가 선택되었습니다.`, 'success'); } // 프로젝트 데이터 가져오기 function getProjectData(jobNo) { const projectsData = { 'TK-2024-015': { jobNo: 'TK-2024-015', name: 'ABC 공장 배관공사', customer: 'ABC 케미칼', deadline: '2024-03-30', delivery: '현장납품', pm: '이PM', status: '제작중', statusClass: 'status-production', progress: '75%' }, 'TK-2024-016': { jobNo: 'TK-2024-016', name: 'DEF 플랜트 배관 설치', customer: 'DEF 화학', deadline: '2024-04-15', delivery: '공장인도', pm: '박PM', status: '계획', statusClass: 'status-planning', progress: '25%' }, 'TK-2024-017': { jobNo: 'TK-2024-017', name: 'GHI 정유 공장 개보수', customer: 'GHI 정유 / 한국엔지니어링', deadline: '2024-05-20', delivery: '부분납품', pm: '최PM', status: '진행중', statusClass: 'status-in-progress', progress: '60%' }, 'TK-2024-012': { jobNo: 'TK-2024-012', name: 'JKL 화학 공장 신설', customer: 'JKL 화학', deadline: '2024-02-28', delivery: '현장납품', pm: '김PM', status: '완료', statusClass: 'status-completed', progress: '100%' } }; return projectsData[jobNo]; } // 프로젝트 정보 표시 function showProjectInfo(projectData) { const infoContainer = document.getElementById('selected-project-info'); // 정보 업데이트 document.getElementById('info-project-title').textContent = projectData.name; document.getElementById('info-job-no').textContent = projectData.jobNo; document.getElementById('info-customer').textContent = projectData.customer; document.getElementById('info-deadline').textContent = projectData.deadline; document.getElementById('info-delivery').textContent = projectData.delivery; document.getElementById('info-pm').textContent = projectData.pm; document.getElementById('info-progress').textContent = projectData.progress; // 상태 배지 업데이트 const statusBadge = document.getElementById('info-status'); statusBadge.textContent = projectData.status; statusBadge.className = `status-badge ${projectData.statusClass}`; // 버튼 상태 업데이트 updateActionButtons(projectData); // 정보 카드 표시 infoContainer.style.display = 'block'; } // 액션 버튼 상태 업데이트 function updateActionButtons(projectData) { const buttons = { meeting: document.getElementById('btn-production-meeting'), inspection: document.getElementById('btn-incoming-inspection'), work: document.getElementById('btn-production-work') }; // 모든 버튼 활성화 Object.values(buttons).forEach(btn => { btn.classList.remove('disabled'); btn.style.opacity = '1'; btn.style.pointerEvents = 'auto'; }); // 상태에 따른 버튼 비활성화 switch (projectData.statusClass) { case 'status-planning': buttons.meeting.classList.add('disabled'); buttons.meeting.style.opacity = '0.5'; buttons.meeting.style.pointerEvents = 'none'; break; case 'status-completed': buttons.meeting.textContent = '🏭 생산회의록 (완료)'; buttons.inspection.textContent = '📦 입고 검수 (완료)'; buttons.work.textContent = '🔧 생산팀 작업 (완료)'; break; } } // 드롭다운 프로젝트 필터링 function filterProjects(query) { const options = document.querySelectorAll('.dropdown-option'); const searchQuery = query.toLowerCase().trim(); options.forEach(option => { const title = option.querySelector('.option-title').textContent.toLowerCase(); const jobNo = option.querySelector('.option-job-no').textContent.toLowerCase(); const customer = option.querySelector('.option-customer').textContent.toLowerCase(); if (!searchQuery || title.includes(searchQuery) || jobNo.includes(searchQuery) || customer.includes(searchQuery)) { option.style.display = 'block'; } else { option.style.display = 'none'; } }); } // 프로젝트 세부 관리로 이동 function goToProjectDetail() { if (!selectedProject) { showNotification('프로젝트를 먼저 선택해주세요.', 'warning'); return; } showNotification('프로젝트 세부 관리 페이지는 추후 구현 예정입니다.', 'info'); } // 프로젝트 등록 페이지 초기화 function initializeProjectRegistration() { console.log('프로젝트 등록 페이지 초기화'); // 폼 이벤트 리스너 설정 setupProjectForm(); // Job No. 미리보기 업데이트 updateJobNoPreview(); // 요청 리스트 애니메이션 animateElements('.request-item'); } // 프로젝트 폼 설정 function setupProjectForm() { const form = document.querySelector('.project-form'); if (!form) return; // 폼 제출 이벤트 form.addEventListener('submit', function(e) { e.preventDefault(); handleProjectSubmission(); }); // 입력 필드 변경시 Job No. 미리보기 업데이트 const inputs = form.querySelectorAll('input, select'); inputs.forEach(input => { input.addEventListener('input', updateJobNoPreview); }); } // 프로젝트 제출 처리 function handleProjectSubmission() { const form = document.querySelector('.project-form'); const formData = new FormData(form); // 입력값 검증 const projectName = document.getElementById('project-name').value; const endUser = document.getElementById('end-user').value; const deliveryDate = document.getElementById('delivery-date').value; const deliveryMethod = document.getElementById('delivery-method').value; if (!projectName || !endUser || !deliveryDate || !deliveryMethod) { showNotification('필수 항목을 모두 입력해주세요.', 'warning'); return; } // 제출 버튼 상태 변경 const submitBtn = document.getElementById('submit-btn'); const originalText = submitBtn.textContent; submitBtn.textContent = '📤 요청 중...'; submitBtn.disabled = true; // 가상 제출 처리 (2초 후 완료) setTimeout(() => { // 새로운 Job No. 생성 const newJobNo = generateJobNo(); // 성공 메시지 showNotification(`프로젝트 등록 요청이 완료되었습니다! (예상 Job No: ${newJobNo})`, 'success'); // 요청 리스트에 새 항목 추가 addNewRequestToList(projectName, endUser, deliveryDate, deliveryMethod); // 폼 초기화 clearForm(); // 버튼 복원 submitBtn.textContent = originalText; submitBtn.disabled = false; }, 2000); } // Job No. 생성 function generateJobNo() { const year = new Date().getFullYear(); const randomNum = Math.floor(Math.random() * 900) + 100; // 100-999 return `TK-${year}-${randomNum}`; } // Job No. 미리보기 업데이트 function updateJobNoPreview() { const projectName = document.getElementById('project-name')?.value; const previewElement = document.getElementById('preview-job-no'); if (!previewElement) return; if (projectName && projectName.length > 0) { const year = new Date().getFullYear(); const nextNum = String(Math.floor(Math.random() * 900) + 100); previewElement.textContent = `TK-${year}-${nextNum}`; previewElement.style.color = 'var(--dt-primary)'; } else { previewElement.textContent = 'TK-2024-XXX'; previewElement.style.color = 'var(--dt-gray-500)'; } } // 새 요청을 리스트에 추가 function addNewRequestToList(projectName, endUser, deliveryDate, deliveryMethod) { const requestList = document.querySelector('.request-list'); if (!requestList) return; const epcCustomer = document.getElementById('epc-customer')?.value; const customerText = epcCustomer ? `${endUser} / ${epcCustomer}` : endUser; const newItem = document.createElement('div'); newItem.className = 'request-item status-pending'; newItem.innerHTML = `