refactor: TBM/작업보고 코드 통합 및 API 쿼리 버그 수정

- 공통 유틸리티 추출 (common/utils.js, common/base-state.js)
- TBM 모바일 인라인 JS/CSS 외부 파일로 분리 (tbm-mobile.js, tbm-mobile.css)
- 미사용 코드 삭제 (index.js, work-report-*.js 등 5개 파일)
- TBM/작업보고 state.js, utils.js를 공통 모듈 기반으로 전환
- 작업보고서 SSO 인증 호환 수정 (token/user 함수)
- tbmModel.js: incomplete-reports 쿼리에서 users→sso_users 조인 수정, leader_name 조인 추가
- docker-compose.yml: system1-web 볼륨 마운트 추가
- 모바일 인계(handover) 기능 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-03-05 07:51:24 +09:00
parent 22a37ac4d9
commit 4388628788
89 changed files with 5296 additions and 5046 deletions

View File

@@ -2016,3 +2016,374 @@
color: #6b7280;
font-size: 0.875rem;
}
/* ================================================
모바일 카드 레이아웃 + 터치 최적화
================================================ */
/* 전역 터치 최적화 - 더블탭 줌 방지 */
* {
touch-action: manipulation;
}
/* 로딩 상태 버튼 */
.btn-submit-compact.is-loading,
.btn-batch-submit.is-loading {
pointer-events: none;
opacity: 0.7;
position: relative;
}
.btn-submit-compact.is-loading::after,
.btn-batch-submit.is-loading::after {
content: '';
display: inline-block;
width: 14px;
height: 14px;
border: 2px solid rgba(255,255,255,0.3);
border-top-color: white;
border-radius: 50%;
animation: spin 0.6s linear infinite;
margin-left: 6px;
vertical-align: middle;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* ========== 모바일 768px 이하 ========== */
@media (max-width: 768px) {
/* --- 날짜 그룹 헤더 모바일 --- */
.date-group-header {
flex-wrap: wrap;
padding: 0.75rem 1rem;
gap: 0.25rem;
}
.date-header-left {
width: 100%;
}
.date-header-center {
gap: 0.5rem;
font-size: 0.8rem;
}
.date-header-right {
margin-left: auto;
}
/* --- TBM 세션 헤더 모바일 --- */
.tbm-session-header {
flex-wrap: wrap;
padding: 0.625rem 1rem;
gap: 0.375rem;
font-size: 0.8rem;
}
.tbm-session-count {
margin-left: 0;
}
/* --- 테이블 → 카드 전환 --- */
.tbm-table-container {
overflow-x: visible;
border: none;
border-radius: 0;
background: transparent;
}
.tbm-work-table {
display: block;
}
.tbm-work-table thead {
display: none;
}
.tbm-work-table tbody {
display: flex;
flex-direction: column;
gap: 0.75rem;
padding: 0.75rem;
}
.tbm-work-table tbody tr[data-type] {
display: flex;
flex-wrap: wrap;
background: white;
border: 1px solid #e5e7eb;
border-radius: 10px;
box-shadow: 0 1px 3px rgba(0,0,0,0.06);
padding: 0;
overflow: hidden;
}
.tbm-work-table tbody tr[data-type] td {
border-bottom: none;
padding: 0;
}
/* 작업자 이름 (카드 상단 헤더) */
.tbm-work-table tbody tr[data-type] td:nth-child(1) {
width: 100%;
background: linear-gradient(135deg, #f8fafc, #f1f5f9);
padding: 0.625rem 0.875rem;
border-bottom: 1px solid #e5e7eb;
}
.tbm-work-table tbody tr[data-type] td:nth-child(1) .worker-cell {
display: flex;
align-items: center;
gap: 0.5rem;
min-width: 0;
}
.tbm-work-table tbody tr[data-type] td:nth-child(1) .worker-cell strong {
margin-bottom: 0;
font-size: 0.95rem;
}
/* 프로젝트/공정/작업/작업장소 → 2열 그리드 */
.tbm-work-table tbody tr[data-type] td:nth-child(2),
.tbm-work-table tbody tr[data-type] td:nth-child(3),
.tbm-work-table tbody tr[data-type] td:nth-child(4),
.tbm-work-table tbody tr[data-type] td:nth-child(5) {
width: 50%;
padding: 0.5rem 0.875rem;
font-size: 0.8rem;
box-sizing: border-box;
}
.tbm-work-table tbody tr[data-type] td:nth-child(2)::before,
.tbm-work-table tbody tr[data-type] td:nth-child(3)::before,
.tbm-work-table tbody tr[data-type] td:nth-child(4)::before,
.tbm-work-table tbody tr[data-type] td:nth-child(5)::before {
content: attr(data-label);
display: block;
font-size: 0.7rem;
font-weight: 600;
color: #6b7280;
margin-bottom: 0.125rem;
text-transform: uppercase;
letter-spacing: 0.03em;
}
/* 작업시간 + 부적합 + 제출 → 하단 풀 영역 */
.tbm-work-table tbody tr[data-type] td:nth-child(6),
.tbm-work-table tbody tr[data-type] td:nth-child(7),
.tbm-work-table tbody tr[data-type] td:nth-child(8) {
padding: 0.5rem 0.875rem;
box-sizing: border-box;
}
/* 작업시간 */
.tbm-work-table tbody tr[data-type] td:nth-child(6) {
width: 40%;
border-top: 1px solid #f3f4f6;
}
.tbm-work-table tbody tr[data-type] td:nth-child(6)::before {
content: '작업시간';
display: block;
font-size: 0.7rem;
font-weight: 600;
color: #6b7280;
margin-bottom: 0.25rem;
}
/* 부적합 */
.tbm-work-table tbody tr[data-type] td:nth-child(7) {
width: 30%;
border-top: 1px solid #f3f4f6;
}
/* 제출 */
.tbm-work-table tbody tr[data-type] td:nth-child(8) {
width: 30%;
border-top: 1px solid #f3f4f6;
display: flex;
align-items: center;
justify-content: flex-end;
}
/* 수동 입력의 날짜 컬럼 처리 (9개 컬럼) */
.manual-input-section .tbm-work-table tbody tr[data-type] td:nth-child(2) {
width: 50%;
}
.manual-input-section .tbm-work-table tbody tr[data-type] td:nth-child(2)::before {
content: '날짜';
}
.manual-input-section .tbm-work-table tbody tr[data-type] td:nth-child(3) {
width: 50%;
}
.manual-input-section .tbm-work-table tbody tr[data-type] td:nth-child(3)::before {
content: '프로젝트';
}
.manual-input-section .tbm-work-table tbody tr[data-type] td:nth-child(4)::before {
content: '공정';
}
.manual-input-section .tbm-work-table tbody tr[data-type] td:nth-child(5)::before {
content: '작업';
}
.manual-input-section .tbm-work-table tbody tr[data-type] td:nth-child(6) {
width: 50%;
}
.manual-input-section .tbm-work-table tbody tr[data-type] td:nth-child(6)::before {
content: '작업장소';
}
.manual-input-section .tbm-work-table tbody tr[data-type] td:nth-child(7) {
width: 50%;
border-top: 1px solid #f3f4f6;
}
.manual-input-section .tbm-work-table tbody tr[data-type] td:nth-child(7)::before {
content: '작업시간';
display: block;
font-size: 0.7rem;
font-weight: 600;
color: #6b7280;
margin-bottom: 0.25rem;
}
.manual-input-section .tbm-work-table tbody tr[data-type] td:nth-child(8) {
width: 25%;
border-top: 1px solid #f3f4f6;
}
.manual-input-section .tbm-work-table tbody tr[data-type] td:nth-child(9) {
width: 25%;
border-top: 1px solid #f3f4f6;
display: flex;
align-items: center;
justify-content: flex-end;
padding: 0.5rem 0.875rem;
}
/* 수동 입력 select/input 모바일 크기 조정 */
.manual-input-section .form-input-compact {
width: 100% !important;
min-width: 0;
font-size: 0.8rem;
}
/* 부적합 행 (defect-row) 카드 모바일 */
.tbm-work-table tbody tr.defect-row {
display: block;
margin-top: -0.75rem;
border: 1px solid #fde68a;
border-top: none;
border-radius: 0 0 10px 10px;
background: #fef3c7;
padding: 0;
}
.tbm-work-table tbody tr.defect-row td {
display: block;
width: 100%;
padding: 0.75rem;
}
.tbm-work-table tbody tr.defect-row td[colspan] {
padding: 0.75rem;
}
/* 시간 입력 트리거 모바일 확대 */
.time-input-trigger {
min-height: 44px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.95rem;
padding: 0.5rem 0.75rem;
}
/* 제출 버튼 터치 타겟 확대 */
.btn-submit-compact {
min-height: 44px;
min-width: 60px;
padding: 0.625rem 1rem;
font-size: 0.875rem;
}
/* 부적합 버튼 터치 타겟 확대 */
.btn-defect-toggle {
min-height: 44px;
min-width: 60px;
padding: 0.5rem 0.625rem;
font-size: 0.8rem;
}
/* 일괄제출 버튼 모바일 full-width */
.batch-submit-container {
padding: 0.75rem;
}
.btn-batch-submit {
width: 100%;
min-height: 48px;
font-size: 0.95rem;
padding: 0.75rem 1rem;
border-radius: 8px;
}
/* --- 시간 선택 피커 모바일 --- */
.time-picker-popup {
max-width: 340px;
padding: 1.25rem;
}
.quick-time-grid {
grid-template-columns: repeat(3, 1fr);
gap: 0.625rem;
}
.time-btn {
min-height: 56px;
padding: 0.75rem 0.375rem;
font-size: 0.95rem;
border-radius: 8px;
}
.time-btn .time-value {
font-size: 1rem;
}
.adjust-btn {
min-height: 48px;
font-size: 0.95rem;
}
.confirm-btn {
min-height: 52px;
font-size: 1rem;
}
/* --- 작업장소 모달 모바일 --- */
#workplaceModal .modal-container {
width: 95% !important;
max-width: none !important;
}
/* --- 신고 리마인더 모바일 --- */
.issue-reminder-section {
margin: 0 0 0.75rem 0;
border-radius: 8px;
}
.issue-reminder-item {
flex-wrap: wrap;
gap: 0.25rem;
}
/* --- 작업 추가 버튼 모바일 --- */
.btn-add-work {
min-height: 44px;
padding: 0.625rem 1rem;
}
/* --- 삭제 버튼 모바일 --- */
.btn-delete-compact {
min-height: 44px;
min-width: 44px;
}
}