🔍 구글 스타일 프로젝트 선택기로 전면 개편

핵심 변경사항:
 구글 검색창 스타일의 깔끔한 프로젝트 관리 페이지 완성
- 복잡한 카드 리스트 → 중앙 집중식 드롭다운 선택기
- 미니멀한 디자인으로 사용성 대폭 개선

🎯 구글 스타일 드롭다운 시스템
- 중앙 배치된 둥근 검색창 스타일 드롭다운
- 클릭 시 부드러운 확장 애니메이션 (둥근→사각형)
- 내장된 실시간 검색 기능 (프로젝트명/Job No./고객사)
- 외부 클릭 시 자동 닫힘

🎨 DevonThink 미니멀 디자인
- 중앙 정렬된 대형 'TK Project' 타이틀 (48px, 얇은 폰트)
- 충분한 여백과 깔끔한 레이아웃 (80vh 중앙 배치)
- 회색/파란색 위주의 절제된 색상 팔레트
- 부드러운 그림자와 호버 효과

📋 스마트 프로젝트 정보 표시
- 드롭다운 옵션: 프로젝트명 + Job No. + 고객사 + 상태
- 선택 후 상세 정보 카드 자동 표시 (fadeInUp 애니메이션)
- 프로젝트별 맞춤 액션 버튼 (상태에 따른 활성화/비활성화)
- 세션 스토리지 자동 저장

 인터랙티브 기능
- 드롭다운 열기 시 검색창 자동 포커스
- 실시간 필터링 (타이핑과 동시에 옵션 필터링)
- 키보드 네비게이션 지원 (Enter, Escape)
- 상태별 버튼 동적 업데이트

🔄 상태별 버튼 로직
- 계획 단계: 생산회의록 비활성화
- 진행중: 모든 기능 활성화
- 제작중: 생산회의록 + 프로젝트 관리 활성화
- 완료: 모든 버튼 '(완료)' 표시로 변경

📊 하단 통계 표시
- 간소화된 4개 통계 (전체/진행중/제작중/지연)
- 중앙 정렬된 깔끔한 배치
- 큰 숫자 + 작은 라벨 구조

💾 하드코딩 데이터 구조화
- getProjectData() 함수로 중앙 관리
- 4개 프로젝트 완전한 정보 (고객사, 납기, PM, 상태 등)
- 상태별 클래스와 진행률 포함

🎭 애니메이션 효과
- 페이지 로드 시 순차적 fade-in
- 드롭다운 화살표 회전 (180도)
- 프로젝트 정보 카드 fadeInUp
- 호버 시 그림자 확대

시연 준비: 구글 수준의 직관적이고 깔끔한 프로젝트 선택 시스템 완성
This commit is contained in:
Hyungi Ahn
2025-09-15 11:56:56 +09:00
parent 23eb3f1f46
commit 5375842144
3 changed files with 552 additions and 564 deletions

View File

@@ -359,146 +359,211 @@ function initializePage(pageId) {
function initializeProjectManagement() {
console.log('프로젝트 관리 페이지 초기화');
// 프로젝트 카드 애니메이션
animateElements('.project-card');
// 드롭다운 외부 클릭 이벤트 설정
setupDropdownOutsideClick();
// 필터 버튼 이벤트 설정
setupProjectFilters();
// 검색 기능 설정
setupProjectSearch();
// 애니메이션 효과
animateElements('.project-selector-header');
animateElements('.project-dropdown-container');
animateElements('.project-stats-simple');
}
// 프로젝트 필터 설정
function setupProjectFilters() {
const filterButtons = document.querySelectorAll('.filter-btn');
filterButtons.forEach(btn => {
btn.addEventListener('click', function() {
// 활성 버튼 변경
filterButtons.forEach(b => b.classList.remove('active'));
this.classList.add('active');
// 필터 적용
const filter = this.getAttribute('data-filter');
filterProjects(filter);
});
// 드롭다운 외부 클릭 설정
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 setupProjectSearch() {
const searchInput = document.querySelector('.search-input');
const searchBtn = document.querySelector('.search-btn');
// 프로젝트 드롭다운 토글
function toggleProjectDropdown() {
const dropdownMenu = document.getElementById('project-dropdown-menu');
const dropdownDisplay = document.querySelector('.dropdown-display');
if (searchInput && searchBtn) {
searchBtn.addEventListener('click', performSearch);
searchInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
performSearch();
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 performSearch() {
const searchInput = document.querySelector('.search-input');
const query = searchInput.value.toLowerCase().trim();
// 드롭다운에서 프로젝트 선택
function selectProjectFromDropdown(jobNo) {
const projectData = getProjectData(jobNo);
if (!projectData) return;
if (!query) {
showAllProjects();
// 드롭다운 닫기
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;
}
const projectCards = document.querySelectorAll('.project-card');
let visibleCount = 0;
projectCards.forEach(card => {
const title = card.querySelector('h3').textContent.toLowerCase();
const jobNo = card.querySelector('.job-no').textContent.toLowerCase();
const customer = card.querySelector('.info-value').textContent.toLowerCase();
if (title.includes(query) || jobNo.includes(query) || customer.includes(query)) {
card.style.display = 'block';
visibleCount++;
} else {
card.style.display = 'none';
}
});
showNotification(`${visibleCount}개의 프로젝트를 찾았습니다.`, 'info');
}
// 프로젝트 필터링
function filterProjects(filter) {
const projectCards = document.querySelectorAll('.project-card');
let visibleCount = 0;
projectCards.forEach(card => {
if (filter === 'all') {
card.style.display = 'block';
visibleCount++;
} else {
const hasStatus = card.classList.contains(`status-${filter}`);
if (hasStatus) {
card.style.display = 'block';
visibleCount++;
} else {
card.style.display = 'none';
}
}
});
// 통계 업데이트
updateProjectStats(filter, visibleCount);
}
// 모든 프로젝트 표시
function showAllProjects() {
const projectCards = document.querySelectorAll('.project-card');
projectCards.forEach(card => {
card.style.display = 'block';
});
}
// 프로젝트 통계 업데이트
function updateProjectStats(filter, count) {
const filterName = {
'all': '전체',
'planning': '계획',
'in-progress': '진행중',
'production': '제작중',
'completed': '완료'
};
showNotification(`${filterName[filter]} 프로젝트: ${count}`, 'info');
}
// 프로젝트 선택
function selectProject(jobNo) {
selectedProject = jobNo;
// 프로젝트 정보 저장
const projectCard = document.querySelector(`[data-job-no="${jobNo}"]`);
if (projectCard) {
const projectName = projectCard.querySelector('h3').textContent;
const customer = projectCard.querySelector('.info-value').textContent;
// 세션 스토리지에 저장
sessionStorage.setItem('selectedProject', JSON.stringify({
jobNo: jobNo,
name: projectName,
customer: customer
}));
showNotification(`${projectName} (${jobNo}) 프로젝트가 선택되었습니다.`, 'success');
// 프로젝트 세부 관리 페이지로 이동 (현재는 알림만)
setTimeout(() => {
showNotification('프로젝트 세부 관리 기능은 추후 구현 예정입니다.', 'info');
}, 1000);
}
showNotification('프로젝트 세부 관리 페이지는 추후 구현 예정입니다.', 'info');
}
// 프로젝트 등록 페이지 초기화
@@ -921,5 +986,9 @@ window.hideModal = hideModal;
window.showNotification = showNotification;
window.clearForm = clearForm;
window.selectProject = selectProject;
window.toggleProjectDropdown = toggleProjectDropdown;
window.selectProjectFromDropdown = selectProjectFromDropdown;
window.filterProjects = filterProjects;
window.goToProjectDetail = goToProjectDetail;
console.log('TK Project Demo JavaScript 로드 완료');