feat(tkfb): 모바일 전체 최적화 — 네비 수정 + 공통 기반 + 페이지별 개선
Phase 1: 기반 수정 - 햄버거 메뉴 .mobile-open 규칙 커밋 (네비 버그 수정) - 36개 HTML 파일 tkfb.css 캐시 버스팅 ?v=2026031601 - tkfb.css 공통 모바일 기반: 터치 44px, iOS 줌 방지, 테이블 스크롤, 모달 최적화 Phase 2: 페이지별 최적화 - 그룹 A (심각): daily.html, work-status.html JS 카드 뷰 변환 - 그룹 A: monthly.html 모바일 컨트롤 스택 + No열 숨김 + 범례 그리드 - 공통 CSS: 페이지 헤더/컨트롤/필터 스택, 탭 가로 스크롤, 폼 2열→1열, 요약 바 wrap, 저장 바 sticky, 작업자 칩 터치 최적화, 2열 레이아웃→세로 스택, 테이블 래퍼 오버플로, 모달 풀스크린 - 개별 페이지: checkin, vacation-management, vacation-approval, projects, repair-management, annual-overview 인라인 모바일 스타일 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
<title>출퇴근-작업보고서 대조 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<style>
|
||||
.comparison-grid {
|
||||
display: grid;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>부서 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<style>
|
||||
.department-grid {
|
||||
display: grid;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>설비 상세 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<link rel="stylesheet" href="/css/equipment-detail.css?v=2026031401">
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>설비 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<link rel="stylesheet" href="/css/equipment-management.css?v=2026031401">
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>신고 카테고리 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<style>
|
||||
.type-tabs {
|
||||
display: flex;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>알림 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<style>
|
||||
.notification-page-container {
|
||||
max-width: 1000px;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>프로젝트 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<style>
|
||||
.page-wrapper {
|
||||
max-width: 1600px;
|
||||
@@ -223,6 +223,14 @@
|
||||
color: #6b7280;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.header-controls { flex-wrap: wrap; gap: 0.5rem; }
|
||||
.search-input { width: 100% !important; }
|
||||
.table-wrapper { max-height: none; }
|
||||
.stats-bar { display: grid; grid-template-columns: repeat(4, 1fr); }
|
||||
.modal-container { width: 95% !important; }
|
||||
.form-row { grid-template-columns: 1fr !important; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>소모품 분석 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>시설설비 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<style>
|
||||
.repair-page {
|
||||
max-width: 1400px;
|
||||
@@ -339,19 +339,39 @@
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
flex: 1 1 45%;
|
||||
flex: 1 1 calc(50% - 0.5rem);
|
||||
}
|
||||
|
||||
.repair-table-container {
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.repair-table {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.repair-table th,
|
||||
.repair-table td {
|
||||
padding: 0.625rem 0.5rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.repair-table th:nth-child(3),
|
||||
.repair-table td:nth-child(3),
|
||||
.repair-table th:nth-child(5),
|
||||
.repair-table td:nth-child(5) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.repair-desc {
|
||||
max-width: 120px;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
width: 95% !important;
|
||||
max-width: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>작업 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<style>
|
||||
.page-wrapper { max-width: 1400px; }
|
||||
.page-header {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>작업장 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<link rel="stylesheet" href="/css/workplace-management.css?v=2026031401">
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>연간 연차 현황 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<style>
|
||||
.page-wrapper {
|
||||
padding: 1.5rem;
|
||||
@@ -230,6 +230,16 @@
|
||||
}
|
||||
|
||||
.loading { text-align: center; padding: 2rem; color: #6b7280; }
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.controls { flex-wrap: wrap; gap: 0.5rem; }
|
||||
.controls select { flex: 1; }
|
||||
.legend-box { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.5rem; }
|
||||
.data-table { font-size: 0.7rem; }
|
||||
.data-table th, .data-table td { padding: 0.375rem 0.25rem; }
|
||||
.num-input { width: 45px; font-size: 0.75rem; }
|
||||
.save-bar { position: sticky; bottom: 0; z-index: 20; background: white; box-shadow: 0 -2px 8px rgba(0,0,0,0.08); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>출근 체크 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<style>
|
||||
.page-wrapper {
|
||||
padding: 1.5rem;
|
||||
@@ -156,6 +156,18 @@
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
}
|
||||
|
||||
/* 모바일 최적화 */
|
||||
@media (max-width: 768px) {
|
||||
.summary-bar { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; padding: 0.75rem; }
|
||||
.summary-item { flex-direction: column; text-align: center; }
|
||||
.summary-count { font-size: 1.25rem; }
|
||||
.controls { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; }
|
||||
.controls input[type="date"] { grid-column: 1 / -1; }
|
||||
.worker-chip { padding: 0.625rem 1rem; font-size: 1rem; }
|
||||
.btn-save { width: 100%; font-size: 1.1rem; padding: 1rem; }
|
||||
.save-section { position: sticky; bottom: 0; background: white; padding: 1rem; margin: 0 -1rem; box-shadow: 0 -2px 8px rgba(0,0,0,0.08); z-index: 20; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>일일 출퇴근 입력 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
@@ -250,76 +250,140 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const tableHTML = `
|
||||
<table class="data-table" style="font-size: 0.95rem;">
|
||||
<thead style="background-color: #f8f9fa;">
|
||||
<tr>
|
||||
<th style="width: 120px;">작업자</th>
|
||||
<th style="width: 180px;">근태 구분</th>
|
||||
<th style="width: 100px;">근무시간</th>
|
||||
<th style="width: 120px;">연장근로</th>
|
||||
<th style="width: 100px;">특이사항</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
const isMobile = window.innerWidth <= 768;
|
||||
|
||||
if (isMobile) {
|
||||
// 모바일: 카드 뷰
|
||||
const cardsHTML = `
|
||||
<div class="mobile-attendance-cards">
|
||||
${attendanceRecords.map((record, index) => {
|
||||
const isCustom = record.is_custom || record.attendance_type === 'custom';
|
||||
const isHoursReadonly = !isCustom; // 특이사항이 아니면 근무시간은 읽기 전용
|
||||
|
||||
const isHoursReadonly = !isCustom;
|
||||
const isOnVacation = record.is_on_vacation || false;
|
||||
const vacationLabel = record.vacation_type_name ? ` (${record.vacation_type_name})` : '';
|
||||
|
||||
return `
|
||||
<tr style="border-bottom: 1px solid #e5e7eb; ${isOnVacation ? 'background-color: #f0f9ff;' : ''}">
|
||||
<td style="padding: 0.75rem; font-weight: 600;">
|
||||
<div class="mobile-attendance-card ${isOnVacation ? 'vacation' : ''}">
|
||||
<div class="card-name">
|
||||
${record.worker_name}
|
||||
${isOnVacation ? `<span style="margin-left: 0.5rem; display: inline-block; padding: 0.125rem 0.5rem; background-color: #dbeafe; color: #1e40af; border-radius: 0.25rem; font-size: 0.75rem; font-weight: 500;">연차${vacationLabel}</span>` : ''}
|
||||
</td>
|
||||
<td style="padding: 0.75rem;">
|
||||
<select class="form-control"
|
||||
onchange="updateAttendanceType(${index}, this.value)"
|
||||
style="width: 160px; padding: 0.5rem; border: 1px solid #d1d5db; border-radius: 0.375rem;">
|
||||
${attendanceTypes.map(type => `
|
||||
<option value="${type.value}" ${record.attendance_type === type.value ? 'selected' : ''}>
|
||||
${type.label}
|
||||
</option>
|
||||
`).join('')}
|
||||
</select>
|
||||
</td>
|
||||
<td style="padding: 0.75rem;">
|
||||
<input type="number" class="form-control"
|
||||
id="hours_${index}"
|
||||
value="${record.total_hours || 0}"
|
||||
min="0" max="24" step="0.5"
|
||||
${isHoursReadonly ? 'readonly' : ''}
|
||||
onchange="updateTotalHours(${index}, this.value)"
|
||||
style="width: 90px; padding: 0.5rem; border: 1px solid ${isHoursReadonly ? '#e5e7eb' : '#d1d5db'};
|
||||
border-radius: 0.375rem; background-color: ${isHoursReadonly ? '#f9fafb' : 'white'}; text-align: center;">
|
||||
</td>
|
||||
<td style="padding: 0.75rem;">
|
||||
<input type="number" class="form-control"
|
||||
id="overtime_${index}"
|
||||
value="${record.overtime_hours || 0}"
|
||||
min="0" max="12" step="0.5"
|
||||
onchange="updateOvertimeHours(${index}, this.value)"
|
||||
style="width: 90px; padding: 0.5rem; border: 1px solid #d1d5db;
|
||||
border-radius: 0.375rem; background-color: white; text-align: center;">
|
||||
</td>
|
||||
<td style="padding: 0.75rem; text-align: center;">
|
||||
${isCustom ?
|
||||
'<span style="color: #dc2626; font-weight: 600;">✓</span>' :
|
||||
'<span style="color: #9ca3af;">-</span>'}
|
||||
</td>
|
||||
</tr>
|
||||
${isOnVacation ? `<span style="padding: 0.125rem 0.5rem; background: #dbeafe; color: #1e40af; border-radius: 0.25rem; font-size: 0.7rem; font-weight: 500;">연차${vacationLabel}</span>` : ''}
|
||||
</div>
|
||||
<div class="card-fields">
|
||||
<div class="card-field">
|
||||
<label>근태 구분</label>
|
||||
<select onchange="updateAttendanceType(${index}, this.value)">
|
||||
${attendanceTypes.map(type => `
|
||||
<option value="${type.value}" ${record.attendance_type === type.value ? 'selected' : ''}>${type.label}</option>
|
||||
`).join('')}
|
||||
</select>
|
||||
</div>
|
||||
<div class="card-field">
|
||||
<label>근무시간</label>
|
||||
<input type="number" id="hours_${index}" value="${record.total_hours || 0}"
|
||||
min="0" max="24" step="0.5" ${isHoursReadonly ? 'readonly' : ''}
|
||||
onchange="updateTotalHours(${index}, this.value)"
|
||||
style="background: ${isHoursReadonly ? '#f9fafb' : 'white'}; text-align: center;">
|
||||
</div>
|
||||
<div class="card-field">
|
||||
<label>연장근로</label>
|
||||
<input type="number" id="overtime_${index}" value="${record.overtime_hours || 0}"
|
||||
min="0" max="12" step="0.5"
|
||||
onchange="updateOvertimeHours(${index}, this.value)"
|
||||
style="text-align: center;">
|
||||
</div>
|
||||
<div class="card-field">
|
||||
<label>특이사항</label>
|
||||
<div style="padding: 0.5rem; text-align: center;">
|
||||
${isCustom ? '<span style="color: #dc2626; font-weight: 600;">✓</span>' : '<span style="color: #9ca3af;">-</span>'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('')}
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
</div>
|
||||
`;
|
||||
container.innerHTML = cardsHTML;
|
||||
} else {
|
||||
// 데스크탑: 테이블 뷰
|
||||
const tableHTML = `
|
||||
<table class="data-table" style="font-size: 0.95rem;">
|
||||
<thead style="background-color: #f8f9fa;">
|
||||
<tr>
|
||||
<th style="width: 120px;">작업자</th>
|
||||
<th style="width: 180px;">근태 구분</th>
|
||||
<th style="width: 100px;">근무시간</th>
|
||||
<th style="width: 120px;">연장근로</th>
|
||||
<th style="width: 100px;">특이사항</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${attendanceRecords.map((record, index) => {
|
||||
const isCustom = record.is_custom || record.attendance_type === 'custom';
|
||||
const isHoursReadonly = !isCustom;
|
||||
const isOnVacation = record.is_on_vacation || false;
|
||||
const vacationLabel = record.vacation_type_name ? ` (${record.vacation_type_name})` : '';
|
||||
|
||||
container.innerHTML = tableHTML;
|
||||
return `
|
||||
<tr style="border-bottom: 1px solid #e5e7eb; ${isOnVacation ? 'background-color: #f0f9ff;' : ''}">
|
||||
<td style="padding: 0.75rem; font-weight: 600;">
|
||||
${record.worker_name}
|
||||
${isOnVacation ? `<span style="margin-left: 0.5rem; display: inline-block; padding: 0.125rem 0.5rem; background-color: #dbeafe; color: #1e40af; border-radius: 0.25rem; font-size: 0.75rem; font-weight: 500;">연차${vacationLabel}</span>` : ''}
|
||||
</td>
|
||||
<td style="padding: 0.75rem;">
|
||||
<select class="form-control"
|
||||
onchange="updateAttendanceType(${index}, this.value)"
|
||||
style="width: 160px; padding: 0.5rem; border: 1px solid #d1d5db; border-radius: 0.375rem;">
|
||||
${attendanceTypes.map(type => `
|
||||
<option value="${type.value}" ${record.attendance_type === type.value ? 'selected' : ''}>
|
||||
${type.label}
|
||||
</option>
|
||||
`).join('')}
|
||||
</select>
|
||||
</td>
|
||||
<td style="padding: 0.75rem;">
|
||||
<input type="number" class="form-control"
|
||||
id="hours_${index}"
|
||||
value="${record.total_hours || 0}"
|
||||
min="0" max="24" step="0.5"
|
||||
${isHoursReadonly ? 'readonly' : ''}
|
||||
onchange="updateTotalHours(${index}, this.value)"
|
||||
style="width: 90px; padding: 0.5rem; border: 1px solid ${isHoursReadonly ? '#e5e7eb' : '#d1d5db'};
|
||||
border-radius: 0.375rem; background-color: ${isHoursReadonly ? '#f9fafb' : 'white'}; text-align: center;">
|
||||
</td>
|
||||
<td style="padding: 0.75rem;">
|
||||
<input type="number" class="form-control"
|
||||
id="overtime_${index}"
|
||||
value="${record.overtime_hours || 0}"
|
||||
min="0" max="12" step="0.5"
|
||||
onchange="updateOvertimeHours(${index}, this.value)"
|
||||
style="width: 90px; padding: 0.5rem; border: 1px solid #d1d5db;
|
||||
border-radius: 0.375rem; background-color: white; text-align: center;">
|
||||
</td>
|
||||
<td style="padding: 0.75rem; text-align: center;">
|
||||
${isCustom ?
|
||||
'<span style="color: #dc2626; font-weight: 600;">✓</span>' :
|
||||
'<span style="color: #9ca3af;">-</span>'}
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
}).join('')}
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
container.innerHTML = tableHTML;
|
||||
}
|
||||
}
|
||||
|
||||
// 화면 크기 변경 시 재렌더링
|
||||
let resizeTimer;
|
||||
window.addEventListener('resize', () => {
|
||||
clearTimeout(resizeTimer);
|
||||
resizeTimer = setTimeout(() => {
|
||||
if (attendanceRecords.length > 0) renderAttendanceList();
|
||||
}, 250);
|
||||
});
|
||||
|
||||
function updateTotalHours(index, value) {
|
||||
attendanceRecords[index].total_hours = parseFloat(value) || 0;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>월별 출근부 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<style>
|
||||
/* 테이블 컨테이너 */
|
||||
.table-container {
|
||||
@@ -349,6 +349,30 @@
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
|
||||
/* 모바일 최적화 */
|
||||
@media (max-width: 768px) {
|
||||
.page-actions {
|
||||
flex-direction: column !important;
|
||||
width: 100%;
|
||||
}
|
||||
.page-actions input[type="month"],
|
||||
.page-actions .btn { width: 100%; }
|
||||
.page-actions .btn { justify-content: center; text-align: center; }
|
||||
.summary-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; }
|
||||
.summary-card { min-width: 0; }
|
||||
.legend-container { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.5rem; }
|
||||
.table-container { margin: 0 -0.5rem; }
|
||||
.attendance-table th.fixed-no,
|
||||
.attendance-table td.fixed-no { display: none; }
|
||||
.attendance-table th.fixed-name,
|
||||
.attendance-table td.fixed-name { left: 0; }
|
||||
.attendance-table th.fixed-job,
|
||||
.attendance-table td.fixed-job { left: 60px; }
|
||||
.modal-content { width: 95% !important; }
|
||||
.add-holiday-form { flex-direction: column; }
|
||||
.add-holiday-form input, .add-holiday-form .btn { width: 100%; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>내 연차 정보 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<style>
|
||||
.page-wrapper {
|
||||
padding: 1.5rem;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<title>휴가 발생 입력 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<link rel="stylesheet" href="/css/vacation-allocation.css">
|
||||
</head>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>휴가 승인 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<style>
|
||||
.tabs {
|
||||
display: flex;
|
||||
@@ -37,6 +37,13 @@
|
||||
.tab-content.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 모바일 최적화 */
|
||||
@media (max-width: 768px) {
|
||||
.tabs { overflow-x: auto; -webkit-overflow-scrolling: touch; flex-wrap: nowrap; scrollbar-width: none; }
|
||||
.tabs::-webkit-scrollbar { display: none; }
|
||||
.tab { flex-shrink: 0; padding: 0.625rem 1rem; white-space: nowrap; font-size: 0.875rem; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>휴가 직접 입력 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>휴가 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<style>
|
||||
.tabs {
|
||||
display: flex;
|
||||
@@ -37,6 +37,16 @@
|
||||
.tab-content.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 모바일 최적화 */
|
||||
@media (max-width: 768px) {
|
||||
.tabs { overflow-x: auto; -webkit-overflow-scrolling: touch; flex-wrap: nowrap; scrollbar-width: none; }
|
||||
.tabs::-webkit-scrollbar { display: none; }
|
||||
.tab { flex-shrink: 0; padding: 0.625rem 1rem; white-space: nowrap; font-size: 0.875rem; }
|
||||
.page-actions { flex-direction: column; width: 100%; gap: 0.5rem; }
|
||||
.page-actions input[type="date"] { width: 100%; }
|
||||
.page-actions .btn { width: 100%; text-align: center; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>휴가 신청 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>근무 현황 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<style>
|
||||
.page-wrapper {
|
||||
padding: 1.5rem;
|
||||
@@ -199,6 +199,16 @@
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.warning-box a { color: #92400e; font-weight: 500; }
|
||||
|
||||
/* 모바일 최적화 */
|
||||
@media (max-width: 768px) {
|
||||
.summary-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.375rem; font-size: 0.7rem; }
|
||||
.summary-row span { flex-direction: column; text-align: center; gap: 0.125rem; }
|
||||
.controls { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; }
|
||||
.controls input[type="date"] { grid-column: 1 / -1; }
|
||||
.save-bar { position: sticky; bottom: 0; z-index: 20; background: white; box-shadow: 0 -2px 8px rgba(0,0,0,0.08); margin: 0 -1rem; padding: 0.75rem 1rem; }
|
||||
.btn-save { width: 100%; padding: 0.75rem; font-size: 1rem; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
@@ -449,6 +459,16 @@
|
||||
}
|
||||
|
||||
function render() {
|
||||
const isMobile = window.innerWidth <= 768;
|
||||
|
||||
if (isMobile) {
|
||||
renderMobile();
|
||||
} else {
|
||||
renderDesktop();
|
||||
}
|
||||
}
|
||||
|
||||
function renderMobile() {
|
||||
const tbody = document.getElementById('workerTableBody');
|
||||
|
||||
if (workers.length === 0) {
|
||||
@@ -456,10 +476,93 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// 모바일에서는 테이블을 숨기고 카드 뷰 사용
|
||||
const table = tbody.closest('table');
|
||||
table.style.display = 'none';
|
||||
|
||||
// 기존 모바일 컨테이너 제거
|
||||
let mobileContainer = document.getElementById('mobileWorkCards');
|
||||
if (!mobileContainer) {
|
||||
mobileContainer = document.createElement('div');
|
||||
mobileContainer.id = 'mobileWorkCards';
|
||||
table.parentNode.insertBefore(mobileContainer, table.nextSibling);
|
||||
}
|
||||
|
||||
mobileContainer.className = 'mobile-work-cards';
|
||||
mobileContainer.innerHTML = workers.map((w, idx) => {
|
||||
const s = workStatus[w.user_id];
|
||||
|
||||
if (s.isNotHired) {
|
||||
return `
|
||||
<div class="mobile-work-card not-hired">
|
||||
<div class="wc-left">
|
||||
<span class="wc-name">${w.worker_name} <span class="not-hired-tag">미입사</span></span>
|
||||
<span class="wc-status" style="color:#9ca3af;">입사일: ${formatDisplayDate(s.joinDate)}</span>
|
||||
</div>
|
||||
<div class="wc-right"><span class="wc-hours">-</span></div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
const typeInfo = attendanceTypes.find(t => t.value === s.type);
|
||||
const isLeaveType = typeInfo?.isLeave || false;
|
||||
const showOvertimeInput = s.type === 'overtime';
|
||||
const baseHours = s.hours;
|
||||
const totalHours = s.type === 'overtime' ? baseHours + s.overtimeHours : baseHours;
|
||||
|
||||
let rowClass = '';
|
||||
if (s.isSaved) rowClass = isLeaveType ? 'leave' : 'saved';
|
||||
else if (!s.isPresent) rowClass = isLeaveType ? 'leave' : 'absent-no-leave';
|
||||
|
||||
let statusText = '', statusClass = '';
|
||||
if (isLeaveType) { statusText = typeInfo.label; statusClass = 'color:#a16207;'; }
|
||||
else if (s.isPresent) { statusText = '출근'; statusClass = 'color:#10b981;'; }
|
||||
else { statusText = '⚠️ 결근'; statusClass = 'color:#dc2626;font-weight:600;'; }
|
||||
|
||||
let tag = '';
|
||||
if (s.isSaved) tag = '<span class="saved-tag">저장됨</span>';
|
||||
else if (isLeaveType) tag = '<span class="leave-tag">연차</span>';
|
||||
|
||||
return `
|
||||
<div class="mobile-work-card ${rowClass}">
|
||||
<div class="wc-left">
|
||||
<span class="wc-name">${w.worker_name} ${tag}</span>
|
||||
<span class="wc-status" style="${statusClass}">${statusText}</span>
|
||||
</div>
|
||||
<div class="wc-right">
|
||||
<select onchange="updateType(${w.user_id}, this.value)">
|
||||
${attendanceTypes.map(t => `
|
||||
<option value="${t.value}" ${s.type === t.value ? 'selected' : ''}>${t.label}</option>
|
||||
`).join('')}
|
||||
</select>
|
||||
${showOvertimeInput ? `
|
||||
<input type="number" class="overtime-input" value="${s.overtimeHours}" min="0" max="8" step="0.5"
|
||||
onchange="updateOvertime(${w.user_id}, this.value)" style="width:60px;text-align:center;font-size:14px;">
|
||||
` : ''}
|
||||
<span class="wc-hours">${totalHours}h</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function renderDesktop() {
|
||||
const tbody = document.getElementById('workerTableBody');
|
||||
const table = tbody.closest('table');
|
||||
table.style.display = '';
|
||||
|
||||
// 모바일 컨테이너 숨기기
|
||||
const mobileContainer = document.getElementById('mobileWorkCards');
|
||||
if (mobileContainer) mobileContainer.remove();
|
||||
|
||||
if (workers.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="7" style="text-align:center;color:#6b7280;padding:2rem;">작업자가 없습니다</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
tbody.innerHTML = workers.map((w, idx) => {
|
||||
const s = workStatus[w.user_id];
|
||||
|
||||
// 미입사 상태 처리
|
||||
if (s.isNotHired) {
|
||||
return `
|
||||
<tr class="not-hired">
|
||||
@@ -483,36 +586,18 @@
|
||||
const baseHours = s.hours;
|
||||
const totalHours = s.type === 'overtime' ? baseHours + s.overtimeHours : baseHours;
|
||||
|
||||
// 행 클래스 결정
|
||||
let rowClass = '';
|
||||
if (s.isSaved) {
|
||||
rowClass = isLeaveType ? 'leave' : 'saved';
|
||||
} else if (!s.isPresent) {
|
||||
// 출근 안 했는데 연차 정보도 없으면 경고
|
||||
rowClass = isLeaveType ? 'leave' : 'absent-no-leave';
|
||||
}
|
||||
if (s.isSaved) rowClass = isLeaveType ? 'leave' : 'saved';
|
||||
else if (!s.isPresent) rowClass = isLeaveType ? 'leave' : 'absent-no-leave';
|
||||
|
||||
// 출근 상태 텍스트 및 클래스 결정
|
||||
let statusText = '';
|
||||
let statusClass = '';
|
||||
if (isLeaveType) {
|
||||
statusText = typeInfo.label;
|
||||
statusClass = 'status-leave';
|
||||
} else if (s.isPresent) {
|
||||
statusText = '출근';
|
||||
statusClass = 'status-present';
|
||||
} else {
|
||||
statusText = '⚠️ 결근';
|
||||
statusClass = 'status-absent-warning';
|
||||
}
|
||||
let statusText = '', statusClass = '';
|
||||
if (isLeaveType) { statusText = typeInfo.label; statusClass = 'status-leave'; }
|
||||
else if (s.isPresent) { statusText = '출근'; statusClass = 'status-present'; }
|
||||
else { statusText = '⚠️ 결근'; statusClass = 'status-absent-warning'; }
|
||||
|
||||
// 태그 표시
|
||||
let tag = '';
|
||||
if (s.isSaved) {
|
||||
tag = '<span class="saved-tag">저장됨</span>';
|
||||
} else if (isLeaveType) {
|
||||
tag = '<span class="leave-tag">연차</span>';
|
||||
}
|
||||
if (s.isSaved) tag = '<span class="saved-tag">저장됨</span>';
|
||||
else if (isLeaveType) tag = '<span class="leave-tag">연차</span>';
|
||||
|
||||
return `
|
||||
<tr class="${rowClass}">
|
||||
@@ -521,9 +606,7 @@
|
||||
<span class="worker-name">${w.worker_name}</span>
|
||||
${tag}
|
||||
</td>
|
||||
<td class="${statusClass}">
|
||||
${statusText}
|
||||
</td>
|
||||
<td class="${statusClass}">${statusText}</td>
|
||||
<td>
|
||||
<select class="type-select" onchange="updateType(${w.user_id}, this.value)">
|
||||
${attendanceTypes.map(t => `
|
||||
@@ -544,6 +627,15 @@
|
||||
}).join('');
|
||||
}
|
||||
|
||||
// 화면 크기 변경 시 재렌더링
|
||||
let resizeTimer;
|
||||
window.addEventListener('resize', () => {
|
||||
clearTimeout(resizeTimer);
|
||||
resizeTimer = setTimeout(() => {
|
||||
if (workers.length > 0) render();
|
||||
}, 250);
|
||||
});
|
||||
|
||||
function updateType(workerId, value) {
|
||||
const typeInfo = attendanceTypes.find(t => t.value === value);
|
||||
workStatus[workerId].type = value;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>대시보드 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>작업장 현황 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<link rel="stylesheet" href="/css/modern-dashboard.css?v=2026031401">
|
||||
<link rel="stylesheet" href="/css/mobile.css?v=2026031601">
|
||||
</head>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link rel="stylesheet" href="/css/daily-patrol.css?v=2026031401">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link rel="stylesheet" href="/css/zone-detail.css?v=2026031401">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>내 프로필 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
|
||||
<style>
|
||||
.profile-page {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>비밀번호 변경 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
|
||||
<style>
|
||||
/* 페이지 전용 스타일 */
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>소모품 신청 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<script src="https://cdn.jsdelivr.net/npm/heic2any@0.0.4/dist/heic2any.min.js"></script>
|
||||
<style>
|
||||
.item-dropdown { position: absolute; top: 100%; left: 0; right: 0; max-height: 280px; overflow-y: auto; background: white; border: 1px solid #e5e7eb; border-top: none; border-radius: 0 0 8px 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); z-index: 20; display: none; }
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>작업 분석 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<link rel="stylesheet" href="/css/work-analysis.css?v=2026031401">
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.js"></script>
|
||||
</head>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>부적합 현황 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-700 text-white sticky top-0 z-50">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>작업보고서 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<link rel="stylesheet" href="/css/daily-work-report-mobile.css?v=2026031401">
|
||||
<style>
|
||||
/* 데스크탑이면 리다이렉트 */
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>작업보고서 작성 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<link rel="stylesheet" href="/css/daily-work-report.css?v=2026031401">
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>TBM 등록 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<style>
|
||||
* { box-sizing: border-box; }
|
||||
button, .worker-card, .list-item, .list-item-skip, .pill-btn, .pill-btn-add,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>TBM - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<link rel="stylesheet" href="/css/tbm-mobile.css?v=2026031401">
|
||||
|
||||
</head>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>TBM 관리 - TK 공장관리</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css">
|
||||
<link rel="stylesheet" href="/static/css/tkfb.css?v=2026031601">
|
||||
<link rel="stylesheet" href="/css/tbm.css?v=2026031401">
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
|
||||
@@ -57,4 +57,158 @@ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; b
|
||||
.data-table { font-size: 0.8rem; }
|
||||
.data-table th, .data-table td { padding: 0.5rem; }
|
||||
.hide-mobile { display: none; }
|
||||
|
||||
/* 가로 스크롤 방지 */
|
||||
html, body { overflow-x: hidden !important; max-width: 100vw !important; }
|
||||
|
||||
/* 터치 타겟 최소 크기 — 테이블 내 소형 버튼 제외 */
|
||||
button, .btn, select, input[type="button"] { min-height: 44px; }
|
||||
.table-container button, .data-table button, table button { min-height: auto; }
|
||||
|
||||
/* iOS 폼 줌 방지 */
|
||||
input, select, textarea { font-size: 16px !important; }
|
||||
|
||||
/* 테이블 가로 스크롤 */
|
||||
.table-container, .data-table-wrapper { overflow-x: auto; -webkit-overflow-scrolling: touch; }
|
||||
|
||||
/* 모달 모바일 최적화 */
|
||||
.modal-content { width: 95% !important; max-width: none !important; max-height: 90vh; overflow-y: auto; }
|
||||
|
||||
/* 터치 피드백 */
|
||||
button:active, .btn:active { transform: scale(0.98); }
|
||||
|
||||
/* === 페이지 헤더 모바일 === */
|
||||
.page-header { flex-direction: column !important; align-items: stretch !important; gap: 0.75rem; }
|
||||
.page-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
||||
.page-actions input[type="date"],
|
||||
.page-actions input[type="month"],
|
||||
.page-actions .btn { flex: 1; min-width: 0; }
|
||||
|
||||
/* === 컨트롤 / 필터 모바일 === */
|
||||
.controls, .header-controls { flex-wrap: wrap; gap: 0.5rem; }
|
||||
.controls input, .controls select { flex: 1; min-width: 100px; }
|
||||
.search-input { width: 100% !important; }
|
||||
.filter-select { min-width: 0 !important; }
|
||||
.eq-filter-section { flex-direction: column !important; gap: 0.75rem !important; }
|
||||
.eq-filter-group { width: 100% !important; }
|
||||
.eq-search-group { width: 100% !important; }
|
||||
|
||||
/* === 탭 모바일 — 가로 스크롤 === */
|
||||
.tabs, .tab-navigation {
|
||||
overflow-x: auto; -webkit-overflow-scrolling: touch;
|
||||
flex-wrap: nowrap !important; gap: 0 !important;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
.tabs::-webkit-scrollbar, .tab-navigation::-webkit-scrollbar { display: none; }
|
||||
.tab, .tab-button {
|
||||
flex-shrink: 0; padding: 0.625rem 1rem;
|
||||
white-space: nowrap; font-size: 0.875rem;
|
||||
}
|
||||
|
||||
/* === 폼 그리드 2열 → 1열 === */
|
||||
[style*="grid-template-columns: repeat(2"] { grid-template-columns: 1fr !important; }
|
||||
.form-row, .eq-form-row { flex-direction: column !important; gap: 0.75rem !important; }
|
||||
.form-section { padding: 0.75rem !important; }
|
||||
|
||||
/* === 요약 바 / 통계 카드 === */
|
||||
.summary-bar { flex-wrap: wrap; gap: 0.75rem; padding: 0.75rem; }
|
||||
.summary-bar .summary-item { flex: 1 1 auto; }
|
||||
.summary-row { flex-wrap: wrap; gap: 0.5rem 1rem; font-size: 0.75rem; }
|
||||
.stats-row, .stats-bar { flex-wrap: wrap; gap: 0.5rem; }
|
||||
.stat-card { padding: 0.875rem; }
|
||||
.summary-card { min-width: 0; flex: 1 1 80px; padding: 0.5rem; }
|
||||
.summary-value { font-size: 1.1rem; }
|
||||
|
||||
/* === 저장 바 sticky === */
|
||||
.save-bar {
|
||||
position: sticky; bottom: 0; z-index: 20;
|
||||
margin: 0 -1rem; padding: 0.75rem 1rem;
|
||||
background: white; box-shadow: 0 -2px 8px rgba(0,0,0,0.08);
|
||||
}
|
||||
|
||||
/* === 작업자 칩 터치 최적화 === */
|
||||
.worker-chip { padding: 0.5rem 0.875rem; font-size: 0.9375rem; margin: 0.25rem; }
|
||||
|
||||
/* === 2열 레이아웃 → 세로 스택 (순회점검 등) === */
|
||||
.patrol-content { flex-direction: column !important; }
|
||||
.patrol-map-section, .patrol-checklist-section { width: 100% !important; }
|
||||
|
||||
/* === 범례 === */
|
||||
.legend-container { gap: 0.75rem; padding: 0.75rem; font-size: 0.8rem; }
|
||||
.legend-box { gap: 0.5rem 0.75rem; font-size: 0.75rem; padding: 0.5rem 0.75rem; }
|
||||
|
||||
/* === 테이블 오버플로 === */
|
||||
.table-responsive, .repair-table-container, .eq-table-container,
|
||||
.table-wrapper, .data-table-container { overflow-x: auto; -webkit-overflow-scrolling: touch; }
|
||||
|
||||
/* === 모달 풀스크린 === */
|
||||
.modal-container { width: 95% !important; max-width: none !important; }
|
||||
|
||||
/* === 카드 간격 조정 === */
|
||||
.card { margin-bottom: 0.75rem; }
|
||||
.card-header { padding: 0.875rem 1rem; }
|
||||
.card-body { padding: 0.875rem 1rem; }
|
||||
.content-section { margin-bottom: 0.75rem; }
|
||||
|
||||
/* === 일일출퇴근 모바일 카드 뷰 === */
|
||||
.mobile-attendance-cards { display: flex; flex-direction: column; gap: 0.5rem; }
|
||||
.mobile-attendance-card {
|
||||
background: white; border-radius: 0.75rem; padding: 0.875rem;
|
||||
border: 1px solid #e5e7eb; box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
||||
}
|
||||
.mobile-attendance-card.vacation { background: #f0f9ff; border-color: #bae6fd; }
|
||||
.mobile-attendance-card .card-name {
|
||||
font-weight: 600; font-size: 0.9375rem; margin-bottom: 0.5rem;
|
||||
display: flex; align-items: center; gap: 0.5rem;
|
||||
}
|
||||
.mobile-attendance-card .card-fields {
|
||||
display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem;
|
||||
}
|
||||
.mobile-attendance-card .card-field label {
|
||||
display: block; font-size: 0.7rem; color: #6b7280; margin-bottom: 0.25rem;
|
||||
}
|
||||
.mobile-attendance-card .card-field select,
|
||||
.mobile-attendance-card .card-field input {
|
||||
width: 100%; padding: 0.5rem; border: 1px solid #d1d5db;
|
||||
border-radius: 0.375rem; font-size: 14px;
|
||||
}
|
||||
|
||||
/* === 근무현황 모바일 카드 뷰 === */
|
||||
.mobile-work-cards { display: flex; flex-direction: column; gap: 0.5rem; }
|
||||
.mobile-work-card {
|
||||
display: grid; grid-template-columns: 1fr auto;
|
||||
gap: 0.5rem; align-items: center;
|
||||
padding: 0.75rem; background: white; border-radius: 0.5rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
.mobile-work-card.saved { background: #f0fdf4; }
|
||||
.mobile-work-card.leave { background: #fefce8; }
|
||||
.mobile-work-card.absent-no-leave { background: #fee2e2; }
|
||||
.mobile-work-card.not-hired { background: #f3f4f6; color: #9ca3af; }
|
||||
.mobile-work-card .wc-left { display: flex; flex-direction: column; gap: 0.25rem; }
|
||||
.mobile-work-card .wc-name { font-weight: 600; font-size: 0.9375rem; }
|
||||
.mobile-work-card .wc-status { font-size: 0.75rem; }
|
||||
.mobile-work-card .wc-right { display: flex; flex-direction: column; align-items: flex-end; gap: 0.375rem; }
|
||||
.mobile-work-card .wc-right select { font-size: 14px; padding: 0.375rem; border: 1px solid #d1d5db; border-radius: 0.25rem; }
|
||||
.mobile-work-card .wc-hours { font-size: 0.8125rem; font-weight: 600; }
|
||||
|
||||
/* === 소모품 신청 모바일 카드 목록 === */
|
||||
.mobile-request-cards { display: flex; flex-direction: column; gap: 0.5rem; }
|
||||
.mobile-request-card {
|
||||
background: white; border-radius: 0.5rem; padding: 0.75rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
.mobile-request-card .rc-header {
|
||||
display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem;
|
||||
}
|
||||
.mobile-request-card .rc-item-name { font-weight: 600; font-size: 0.875rem; }
|
||||
.mobile-request-card .rc-details { font-size: 0.75rem; color: #6b7280; }
|
||||
|
||||
/* === 프로필 페이지 === */
|
||||
.profile-grid { grid-template-columns: 1fr !important; }
|
||||
}
|
||||
|
||||
/* Mobile nav */
|
||||
#sideNav.mobile-open {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user