diff --git a/docs/guides/work-report-time-input-guide.md b/docs/guides/work-report-time-input-guide.md new file mode 100644 index 0000000..7157e66 --- /dev/null +++ b/docs/guides/work-report-time-input-guide.md @@ -0,0 +1,242 @@ +# 작업보고서 시간 입력 가이드 + +**대상**: 현장 작업자, 관리자 +**페이지**: 일일 작업보고서 작성 (`/pages/work/report-create.html`) +**업데이트**: 2026-01-27 + +--- + +## 📱 시간 입력 방법 + +작업보고서 작성 시 작업시간과 부적합 시간을 쉽고 빠르게 입력할 수 있습니다. + +### 1단계: 시간 입력 영역 터치 + +작업보고서 테이블에서 **작업시간** 또는 **부적합 시간** 영역을 터치하세요. + +``` +┌─────────────────────────────────────┐ +│ 작업자 │ 날짜 │ 작업시간 │ 부적합 │ +├─────────────────────────────────────┤ +│ 김철수 │ 01.27│ [시간 선택] │ [0시간] │ +└─────────────────────────────────────┘ + ↑ 여기를 터치 +``` + +### 2단계: 원하는 시간 선택 + +팝업 창에서 자주 사용하는 시간을 선택하세요. + +``` +┌──────────────────────────────────┐ +│ 시간 선택 │ +├──────────────────────────────────┤ +│ [30분] [1시간] [2시간] │ +│ [4시간] [8시간] │ ← 큰 버튼으로 쉽게 선택 +├──────────────────────────────────┤ +│ 현재: 8시간 │ +│ [-30분] [+30분] │ ← 미세 조정 +├──────────────────────────────────┤ +│ [확인] │ +└──────────────────────────────────┘ +``` + +### 3단계: 확인 버튼 터치 + +선택한 시간이 맞으면 **확인** 버튼을 터치하세요. + +--- + +## ⏱️ 사용 예시 + +### 예시 1: 8시간 근무 + +**상황**: 오늘 8시간 근무했습니다. + +**입력 방법**: +1. 작업시간 영역 터치 +2. **[8시간]** 버튼 터치 +3. **[확인]** 버튼 터치 + +**결과**: `8시간` 표시 + +--- + +### 예시 2: 8시간 30분 근무 + +**상황**: 오늘 8시간 30분 근무했습니다. + +**입력 방법**: +1. 작업시간 영역 터치 +2. **[8시간]** 버튼 터치 +3. **[+30분]** 버튼 터치 (현재: 8시간 30분) +4. **[확인]** 버튼 터치 + +**결과**: `8시간 30분` 표시 + +--- + +### 예시 3: 7시간 근무 (7시간 30분에서 조정) + +**상황**: 처음에 7시간 30분을 선택했는데, 7시간으로 수정하고 싶습니다. + +**입력 방법**: +1. 작업시간 영역 터치 +2. **[8시간]** 버튼 터치 +3. **[-30분]** 버튼 터치 (현재: 7시간 30분) +4. **[-30분]** 버튼 한 번 더 터치 (현재: 7시간) +5. **[확인]** 버튼 터치 + +**결과**: `7시간` 표시 + +--- + +### 예시 4: 부적합 시간 입력 + +**상황**: 8시간 근무했는데, 그 중 1시간은 설계 미스로 인한 부적합 작업이었습니다. + +**입력 방법**: +1. **작업시간**: 8시간 입력 (위 예시 1 참고) +2. **부적합 시간** 영역 터치 +3. **[1시간]** 버튼 터치 +4. **[확인]** 버튼 터치 +5. 부적합 원인 드롭다운에서 **설계미스** 선택 + +**결과**: +- 작업시간: `8시간` +- 부적합: `1시간` +- 원인: `설계미스` + +--- + +## 🎯 빠른 입력 팁 + +### 자주 사용하는 시간 +대부분의 경우 아래 시간을 많이 사용합니다: +- **8시간**: 표준 근무시간 +- **4시간**: 반일 근무 +- **2시간**: 단시간 작업 +- **1시간**: 짧은 작업 +- **30분**: 아주 짧은 작업 + +### +/- 버튼 활용 +- **+30분**: 30분 단위로 증가 +- **-30분**: 30분 단위로 감소 +- 여러 번 터치 가능 (예: +30분 3번 = 1시간 30분 증가) + +### 취소 방법 +잘못 선택한 경우: +- 팝업 창 바깥을 터치하거나 +- ESC 키를 누르면 +- 변경 없이 닫힙니다 + +--- + +## ❗ 주의사항 + +### 시간 범위 +- **최소**: 0시간 +- **최대**: 24시간 +- **단위**: 30분 (0.5시간) + +### 부적합 시간 제한 +- 부적합 시간은 작업시간을 초과할 수 없습니다 +- 예: 작업시간 8시간 → 부적합 최대 8시간 + +### 부적합 시간 입력 시 +- 부적합 시간이 0보다 크면 자동으로 **부적합 원인** 선택창이 나타납니다 +- 반드시 원인을 선택해야 제출할 수 있습니다 + +--- + +## 🔍 자주 묻는 질문 (FAQ) + +### Q1: 15분 단위로 입력할 수 있나요? +**A**: 현재는 30분 단위만 지원합니다. 15분 단위가 필요하면 관리자에게 문의하세요. + +### Q2: 시간을 잘못 입력했어요. 어떻게 수정하나요? +**A**: 같은 영역을 다시 터치하면 팝업이 열립니다. 원하는 시간으로 다시 선택하고 확인하세요. + +### Q3: 팝업이 안 닫혀요. +**A**: +- 팝업 바깥 영역을 터치하거나 +- X 버튼을 터치하거나 +- ESC 키를 누르세요 + +### Q4: 숫자로 직접 입력할 수 없나요? +**A**: 터치 환경 최적화를 위해 버튼 선택 방식으로 변경되었습니다. 더 빠르고 정확한 입력이 가능합니다. + +### Q5: 이전 입력 값을 기억할 수 있나요? +**A**: 현재는 지원하지 않습니다. 향후 업데이트에서 추가 예정입니다. + +--- + +## 💡 실전 활용 시나리오 + +### 시나리오 1: 일반 근무일 +``` +작업자: 김철수 +작업시간: 8시간 +부적합: 없음 + +입력 순서: +1. 작업시간 터치 → 8시간 → 확인 +2. 부적합은 0시간으로 유지 +3. 제출 +``` + +### 시나리오 2: 자재 지연으로 인한 부적합 +``` +작업자: 이영희 +작업시간: 8시간 +부적합: 2시간 (입고지연) + +입력 순서: +1. 작업시간 터치 → 8시간 → 확인 +2. 부적합 터치 → 2시간 → 확인 +3. 부적합 원인: 입고지연 선택 +4. 제출 +``` + +### 시나리오 3: 반일 근무 +``` +작업자: 박민수 +작업시간: 4시간 +부적합: 없음 + +입력 순서: +1. 작업시간 터치 → 4시간 → 확인 +2. 부적합은 0시간으로 유지 +3. 제출 +``` + +### 시나리오 4: 잔업 (10시간 30분) +``` +작업자: 최지훈 +작업시간: 10시간 30분 +부적합: 없음 + +입력 순서: +1. 작업시간 터치 → 8시간 → +30분 5번 → 확인 + (또는 1시간 → +30분 19번) +2. 부적합은 0시간으로 유지 +3. 제출 +``` + +--- + +## 📞 문의 및 지원 + +### 기술 지원 +- **이메일**: support@technical-korea.com +- **전화**: 02-XXXX-XXXX +- **근무시간**: 평일 09:00 - 18:00 + +### 피드백 +개선 사항이나 건의사항이 있으시면 관리자에게 알려주세요. + +--- + +**마지막 업데이트**: 2026-01-27 +**버전**: 1.0 +**작성자**: 테크니컬코리아 개발팀 diff --git a/web-ui/css/daily-work-report.css b/web-ui/css/daily-work-report.css index 1e4ea82..e935cba 100644 --- a/web-ui/css/daily-work-report.css +++ b/web-ui/css/daily-work-report.css @@ -1,1215 +1,652 @@ -/* ========== 일일 작업보고서 전용 스타일 ========== */ +/* daily-work-report.css - 일일 작업보고서 스타일 */ -/* 메인 레이아웃 */ -.work-report-container { - min-height: 100vh; - background: var(--bg-secondary); +/* 탭 메뉴 스타일 */ +.tab-menu { display: flex; - flex-direction: column; + gap: 0.5rem; + border-bottom: 2px solid var(--border-color, #e5e7eb); + margin-bottom: 1.5rem; } -.work-report-header { - background: linear-gradient(135deg, var(--primary-600) 0%, var(--primary-700) 100%); +/* TBM 세션 그룹 스타일 */ +.tbm-session-group { + margin-bottom: 2rem; +} + +.tbm-session-header { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; - padding: var(--space-8) var(--space-6); - text-align: center; - box-shadow: var(--shadow-lg); + padding: 0.75rem 1.5rem; + border-radius: 8px 8px 0 0; + display: flex; + align-items: center; + gap: 1rem; + font-size: 0.875rem; } -.work-report-header h1 { - font-size: var(--text-4xl); - font-weight: var(--font-bold); - margin-bottom: var(--space-2); - text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +.tbm-session-badge { + background-color: rgba(255, 255, 255, 0.3); + padding: 0.25rem 0.75rem; + border-radius: 12px; + font-weight: 600; + font-size: 0.75rem; } -.work-report-header .subtitle { - font-size: var(--text-lg); +.tbm-session-date { + font-weight: 600; + font-size: 1rem; +} + +.tbm-session-creator { + font-size: 0.8rem; opacity: 0.9; - font-weight: var(--font-medium); } -.work-report-main { - flex: 1; - padding: var(--space-8) var(--space-6); - max-width: 1200px; - margin: 0 auto; +.tbm-session-count { + background-color: rgba(255, 255, 255, 0.2); + padding: 0.25rem 0.625rem; + border-radius: 12px; + font-weight: 600; + margin-left: auto; +} + +.tbm-session-info { + opacity: 0.95; + font-size: 0.875rem; +} + +/* TBM 작업 테이블 스타일 */ +.tbm-table-container { + overflow-x: auto; + border: 1px solid var(--border-color, #e5e7eb); + border-radius: 0 0 8px 8px; + background: white; +} + +.tbm-work-table { width: 100%; + border-collapse: collapse; + font-size: 0.875rem; } -/* 뒤로가기 버튼 */ -.back-button { - display: inline-flex; - align-items: center; - gap: var(--space-2); - padding: var(--space-3) var(--space-4); - background: var(--bg-primary); - color: var(--primary-600); - border: 2px solid var(--primary-200); - border-radius: var(--radius-lg); - text-decoration: none; - font-weight: var(--font-semibold); - transition: var(--transition-normal); - margin-bottom: var(--space-6); - box-shadow: var(--shadow-sm); +.tbm-work-table thead { + background-color: #f9fafb; + border-bottom: 2px solid var(--border-color, #e5e7eb); } -.back-button:hover { - background: var(--primary-50); - border-color: var(--primary-300); - transform: translateY(-1px); - box-shadow: var(--shadow-md); +.tbm-work-table th { + padding: 0.75rem 0.5rem; + text-align: left; + font-weight: 600; + color: var(--text-secondary, #6b7280); + border-bottom: 2px solid var(--border-color, #e5e7eb); + white-space: nowrap; + font-size: 0.8rem; } -/* 진행 단계 표시 */ -.progress-steps { - display: flex; - justify-content: center; - align-items: center; - margin-bottom: var(--space-8); - padding: var(--space-6); - background: var(--bg-primary); - border-radius: var(--radius-xl); - box-shadow: var(--shadow-sm); +.tbm-work-table td { + padding: 0.75rem 0.5rem; + border-bottom: 1px solid var(--border-light, #f3f4f6); + vertical-align: middle; } -.progress-step { - display: flex; - flex-direction: column; - align-items: center; - gap: var(--space-2); - position: relative; - flex: 1; - max-width: 200px; +.tbm-work-table tbody tr:hover { + background-color: #f9fafb; } -.progress-step:not(:last-child)::after { - content: ''; - position: absolute; - top: 20px; - right: -50%; - width: 100%; - height: 2px; - background: var(--border-light); - z-index: 1; +.tbm-work-table tbody tr:last-child td { + border-bottom: none; } -.progress-step.active:not(:last-child)::after, -.progress-step.completed:not(:last-child)::after { - background: var(--primary-500); +.worker-cell { + min-width: 100px; } -.step-circle { - width: 40px; - height: 40px; - border-radius: var(--radius-full); - display: flex; - align-items: center; - justify-content: center; - font-weight: var(--font-bold); - font-size: var(--text-sm); - background: var(--gray-200); - color: var(--gray-600); - transition: var(--transition-normal); - z-index: 2; - position: relative; +.worker-cell strong { + display: block; + color: var(--text-primary, #111827); + margin-bottom: 0.25rem; } -.progress-step.active .step-circle { - background: var(--primary-500); - color: white; - box-shadow: 0 0 0 4px var(--primary-100); +.worker-job-type { + font-size: 0.75rem; + color: var(--text-secondary, #6b7280); + background-color: #f3f4f6; + padding: 0.125rem 0.5rem; + border-radius: 4px; + display: inline-block; } -.progress-step.completed .step-circle { - background: var(--success-500); - color: white; +.workplace-cell div { + font-size: 0.8rem; } -.step-label { - font-size: var(--text-sm); - font-weight: var(--font-medium); - color: var(--text-secondary); +.workplace-cell div:first-child { + color: var(--text-secondary, #6b7280); + font-size: 0.75rem; +} + +.form-input-compact { + width: 70px; + padding: 0.375rem 0.5rem; + border: 1px solid var(--border-color, #d1d5db); + border-radius: 4px; + font-size: 0.875rem; text-align: center; } -.progress-step.active .step-label { - color: var(--primary-600); - font-weight: var(--font-semibold); +.form-input-compact:focus { + outline: none; + border-color: var(--primary, #3b82f6); + box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1); } -.progress-step.completed .step-label { - color: var(--success-600); +.form-input-compact[type="number"] { + -moz-appearance: textfield; } -/* 단계별 섹션 */ -.step-section { - background: var(--bg-primary); - border-radius: var(--radius-xl); - padding: var(--space-8); - margin-bottom: var(--space-6); - box-shadow: var(--shadow-md); - border: 1px solid var(--border-light); - opacity: 0.5; - transform: translateY(20px); - transition: all 0.4s ease; +.form-input-compact[type="number"]::-webkit-outer-spin-button, +.form-input-compact[type="number"]::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; } -.step-section.active { - opacity: 1; - transform: translateY(0); - border-color: var(--primary-200); - box-shadow: var(--shadow-lg); -} - -.step-section.completed { - opacity: 0.8; - border-color: var(--success-200); -} - -.step-header { - display: flex; - align-items: center; - gap: var(--space-4); - margin-bottom: var(--space-6); - padding-bottom: var(--space-4); - border-bottom: 2px solid var(--border-light); -} - -.step-number { - width: 48px; - height: 48px; - border-radius: var(--radius-full); - background: var(--primary-500); +.btn-submit-compact { + padding: 0.5rem 1rem; + background-color: var(--primary, #3b82f6); color: white; + border: none; + border-radius: 4px; + font-size: 0.875rem; + font-weight: 500; + cursor: pointer; + transition: background-color 0.2s; + white-space: nowrap; +} + +.btn-submit-compact:hover { + background-color: var(--primary-dark, #2563eb); +} + +.btn-submit-compact:active { + transform: scale(0.98); +} + +.btn-add-work { + padding: 0.625rem 1.25rem; + background-color: #10b981; + color: white; + border: none; + border-radius: 6px; + font-size: 0.875rem; + font-weight: 500; + cursor: pointer; + transition: background-color 0.2s; +} + +.btn-add-work:hover { + background-color: #059669; +} + +.btn-delete-compact { + padding: 0.375rem 0.625rem; + background-color: #ef4444; + color: white; + border: none; + border-radius: 4px; + font-size: 0.875rem; + cursor: pointer; + transition: background-color 0.2s; +} + +.btn-delete-compact:hover { + background-color: #dc2626; +} + +.btn-map-select { + padding: 0.5rem 0.875rem; + background-color: #8b5cf6; + color: white; + border: none; + border-radius: 4px; + font-size: 0.8rem; + font-weight: 500; + cursor: pointer; + transition: background-color 0.2s; + white-space: nowrap; +} + +.btn-map-select:hover { + background-color: #7c3aed; +} + +/* 작업장소 선택 박스 hover 효과 */ +.workplace-select-box { + transition: all 0.2s ease; +} + +.workplace-select-box:hover { + background-color: #f3f4f6 !important; + border-color: #8b5cf6 !important; + transform: translateY(-1px); + box-shadow: 0 2px 4px rgba(139, 92, 246, 0.1); +} + +.workplace-category-btn, +.workplace-btn { + padding: 0.75rem 1rem; + background-color: #f3f4f6; + border: 2px solid #e5e7eb; + border-radius: 6px; + cursor: pointer; + transition: all 0.2s; + font-size: 0.875rem; + font-weight: 500; + text-align: center; +} + +.workplace-category-btn:hover, +.workplace-btn:hover { + background-color: #e0e7ff; + border-color: #818cf8; + color: #4338ca; +} + +.workplace-category-btn:active, +.workplace-btn:active { + transform: scale(0.98); +} + +/* 작업장소 선택 모달 */ +#workplaceModal.modal { + display: none; + position: fixed; + z-index: 1000; + left: 0; + top: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + align-items: center; + justify-content: center; +} + +#workplaceModal .modal-content { + background-color: white; + margin: auto; + padding: 0; + border-radius: 8px; + max-width: 600px; + width: 90%; + max-height: 80vh; + overflow: hidden; + display: flex; + flex-direction: column; +} + +#workplaceModal .modal-header { + padding: 1.5rem; + border-bottom: 1px solid #e5e7eb; + display: flex; + justify-content: space-between; + align-items: center; +} + +#workplaceModal .modal-header h3 { + margin: 0; + font-size: 1.25rem; + color: #111827; +} + +#workplaceModal .modal-close { + background: none; + border: none; + font-size: 1.5rem; + cursor: pointer; + color: #6b7280; + padding: 0; + width: 2rem; + height: 2rem; display: flex; align-items: center; justify-content: center; - font-weight: var(--font-bold); - font-size: var(--text-lg); - box-shadow: var(--shadow-sm); + border-radius: 4px; } -.step-number.completed { - background: var(--success-500); +#workplaceModal .modal-close:hover { + background-color: #f3f4f6; + color: #111827; } -.step-title { - font-size: var(--text-2xl); - font-weight: var(--font-bold); - color: var(--text-primary); +#workplaceModal .modal-body { + padding: 1.5rem; + overflow-y: auto; +} + +.tab-btn { + padding: 0.75rem 1.5rem; + background: none; + border: none; + border-bottom: 3px solid transparent; + cursor: pointer; + font-weight: 500; + color: var(--text-secondary, #6b7280); + transition: all 0.2s; +} + +.tab-btn:hover { + color: var(--primary, #3b82f6); +} + +.tab-btn.active { + color: var(--primary, #3b82f6); + border-bottom-color: var(--primary, #3b82f6); +} + +/* TBM 작업 카드 스타일 */ +.tbm-work-card { + background: white; + border: 1px solid var(--border-color, #e5e7eb); + border-radius: 8px; + padding: 1.5rem; + margin-bottom: 1.5rem; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} + +.tbm-work-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; + padding-bottom: 1rem; + border-bottom: 2px solid var(--border-color, #e5e7eb); +} + +.tbm-work-header h4 { + margin: 0; + font-size: 1.125rem; + color: var(--text-primary, #111827); +} + +.tbm-work-date { + font-size: 0.875rem; + color: var(--text-secondary, #6b7280); + background: var(--bg-secondary, #f3f4f6); + padding: 0.25rem 0.75rem; + border-radius: 4px; +} + +.tbm-work-info { + margin-bottom: 1.5rem; +} + +.info-row { + display: flex; + padding: 0.5rem 0; + border-bottom: 1px solid var(--border-light, #f3f4f6); +} + +.info-row:last-child { + border-bottom: none; +} + +.info-row .label { + font-weight: 600; + color: var(--text-secondary, #6b7280); + min-width: 100px; + font-size: 0.875rem; +} + +.info-row .value { + color: var(--text-primary, #111827); + flex: 1; +} + +.tbm-work-input { + background: var(--bg-secondary, #f9fafb); + padding: 1.5rem; + border-radius: 6px; + margin-bottom: 1rem; +} + +.tbm-work-input .form-group { + margin-bottom: 1rem; +} + +.tbm-work-input .form-group:last-child { + margin-bottom: 0; +} + +.tbm-work-input label { + display: block; + font-weight: 500; + font-size: 0.875rem; + color: var(--text-secondary, #6b7280); + margin-bottom: 0.5rem; +} + +.tbm-work-input .form-input { + width: 100%; + padding: 0.625rem; + border: 1px solid var(--border-color, #d1d5db); + border-radius: 4px; + font-size: 1rem; +} + +.tbm-work-input .form-input:focus { + outline: none; + border-color: var(--primary, #3b82f6); + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); +} + +.tbm-work-input .form-input[readonly] { + background-color: #f3f4f6; + cursor: not-allowed; +} + +/* 버튼 스타일 */ +.btn-block { + width: 100%; + padding: 0.875rem; + font-size: 1rem; + font-weight: 500; +} + +.btn-primary { + background-color: var(--primary, #3b82f6); + color: white; + border: none; + border-radius: 6px; + cursor: pointer; + transition: background-color 0.2s; +} + +.btn-primary:hover { + background-color: var(--primary-dark, #2563eb); +} + +.btn-primary:disabled { + background-color: #9ca3af; + cursor: not-allowed; +} + +/* 메시지 스타일 */ +.message { + padding: 1rem; + border-radius: 6px; + margin-bottom: 1rem; + font-size: 0.875rem; +} + +.message.error { + background-color: #fee2e2; + color: #991b1b; + border-left: 4px solid #dc2626; +} + +.message.success { + background-color: #dcfce7; + color: #166534; + border-left: 4px solid #16a34a; +} + +.message.info { + background-color: #dbeafe; + color: #1e40af; + border-left: 4px solid #3b82f6; +} + +/* 완료된 보고서 카드 스타일 */ +.completed-report-card { + background: white; + border: 1px solid var(--border-color, #e5e7eb); + border-radius: 8px; + padding: 1.5rem; + margin-bottom: 1.5rem; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} + +.completed-report-card .report-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; + padding-bottom: 1rem; + border-bottom: 2px solid var(--border-color, #e5e7eb); +} + +.completed-report-card .report-header h4 { + margin: 0 0.5rem 0 0; + font-size: 1.125rem; + color: var(--text-primary, #111827); + display: inline-block; +} + +.completed-report-card .report-date { + font-size: 0.875rem; + color: var(--text-secondary, #6b7280); + background: var(--bg-secondary, #f3f4f6); + padding: 0.25rem 0.75rem; + border-radius: 4px; +} + +.completed-report-card .report-info { + margin-top: 1rem; +} + +.tbm-badge { + display: inline-block; + background-color: #dbeafe; + color: #1e40af; + padding: 0.25rem 0.75rem; + border-radius: 12px; + font-size: 0.75rem; + font-weight: 600; + margin-left: 0.5rem; +} + +.manual-badge { + display: inline-block; + background-color: #f3f4f6; + color: #6b7280; + padding: 0.25rem 0.75rem; + border-radius: 12px; + font-size: 0.75rem; + font-weight: 600; + margin-left: 0.5rem; } -/* 폼 요소들 */ .form-group { - margin-bottom: var(--space-6); + margin-bottom: 1rem; } .form-label { display: block; - margin-bottom: var(--space-3); - font-weight: var(--font-semibold); - color: var(--text-primary); - font-size: var(--text-base); + font-weight: 500; + font-size: 0.875rem; + color: var(--text-secondary, #6b7280); + margin-bottom: 0.5rem; } .form-input { width: 100%; - padding: var(--space-4); - border: 2px solid var(--border-light); - border-radius: var(--radius-lg); - font-size: var(--text-base); - background: var(--bg-primary); - transition: var(--transition-normal); - box-shadow: var(--shadow-sm); + padding: 0.625rem; + border: 1px solid var(--border-color, #d1d5db); + border-radius: 4px; + font-size: 1rem; } .form-input:focus { outline: none; - border-color: var(--primary-500); - box-shadow: 0 0 0 3px var(--primary-100); + border-color: var(--primary, #3b82f6); + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); } -/* 작업자 선택 그리드 */ -.worker-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); - gap: var(--space-4); - margin-bottom: var(--space-6); -} - -.worker-card { - padding: var(--space-5); - border: 2px solid var(--border-light); - border-radius: var(--radius-xl); - background: var(--bg-primary); +/* 시간 입력 트리거 (클릭 가능한 영역) */ +.time-input-trigger { + padding: 0.5rem 0.75rem; + background: #f9fafb; + border: 2px solid #e5e7eb; + border-radius: 6px; cursor: pointer; - transition: all 0.3s ease; text-align: center; - font-weight: var(--font-semibold); - font-size: var(--text-lg); - min-height: 100px; - display: flex; - align-items: center; - justify-content: center; - box-shadow: var(--shadow-sm); - position: relative; - overflow: hidden; -} - -.worker-card::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 3px; - background: var(--primary-500); - transform: scaleX(0); - transition: transform 0.3s ease; -} - -.worker-card:hover { - border-color: var(--primary-300); - background: var(--primary-50); - transform: translateY(-2px); - box-shadow: var(--shadow-lg); -} - -.worker-card:hover::before { - transform: scaleX(1); -} - -.worker-card.selected { - border-color: var(--primary-500); - background: linear-gradient(135deg, var(--primary-500), var(--primary-600)); - color: white; - box-shadow: 0 8px 25px rgba(59, 130, 246, 0.3); -} - -.worker-card.selected::before { - transform: scaleX(1); - background: rgba(255, 255, 255, 0.3); -} - -/* 작업 항목 */ -.work-entry { - background: linear-gradient(135deg, var(--bg-primary) 0%, var(--bg-tertiary) 100%); - border: 2px solid var(--border-light); - border-radius: var(--radius-2xl); - padding: var(--space-8); - margin-bottom: var(--space-6); - position: relative; - transition: var(--transition-normal); - box-shadow: var(--shadow-md); - overflow: hidden; -} - -.work-entry::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 4px; - background: linear-gradient(90deg, var(--primary-500), var(--secondary-500)); - opacity: 0; - transition: opacity 0.3s ease; -} - -.work-entry:hover { - border-color: var(--primary-300); - box-shadow: var(--shadow-lg); - transform: translateY(-2px); -} - -.work-entry:hover::before { - opacity: 1; -} - -.work-entry-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: var(--space-6); - padding-bottom: var(--space-4); - border-bottom: 2px solid var(--border-light); -} - -.work-entry-title { - font-size: var(--text-xl); - font-weight: var(--font-bold); - color: var(--text-primary); - display: flex; - align-items: center; - gap: var(--space-2); -} - -.work-entry-title::before { - content: '🔧'; - font-size: var(--text-lg); -} - -.remove-work-btn { - padding: 8px 16px; - border-radius: 8px; - background: linear-gradient(135deg, #ef4444, #dc2626); - color: white; - border: none; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - gap: 6px; - font-size: 14px; font-weight: 600; - box-shadow: 0 2px 8px rgba(239, 68, 68, 0.4); + color: #374151; + min-height: 44px; + display: flex; + align-items: center; + justify-content: center; transition: all 0.2s ease; + user-select: none; } -.remove-work-btn:hover { - background: linear-gradient(135deg, #dc2626, #b91c1c); - transform: scale(1.15); - box-shadow: 0 4px 12px rgba(239, 68, 68, 0.5); +.time-input-trigger:hover { + background: #f3f4f6; + border-color: #3b82f6; + color: #3b82f6; } -.remove-work-btn:active { - transform: scale(0.95); +.time-input-trigger.has-value { + background: #eff6ff; + border-color: #3b82f6; + color: #1e40af; } -.work-entry-grid { - display: grid; - grid-template-columns: 1fr 1fr; - gap: var(--space-6); +.time-input-trigger.placeholder { + color: #9ca3af; + font-style: italic; + font-weight: 400; } -.work-entry-full { - grid-column: span 2; -} - -/* 폼 필드 그룹 */ -.form-field-group { - background: var(--bg-primary); - border-radius: var(--radius-lg); - padding: var(--space-5); - border: 1px solid var(--border-light); - transition: var(--transition-normal); -} - -.form-field-group:hover { - border-color: var(--primary-200); - box-shadow: var(--shadow-sm); -} - -.form-field-group.focused { - border-color: var(--primary-500); - box-shadow: 0 0 0 3px var(--primary-100); -} - -.form-field-label { - display: flex; - align-items: center; - gap: var(--space-2); - margin-bottom: var(--space-3); - font-weight: var(--font-semibold); - color: var(--text-primary); - font-size: var(--text-base); -} - -.form-field-icon { - font-size: var(--text-lg); -} - -.form-select { - width: 100%; - padding: var(--space-4); - border: 2px solid var(--border-light); - border-radius: var(--radius-lg); - font-size: var(--text-base); - background: var(--bg-primary); - transition: var(--transition-normal); - cursor: pointer; -} - -.form-select:focus { - outline: none; - border-color: var(--primary-500); - box-shadow: 0 0 0 3px var(--primary-100); -} - -.form-select:hover { - border-color: var(--primary-300); -} - -/* 에러 유형 섹션 */ -.error-type-section { - background: linear-gradient(135deg, var(--error-50) 0%, var(--warning-50) 100%); - border: 2px solid var(--error-200); - border-radius: var(--radius-xl); - padding: var(--space-6); - margin-top: var(--space-4); - opacity: 0; - max-height: 0; - overflow: hidden; - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); - transform: translateY(-10px); -} - -.error-type-section.visible { - opacity: 1; - max-height: 200px; - transform: translateY(0); -} - -.error-type-section .form-field-label { - color: var(--error-700); -} - -.error-type-section .form-field-icon { - color: var(--error-500); -} - -/* 시간 입력 */ -.time-input-section { - background: linear-gradient(135deg, var(--primary-50) 0%, var(--secondary-50) 100%); - border: 2px solid var(--primary-200); - border-radius: var(--radius-xl); - padding: var(--space-6); - margin-top: var(--space-4); -} - -.quick-time-buttons { - display: flex; - gap: var(--space-2); - margin-top: var(--space-3); - flex-wrap: wrap; - justify-content: center; -} - -.quick-time-btn { - padding: var(--space-3) var(--space-4); - background: linear-gradient(135deg, var(--primary-100), var(--primary-200)); - border: 2px solid var(--primary-300); - border-radius: var(--radius-xl); - cursor: pointer; - font-size: var(--text-sm); - font-weight: var(--font-semibold); - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - color: var(--primary-700); - min-width: 60px; - text-align: center; - box-shadow: var(--shadow-sm); - position: relative; - overflow: hidden; -} - -.quick-time-btn::before { - content: ''; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent); - transition: left 0.5s ease; -} - -.quick-time-btn:hover { - background: linear-gradient(135deg, var(--primary-500), var(--primary-600)); - color: white; - transform: translateY(-2px) scale(1.05); - box-shadow: var(--shadow-lg); - border-color: var(--primary-400); -} - -.quick-time-btn:hover::before { - left: 100%; -} - -.quick-time-btn:active { - transform: translateY(0) scale(0.98); -} - -/* 총 작업시간 표시 */ -.total-hours-display { - text-align: center; - font-size: var(--text-2xl); - font-weight: var(--font-bold); - padding: var(--space-6); - background: linear-gradient(135deg, var(--primary-500), var(--primary-600)); - color: white; - border-radius: var(--radius-xl); - margin-bottom: var(--space-6); - box-shadow: 0 8px 25px rgba(59, 130, 246, 0.3); -} - -/* 버튼 스타일 */ -.btn { - padding: var(--space-4) var(--space-6); - border: none; - border-radius: var(--radius-lg); - font-size: var(--text-base); - font-weight: var(--font-semibold); - cursor: pointer; - transition: var(--transition-normal); - display: inline-flex; - align-items: center; - justify-content: center; - gap: var(--space-2); - text-decoration: none; - min-height: 48px; - box-shadow: var(--shadow-sm); -} - -.btn:disabled { - opacity: 0.5; - cursor: not-allowed; - transform: none !important; - box-shadow: none !important; -} - -.btn-primary { - background: var(--primary-500); - color: white; -} - -.btn-primary:hover:not(:disabled) { - background: var(--primary-600); - transform: translateY(-2px); - box-shadow: var(--shadow-lg); -} - -.btn-success { - background: var(--success-500); - color: white; -} - -.btn-success:hover:not(:disabled) { - background: var(--success-600); - transform: translateY(-2px); - box-shadow: var(--shadow-lg); -} - -.btn-secondary { - background: var(--gray-500); - color: white; -} - -.btn-secondary:hover:not(:disabled) { - background: var(--gray-600); - transform: translateY(-2px); - box-shadow: var(--shadow-lg); -} - -.btn-block { - width: 100%; -} - -/* 메시지 */ -.message { - padding: var(--space-4) var(--space-5); - border-radius: var(--radius-lg); - margin-bottom: var(--space-6); - font-weight: var(--font-medium); - border: 1px solid; -} - -.message.error { - background: var(--error-50); - color: var(--error-700); - border-color: var(--error-200); -} - -.message.success { - background: var(--success-50); - color: var(--success-700); - border-color: var(--success-200); -} - -.message.loading { - background: var(--primary-50); - color: var(--primary-700); - border-color: var(--primary-200); -} - -.message.warning { - background: var(--warning-50); - color: var(--warning-700); - border-color: var(--warning-200); -} - -/* 반응형 디자인 */ -@media (max-width: 1024px) { - .work-report-main { - padding: var(--space-6) var(--space-4); - } - - .progress-steps { - padding: var(--space-4); - } - - .progress-step:not(:last-child)::after { - right: -40%; - } -} - -@media (max-width: 768px) { - .work-report-header { - padding: var(--space-6) var(--space-4); - } - - .work-report-header h1 { - font-size: var(--text-3xl); - } - - .work-report-main { - padding: var(--space-4) var(--space-3); - } - - .step-section { - padding: var(--space-6); - } - - .worker-grid { - grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); - gap: var(--space-3); - } - - .worker-card { - min-height: 80px; - padding: var(--space-3); - font-size: var(--text-base); - } - - .work-entry-grid { - grid-template-columns: 1fr; - } - - .work-entry-full { - grid-column: span 1; - } - - .progress-steps { - flex-direction: column; - gap: var(--space-4); - } - - .progress-step:not(:last-child)::after { - display: none; - } - - .quick-time-buttons { - gap: var(--space-1); - } - - .quick-time-btn { - padding: var(--space-1) var(--space-3); - font-size: var(--text-xs); - } -} - -/* 슬라이드 다운 애니메이션 */ -@keyframes slideDown { - from { - opacity: 0; - max-height: 0; - transform: translateY(-10px); - } - to { - opacity: 1; - max-height: 200px; - transform: translateY(0); - } -} - -@media (max-width: 480px) { - .work-report-header h1 { - font-size: var(--text-2xl); - } - - .step-section { - padding: var(--space-4); - } - - .step-header { - flex-direction: column; - text-align: center; - gap: var(--space-2); - } - - .step-number { - width: 40px; - height: 40px; - font-size: var(--text-base); - } - - .step-title { - font-size: var(--text-xl); - } - - .worker-grid { - grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); - } - - .total-hours-display { - font-size: var(--text-xl); - padding: var(--space-4); - } -} - -/* 가이드 그리드 */ -.guide-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: var(--space-4); - margin-top: var(--space-4); -} - -.guide-item { - text-align: center; - padding: var(--space-5); - background: var(--bg-tertiary); - border-radius: var(--radius-xl); - border: 2px solid var(--border-light); - transition: var(--transition-normal); -} - -.guide-item:hover { - transform: translateY(-2px); - box-shadow: var(--shadow-lg); - border-color: var(--primary-300); - background: var(--primary-50); -} - -.guide-icon { - font-size: var(--text-3xl); - margin-bottom: var(--space-3); - display: block; -} - -.guide-item strong { - display: block; - font-size: var(--text-base); - font-weight: var(--font-bold); - margin-bottom: var(--space-2); - color: var(--text-primary); -} - -@media (max-width: 768px) { - .guide-grid { - grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); - gap: var(--space-3); - } - - .guide-item { - padding: var(--space-4); - } - - .guide-icon { - font-size: var(--text-2xl); - } -} - -@media (max-width: 480px) { - .guide-grid { - grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); - } - - .guide-item { - padding: var(--space-3); - } - - .guide-item strong { - font-size: var(--text-sm); - } -} - -/* ========== 개별 작업 보고서 전용 스타일 ========== */ - -/* 작업자 정보 카드 */ -.worker-info-card { - background: linear-gradient(135deg, var(--primary-50) 0%, var(--secondary-50) 100%); - border: 2px solid var(--primary-200); - border-radius: var(--radius-2xl); - padding: var(--space-8); - margin-bottom: var(--space-8); - display: flex; - align-items: center; - gap: var(--space-6); - box-shadow: var(--shadow-lg); - position: relative; - overflow: hidden; -} - -.worker-info-card::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 4px; - background: linear-gradient(90deg, var(--primary-500), var(--secondary-500)); -} - -.worker-avatar-large { - width: 80px; - height: 80px; - border-radius: var(--radius-full); - background: linear-gradient(135deg, var(--primary-500), var(--secondary-500)); - display: flex; - align-items: center; - justify-content: center; - color: var(--text-inverse); - font-weight: var(--font-bold); - font-size: var(--text-3xl); - box-shadow: var(--shadow-lg); - flex-shrink: 0; -} - -.worker-info-details { - flex: 1; -} - -.worker-info-details h2 { - font-size: var(--text-2xl); - font-weight: var(--font-bold); - color: var(--text-primary); - margin: 0 0 var(--space-2) 0; -} - -.worker-info-details p { - font-size: var(--text-base); - color: var(--text-secondary); - margin: 0 0 var(--space-1) 0; -} - -.worker-status-summary { - display: flex; - gap: var(--space-6); -} - -.status-item { - text-align: center; - padding: var(--space-4); - background: var(--bg-primary); - border-radius: var(--radius-xl); - border: 1px solid var(--border-light); - min-width: 100px; -} - -.status-label { - display: block; - font-size: var(--text-sm); - color: var(--text-secondary); - margin-bottom: var(--space-1); -} - -.status-value { - display: block; - font-size: var(--text-xl); - font-weight: var(--font-bold); - color: var(--text-primary); -} - -.status-value.warning { - color: var(--error-600); -} - -/* 섹션 헤더 */ -.section-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: var(--space-6); - padding-bottom: var(--space-4); - border-bottom: 2px solid var(--border-light); -} - -.section-header h3 { - font-size: var(--text-xl); - font-weight: var(--font-bold); - color: var(--text-primary); - margin: 0; -} - -/* 기존 작업 목록 */ -.existing-work-section { - margin-bottom: var(--space-8); -} - -.existing-work-item { - background: linear-gradient(135deg, var(--bg-primary) 0%, var(--bg-tertiary) 100%); - border: 2px solid var(--border-light); - border-radius: var(--radius-xl); - padding: var(--space-6); - margin-bottom: var(--space-4); - transition: var(--transition-normal); - box-shadow: var(--shadow-md); - position: relative; - overflow: hidden; -} - -.existing-work-item::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 3px; - background: var(--success-500); - opacity: 0; - transition: opacity 0.3s ease; -} - -.existing-work-item:hover { - border-color: var(--primary-300); - box-shadow: var(--shadow-lg); - transform: translateY(-2px); -} - -.existing-work-item:hover::before { - opacity: 1; -} - -.work-item-header { - display: flex; - justify-content: space-between; - align-items: flex-start; - margin-bottom: var(--space-4); -} - -.work-item-info h4 { - font-size: var(--text-lg); - font-weight: var(--font-semibold); - color: var(--text-primary); - margin: 0 0 var(--space-1) 0; -} - -.work-item-info p { - font-size: var(--text-sm); - color: var(--text-secondary); - margin: 0; -} - -.work-item-status { - display: flex; - flex-direction: column; - align-items: flex-end; - gap: var(--space-2); -} - -.status-badge { - padding: var(--space-1) var(--space-3); - border-radius: var(--radius-full); - font-size: var(--text-xs); - font-weight: var(--font-medium); -} - -.status-badge.normal { - background: var(--success-100); - color: var(--success-700); - border: 1px solid var(--success-300); -} - -.status-badge.error { - background: var(--error-100); - color: var(--error-700); - border: 1px solid var(--error-300); -} - -.work-hours { - font-size: var(--text-lg); - font-weight: var(--font-bold); - color: var(--primary-600); -} - -.work-item-error { - background: var(--error-50); - border: 1px solid var(--error-200); - border-radius: var(--radius-lg); - padding: var(--space-3); - margin-bottom: var(--space-4); -} - -.error-label { - font-size: var(--text-sm); - font-weight: var(--font-medium); - color: var(--error-600); -} - -.error-type { - font-size: var(--text-sm); - color: var(--error-700); - margin-left: var(--space-2); -} - -.work-item-actions { - display: flex; - gap: var(--space-2); - justify-content: flex-end; -} - -/* 새 작업 추가 섹션 */ -.new-work-section { - margin-bottom: var(--space-8); -} - -/* 휴가 처리 섹션 */ -.vacation-section { - margin-bottom: var(--space-8); -} - -.vacation-buttons { - display: flex; - gap: var(--space-4); - flex-wrap: wrap; -} - -.vacation-process-btn { - flex: 1; - min-width: 150px; - padding: var(--space-4) var(--space-6); - font-size: var(--text-base); - font-weight: var(--font-medium); - background: linear-gradient(135deg, var(--warning-500), var(--warning-600)); - border: none; - color: var(--text-inverse); - border-radius: var(--radius-xl); - transition: var(--transition-normal); - box-shadow: var(--shadow-md); -} - -.vacation-process-btn:hover { - background: linear-gradient(135deg, var(--warning-600), var(--warning-700)); - transform: translateY(-2px); - box-shadow: var(--shadow-lg); -} - -/* 빈 상태 */ -.empty-state { - text-align: center; - padding: var(--space-12); - background: var(--bg-secondary); - border-radius: var(--radius-xl); - border: 2px dashed var(--border-light); -} - -.empty-icon { - font-size: var(--text-6xl); - margin-bottom: var(--space-4); -} - -.empty-state h3 { - font-size: var(--text-xl); - font-weight: var(--font-semibold); - color: var(--text-primary); - margin: 0 0 var(--space-2) 0; -} - -.empty-state p { - font-size: var(--text-base); - color: var(--text-secondary); - margin: 0; -} - -/* 개별 보고서 반응형 디자인 */ -@media (max-width: 768px) { - .worker-info-card { - flex-direction: column; - text-align: center; - gap: var(--space-4); - } - - .worker-status-summary { - justify-content: center; - gap: var(--space-4); - } - - .section-header { - flex-direction: column; - align-items: stretch; - gap: var(--space-3); - } - - .work-item-header { - flex-direction: column; - gap: var(--space-3); - } - - .work-item-status { - align-items: flex-start; - flex-direction: row; - justify-content: space-between; - } - - .vacation-buttons { - flex-direction: column; - } - - .vacation-process-btn { - min-width: auto; - } -} - -@media (max-width: 480px) { - .worker-status-summary { - flex-direction: column; - gap: var(--space-3); - } - - .status-item { - min-width: auto; - } - - .work-item-actions { - flex-direction: column; - } -} - -/* ======================================== - 저장 결과 모달 스타일 - ======================================== */ - -.modal-overlay { +/* 시간 선택 팝오버 */ +.time-picker-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; - background: rgba(0, 0, 0, 0.6); - backdrop-filter: blur(8px); - z-index: 10000; + background-color: rgba(0, 0, 0, 0.5); + z-index: 2000; display: flex; align-items: center; justify-content: center; - animation: fadeIn 0.3s ease-out; + padding: 1rem; } -@keyframes fadeIn { +.time-picker-popup { + background: white; + border-radius: 16px; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); + padding: 1.5rem; + max-width: 400px; + width: 100%; + animation: popupSlideIn 0.3s ease-out; +} + +@keyframes popupSlideIn { from { opacity: 0; - } - to { - opacity: 1; - } -} - -.result-modal { - background: var(--bg-primary); - border-radius: var(--radius-2xl); - box-shadow: var(--shadow-2xl); - width: 90%; - max-width: 500px; - max-height: 80vh; - overflow: hidden; - animation: slideUp 0.3s ease-out; - border: 2px solid var(--border-light); -} - -@keyframes slideUp { - from { - opacity: 0; - transform: translateY(30px) scale(0.95); + transform: translateY(20px) scale(0.95); } to { opacity: 1; @@ -1217,165 +654,158 @@ } } -.modal-header { - background: linear-gradient(135deg, var(--primary-500), var(--primary-600)); - color: var(--text-inverse); - padding: var(--space-6); +.time-picker-header { display: flex; justify-content: space-between; align-items: center; - border-bottom: 2px solid var(--primary-700); + margin-bottom: 1.25rem; } -.modal-header h2 { +.time-picker-header h3 { margin: 0; - font-size: var(--text-xl); - font-weight: var(--font-bold); + font-size: 1.125rem; + font-weight: 700; + color: #111827; } -.modal-close-btn { +.time-picker-close { background: none; border: none; - color: var(--text-inverse); - font-size: var(--text-2xl); + font-size: 1.75rem; + color: #6b7280; cursor: pointer; - padding: var(--space-2); - border-radius: var(--radius-full); - transition: var(--transition-fast); - width: 40px; - height: 40px; + padding: 0; + width: 2rem; + height: 2rem; display: flex; align-items: center; justify-content: center; + border-radius: 4px; + transition: all 0.2s; } -.modal-close-btn:hover { - background: rgba(255, 255, 255, 0.2); - transform: scale(1.1); +.time-picker-close:hover { + background: #f3f4f6; + color: #111827; } -.modal-body { - padding: var(--space-8); - max-height: 60vh; - overflow-y: auto; +/* 퀵 선택 버튼 그리드 */ +.quick-time-grid { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 0.5rem; + margin-bottom: 1.25rem; } -.result-content { - text-align: center; -} - -.result-icon { - font-size: 4rem; - margin-bottom: var(--space-6); - display: block; -} - -.result-icon.success { - color: var(--success-500); -} - -.result-icon.error { - color: var(--error-500); -} - -.result-icon.warning { - color: var(--warning-500); -} - -.result-title { - font-size: var(--text-2xl); - font-weight: var(--font-bold); - margin-bottom: var(--space-4); - color: var(--text-primary); -} - -.result-title.success { - color: var(--success-600); -} - -.result-title.error { - color: var(--error-600); -} - -.result-title.warning { - color: var(--warning-600); -} - -.result-message { - font-size: var(--text-lg); - color: var(--text-secondary); - margin-bottom: var(--space-6); - line-height: 1.6; -} - -.result-details { - background: var(--bg-secondary); - border-radius: var(--radius-lg); - padding: var(--space-4); - margin-top: var(--space-4); - text-align: left; -} - -.result-details h4 { - font-size: var(--text-base); - font-weight: var(--font-semibold); - color: var(--text-primary); - margin: 0 0 var(--space-2) 0; -} - -.result-details ul { - margin: 0; - padding-left: var(--space-4); - color: var(--text-secondary); -} - -.result-details li { - margin-bottom: var(--space-1); - font-size: var(--text-sm); -} - -.modal-footer { - background: var(--bg-secondary); - padding: var(--space-6); - border-top: 1px solid var(--border-light); +.time-btn { + padding: 1rem 0.5rem; + background: #3b82f6; + color: white; + border: none; + border-radius: 10px; + cursor: pointer; + font-weight: 700; + font-size: 0.875rem; + min-height: 64px; display: flex; + flex-direction: column; + align-items: center; justify-content: center; + transition: all 0.2s ease; + box-shadow: 0 2px 4px rgba(59, 130, 246, 0.2); } -.modal-footer .btn { - min-width: 120px; - padding: var(--space-3) var(--space-6); - font-weight: var(--font-semibold); +.time-btn:hover { + background: #2563eb; + transform: translateY(-2px); + box-shadow: 0 4px 8px rgba(59, 130, 246, 0.3); } -/* 반응형 디자인 */ -@media (max-width: 480px) { - .result-modal { - width: 95%; - margin: var(--space-4); - } - - .modal-header { - padding: var(--space-4); - } - - .modal-body { - padding: var(--space-6); - } - - .modal-footer { - padding: var(--space-4); - } - - .result-icon { - font-size: 3rem; - } - - .result-title { - font-size: var(--text-xl); - } - - .result-message { - font-size: var(--text-base); - } -} \ No newline at end of file +.time-btn:active { + transform: translateY(0) scale(0.98); + box-shadow: 0 2px 4px rgba(59, 130, 246, 0.2); +} + +.time-btn .time-value { + font-size: 0.95rem; +} + +/* 미세 조정 영역 */ +.time-adjust-area { + background: #f9fafb; + border: 1px solid #e5e7eb; + border-radius: 10px; + padding: 1rem; + margin-bottom: 1rem; + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.current-time-label { + font-size: 0.875rem; + color: #6b7280; + font-weight: 500; +} + +.current-time-value { + font-size: 1.5rem; + color: #111827; + font-weight: 700; + display: block; + margin-bottom: 0.5rem; +} + +.adjust-buttons { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0.5rem; +} + +.adjust-btn { + padding: 0.875rem 1rem; + background: #6b7280; + color: white; + border: none; + border-radius: 8px; + font-weight: 700; + font-size: 0.875rem; + cursor: pointer; + min-height: 48px; + transition: all 0.2s ease; +} + +.adjust-btn:hover { + background: #4b5563; + transform: translateY(-1px); +} + +.adjust-btn:active { + transform: translateY(0) scale(0.98); +} + +/* 확인 버튼 */ +.confirm-btn { + width: 100%; + padding: 1rem; + background: #10b981; + color: white; + border: none; + border-radius: 10px; + font-weight: 700; + font-size: 1rem; + cursor: pointer; + min-height: 52px; + transition: all 0.2s ease; + box-shadow: 0 2px 4px rgba(16, 185, 129, 0.2); +} + +.confirm-btn:hover { + background: #059669; + transform: translateY(-2px); + box-shadow: 0 4px 8px rgba(16, 185, 129, 0.3); +} + +.confirm-btn:active { + transform: translateY(0) scale(0.98); +} diff --git a/web-ui/js/daily-work-report.js b/web-ui/js/daily-work-report.js index 14e9977..1acba6c 100644 --- a/web-ui/js/daily-work-report.js +++ b/web-ui/js/daily-work-report.js @@ -15,6 +15,980 @@ let selectedWorkers = new Set(); let workEntryCounter = 0; let currentStep = 1; let editingWorkId = null; // 수정 중인 작업 ID +let incompleteTbms = []; // 미완료 TBM 작업 목록 +let currentTab = 'tbm'; // 현재 활성 탭 + +// 작업장소 지도 관련 변수 +let mapCanvas = null; +let mapCtx = null; +let mapImage = null; +let mapRegions = []; +let selectedWorkplace = null; +let selectedWorkplaceName = null; +let selectedWorkplaceCategory = null; +let selectedWorkplaceCategoryName = null; + +// 시간 선택 관련 변수 +let currentEditingField = null; // { index, type: 'total' | 'error' } +let currentTimeValue = 0; + +// ================================================================= +// TBM 작업보고 관련 함수 +// ================================================================= + +/** + * 탭 전환 함수 + */ +window.switchTab = function(tab) { + currentTab = tab; + const tbmBtn = document.getElementById('tbmReportTab'); + const completedBtn = document.getElementById('completedReportTab'); + const tbmSection = document.getElementById('tbmReportSection'); + const completedSection = document.getElementById('completedReportSection'); + + // 모든 탭 버튼 비활성화 + tbmBtn.classList.remove('active'); + completedBtn.classList.remove('active'); + + // 모든 섹션 숨기기 + tbmSection.style.display = 'none'; + completedSection.style.display = 'none'; + + // 선택된 탭 활성화 + if (tab === 'tbm') { + tbmBtn.classList.add('active'); + tbmSection.style.display = 'block'; + loadIncompleteTbms(); // TBM 목록 로드 + } else if (tab === 'completed') { + completedBtn.classList.add('active'); + completedSection.style.display = 'block'; + + // 오늘 날짜로 초기화 + document.getElementById('completedReportDate').value = getKoreaToday(); + loadCompletedReports(); + } +}; + +/** + * 미완료 TBM 작업 로드 + */ +async function loadIncompleteTbms() { + try { + const response = await window.apiCall('/tbm/sessions/incomplete-reports'); + + if (!response.success) { + throw new Error(response.message || '미완료 TBM 조회 실패'); + } + + incompleteTbms = response.data || []; + renderTbmWorkList(); + } catch (error) { + console.error('미완료 TBM 로드 오류:', error); + showMessage('TBM 작업 목록을 불러오는 중 오류가 발생했습니다.', 'error'); + } +} + +/** + * TBM 작업 목록 렌더링 (세션별 그룹화) + */ +function renderTbmWorkList() { + const container = document.getElementById('tbmWorkList'); + + // TBM을 세션별로 그룹화 + const groupedTbms = {}; + if (incompleteTbms && incompleteTbms.length > 0) { + incompleteTbms.forEach((tbm, index) => { + const key = `${tbm.session_id}_${tbm.session_date}`; + if (!groupedTbms[key]) { + groupedTbms[key] = { + session_id: tbm.session_id, + session_date: tbm.session_date, + created_by_name: tbm.created_by_name, + items: [] + }; + } + groupedTbms[key].items.push({ ...tbm, originalIndex: index }); + }); + } + + let html = ` +
| 작업자 | +프로젝트 | +공정 | +작업 | +작업장소 | +작업시간 (시간) |
+ 부적합 (시간) |
+ 부적합 원인 | +제출 | +
|---|---|---|---|---|---|---|---|---|
|
+
+ ${tbm.worker_name || '작업자'}
+
+ ${tbm.job_type || '-'}
+ |
+ ${tbm.project_name || '-'} | +${tbm.work_type_name || '-'} | +${tbm.task_name || '-'} | +
+
+
+ ${tbm.category_name || ''}
+ ${tbm.workplace_name || '-'}
+ |
+
+
+
+ 시간 선택
+
+ |
+
+
+
+ 0시간
+
+ |
+ + + - + | ++ + | +
| 작업자 | +날짜 | +프로젝트 | +공정 | +작업 | +작업장소 | +작업시간 (시간) |
+ 부적합 (시간) |
+ 부적합 원인 | +제출 | +
|---|
작성된 작업보고서가 없습니다.
'; + return; + } + + const html = reports.map(report => ` +