Files
tk-factory-services/tkpurchase/web/static/js/tkpurchase-daylabor.js
Hyungi Ahn 54bb26dbd6 fix(tkpurchase): 일정 목록 미표시 버그 수정 — 캐시·타임존·페이지네이션
- API에 Cache-Control: no-store 미들웨어 추가 (304 캐시 문제 해결)
- toLocalDate() 유틸 추가, 전체 8개 JS의 toISOString 타임존 버그 수정
- scheduleModel.findAll에 total COUNT 추가, 컨트롤러에서 total 반환
- HTML 캐시 버스팅 ?v=2026031601

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 07:34:40 +09:00

174 lines
6.9 KiB
JavaScript

/* tkpurchase-daylabor.js - Day labor management */
let dayLaborPage = 1;
const dayLaborLimit = 20;
async function loadDayLabor() {
const dateFrom = document.getElementById('filterDateFrom').value;
const dateTo = document.getElementById('filterDateTo').value;
const status = document.getElementById('filterStatus').value;
const department = document.getElementById('filterDepartment').value;
let query = `?page=${dayLaborPage}&limit=${dayLaborLimit}`;
if (dateFrom) query += '&date_from=' + dateFrom;
if (dateTo) query += '&date_to=' + dateTo;
if (status) query += '&status=' + status;
if (department) query += '&department=' + encodeURIComponent(department);
try {
const r = await api('/day-labor' + query);
renderDayLaborTable(r.data || [], r.total || 0);
} catch(e) {
console.warn('Day labor load error:', e);
document.getElementById('dayLaborTableBody').innerHTML = '<tr><td colspan="8" class="text-center text-red-400 py-8">로딩 실패</td></tr>';
}
}
function renderDayLaborTable(list, total) {
const tbody = document.getElementById('dayLaborTableBody');
if (!list.length) {
tbody.innerHTML = '<tr><td colspan="8" class="text-center text-gray-400 py-8">신청 내역이 없습니다</td></tr>';
document.getElementById('dayLaborPagination').innerHTML = '';
return;
}
const statusMap = {
pending: ['badge-amber', '대기'],
approved: ['badge-green', '승인'],
rejected: ['badge-red', '거절'],
completed: ['badge-gray', '완료']
};
tbody.innerHTML = list.map(d => {
const [cls, label] = statusMap[d.status] || ['badge-gray', d.status];
let actions = '';
if (d.status === 'pending') {
actions = `
<button onclick="approveDayLabor(${d.id})" class="text-emerald-600 hover:text-emerald-800 text-xs mr-1" title="승인"><i class="fas fa-check"></i></button>
<button onclick="rejectDayLabor(${d.id})" class="text-red-500 hover:text-red-700 text-xs" title="거절"><i class="fas fa-times"></i></button>`;
} else if (d.status === 'approved') {
actions = `<button onclick="completeDayLabor(${d.id})" class="text-blue-600 hover:text-blue-800 text-xs" title="완료"><i class="fas fa-check-double"></i></button>`;
}
return `<tr>
<td>${formatDate(d.created_at)}</td>
<td class="font-medium">${formatDate(d.work_date)}</td>
<td>${escapeHtml(d.requester_name || '')}</td>
<td class="hide-mobile">${escapeHtml(d.department || '')}</td>
<td class="text-center">${d.worker_count || 0}명</td>
<td>${escapeHtml(d.workplace_name || '')}</td>
<td><span class="badge ${cls}">${label}</span></td>
<td class="text-right">${actions}</td>
</tr>`;
}).join('');
// Pagination
const totalPages = Math.ceil(total / dayLaborLimit);
renderDayLaborPagination(totalPages);
}
function renderDayLaborPagination(totalPages) {
const container = document.getElementById('dayLaborPagination');
if (totalPages <= 1) { container.innerHTML = ''; return; }
let html = '';
if (dayLaborPage > 1) {
html += `<button onclick="goToDayLaborPage(${dayLaborPage - 1})" class="px-3 py-1 border rounded text-sm hover:bg-gray-50">&laquo;</button>`;
}
for (let i = 1; i <= totalPages; i++) {
if (i === dayLaborPage) {
html += `<button class="px-3 py-1 bg-emerald-600 text-white rounded text-sm">${i}</button>`;
} else if (Math.abs(i - dayLaborPage) <= 2 || i === 1 || i === totalPages) {
html += `<button onclick="goToDayLaborPage(${i})" class="px-3 py-1 border rounded text-sm hover:bg-gray-50">${i}</button>`;
} else if (Math.abs(i - dayLaborPage) === 3) {
html += '<span class="text-gray-400">...</span>';
}
}
if (dayLaborPage < totalPages) {
html += `<button onclick="goToDayLaborPage(${dayLaborPage + 1})" class="px-3 py-1 border rounded text-sm hover:bg-gray-50">&raquo;</button>`;
}
container.innerHTML = html;
}
function goToDayLaborPage(p) {
dayLaborPage = p;
loadDayLabor();
}
function openAddDayLabor() {
document.getElementById('addDayLaborForm').reset();
// Default to tomorrow
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
document.getElementById('addWorkDate').value = toLocalDate(tomorrow);
document.getElementById('addDayLaborModal').classList.remove('hidden');
}
function closeAddDayLabor() {
document.getElementById('addDayLaborModal').classList.add('hidden');
}
async function submitAddDayLabor(e) {
e.preventDefault();
const body = {
work_date: document.getElementById('addWorkDate').value,
worker_count: parseInt(document.getElementById('addWorkerCount').value) || 1,
work_description: document.getElementById('addWorkDescription').value.trim(),
workplace_name: document.getElementById('addWorkplaceName').value.trim(),
notes: document.getElementById('addNotes').value.trim()
};
if (!body.work_date) { showToast('작업일을 선택하세요', 'error'); return; }
try {
await api('/day-labor', { method: 'POST', body: JSON.stringify(body) });
showToast('일용공 신청이 등록되었습니다');
closeAddDayLabor();
loadDayLabor();
} catch(e) {
showToast(e.message || '등록 실패', 'error');
}
}
async function approveDayLabor(id) {
if (!confirm('이 신청을 승인하시겠습니까?')) return;
try {
await api('/day-labor/' + id + '/approve', { method: 'PUT' });
showToast('승인되었습니다');
loadDayLabor();
} catch(e) {
showToast(e.message || '승인 실패', 'error');
}
}
async function rejectDayLabor(id) {
const reason = prompt('거절 사유를 입력하세요:');
if (reason === null) return;
try {
await api('/day-labor/' + id + '/reject', { method: 'PUT', body: JSON.stringify({ reason }) });
showToast('거절되었습니다');
loadDayLabor();
} catch(e) {
showToast(e.message || '거절 실패', 'error');
}
}
async function completeDayLabor(id) {
if (!confirm('이 신청을 완료 처리하시겠습니까?')) return;
try {
await api('/day-labor/' + id + '/complete', { method: 'PUT' });
showToast('완료 처리되었습니다');
loadDayLabor();
} catch(e) {
showToast(e.message || '완료 처리 실패', 'error');
}
}
function initDayLaborPage() {
if (!initAuth()) return;
// Set default date range to this month
const now = new Date();
const firstDay = new Date(now.getFullYear(), now.getMonth(), 1);
document.getElementById('filterDateFrom').value = toLocalDate(firstDay);
document.getElementById('filterDateTo').value = toLocalDate(now);
loadDayLabor();
}