/**
* proxy-input.js — 대리입력 리뉴얼
* Step 1: 날짜 선택 → 작업자 목록 (체크박스)
* Step 2: 선택 작업자 일괄 편집 → 저장 (TBM 자동 생성)
*/
let currentDate = '';
let allWorkers = [];
let selectedIds = new Set();
let projects = [];
let workTypes = [];
let editData = {}; // { userId: { project_id, work_type_id, work_hours, defect_hours, note } }
// ===== Init =====
document.addEventListener('DOMContentLoaded', () => {
const now = new Date();
currentDate = now.toISOString().substring(0, 10);
document.getElementById('dateInput').value = currentDate;
setTimeout(async () => {
await loadDropdownData();
await loadWorkers();
}, 500);
});
async function loadDropdownData() {
try {
const [pRes, wRes] = await Promise.all([
window.apiCall('/projects'),
window.apiCall('/daily-work-reports/work-types')
]);
projects = (pRes.data || pRes || []).filter(p => p.is_active !== 0);
workTypes = (wRes.data || wRes || []).filter(w => w.is_active !== 0);
} catch (e) { console.warn('드롭다운 로드 실패:', e); }
}
// ===== Step 1: Worker List =====
async function loadWorkers() {
currentDate = document.getElementById('dateInput').value;
if (!currentDate) return;
const list = document.getElementById('workerList');
list.innerHTML = '
';
selectedIds.clear();
updateEditButton();
try {
const res = await window.apiCall('/proxy-input/daily-status?date=' + currentDate);
if (!res.success) throw new Error(res.message);
allWorkers = res.data.workers || [];
const s = res.data.summary || {};
document.getElementById('totalNum').textContent = s.total_active_workers || 0;
document.getElementById('doneNum').textContent = s.report_completed || 0;
document.getElementById('missingNum').textContent = s.report_missing || 0;
document.getElementById('vacNum').textContent = allWorkers.filter(w => w.vacation_type_code === 'ANNUAL_FULL').length;
renderWorkerList();
} catch (e) {
list.innerHTML = '';
}
}
function renderWorkerList() {
const list = document.getElementById('workerList');
if (!allWorkers.length) {
list.innerHTML = '';
return;
}
list.innerHTML = allWorkers.map(w => {
const isFullVac = w.vacation_type_code === 'ANNUAL_FULL';
const hasVac = !!w.vacation_type_code;
const vacBadge = isFullVac ? '연차'
: hasVac ? `${esc(w.vacation_type_name)}` : '';
const doneBadge = w.has_report ? `${w.total_report_hours}h` : '미입력';
return `
`;
}).join('');
}
function onWorkerCheck(userId, checked) {
if (checked) selectedIds.add(userId);
else selectedIds.delete(userId);
updateEditButton();
}
function toggleSelectAll(checked) {
allWorkers.forEach(w => {
if (w.vacation_type_code === 'ANNUAL_FULL') return;
const cb = document.querySelector(`.pi-check[value="${w.user_id}"]`);
if (cb) { cb.checked = checked; onWorkerCheck(w.user_id, checked); }
});
}
function updateEditButton() {
const btn = document.getElementById('editBtn');
const n = selectedIds.size;
btn.disabled = n === 0;
document.getElementById('editBtnText').textContent = n > 0 ? `선택 작업자 편집 (${n}명)` : '작업자를 선택하세요';
}
// ===== Step 2: Edit Mode =====
function openEditMode() {
if (selectedIds.size === 0) return;
const selected = allWorkers.filter(w => selectedIds.has(w.user_id));
editData = {};
// 기본값 설정
selected.forEach(w => {
const isHalfVac = w.vacation_type_code === 'ANNUAL_HALF';
const isQuarterVac = w.vacation_type_code === 'ANNUAL_QUARTER';
editData[w.user_id] = {
project_id: '',
work_type_id: '',
work_hours: isHalfVac ? 4 : isQuarterVac ? 6 : 8,
defect_hours: 0,
note: '',
start_time: '08:00',
end_time: isHalfVac ? '12:00' : isQuarterVac ? '14:00' : '17:00',
work_status_id: 1
};
});
document.getElementById('editTitle').textContent = `일괄 편집 (${selected.length}명)`;
const projOpts = projects.map(p => ``).join('');
const typeOpts = workTypes.map(t => ``).join('');
document.getElementById('editList').innerHTML = selected.map(w => {
const d = editData[w.user_id];
const vacLabel = w.vacation_type_name ? ` ${esc(w.vacation_type_name)}` : '';
return `
`;
}).join('');
document.getElementById('step1').classList.add('hidden');
document.getElementById('step2').classList.remove('hidden');
}
function closeEditMode() {
document.getElementById('step2').classList.add('hidden');
document.getElementById('step1').classList.remove('hidden');
}
// ===== Save =====
async function saveAll() {
const btn = document.getElementById('saveBtn');
btn.disabled = true;
document.getElementById('saveBtnText').textContent = '저장 중...';
const entries = [];
let hasError = false;
for (const uid of selectedIds) {
const projEl = document.getElementById('proj_' + uid);
const wtypeEl = document.getElementById('wtype_' + uid);
const hoursEl = document.getElementById('hours_' + uid);
const defectEl = document.getElementById('defect_' + uid);
const noteEl = document.getElementById('note_' + uid);
if (!projEl?.value || !wtypeEl?.value) {
showToast(`프로젝트/공종을 선택하세요`, 'error');
projEl?.focus();
hasError = true;
break;
}
const workHours = parseFloat(hoursEl?.value) || 0;
const defectHours = parseFloat(defectEl?.value) || 0;
if (defectHours > workHours) {
showToast('부적합 시간이 근무시간을 초과합니다', 'error');
hasError = true;
break;
}
entries.push({
user_id: uid,
project_id: parseInt(projEl.value),
work_type_id: parseInt(wtypeEl.value),
work_hours: workHours,
defect_hours: defectHours,
note: noteEl?.value || '',
start_time: '08:00',
end_time: '17:00',
work_status_id: defectHours > 0 ? 2 : 1
});
}
if (hasError) {
btn.disabled = false;
document.getElementById('saveBtnText').textContent = '전체 저장';
return;
}
try {
const res = await window.apiCall('/proxy-input', 'POST', {
session_date: currentDate,
entries
});
if (res.success) {
showToast(res.message || `${entries.length}명 저장 완료`, 'success');
closeEditMode();
selectedIds.clear();
updateEditButton();
await loadWorkers();
} else {
showToast(res.message || '저장 실패', 'error');
}
} catch (e) {
showToast('저장 실패: ' + (e.message || e), 'error');
}
btn.disabled = false;
document.getElementById('saveBtnText').textContent = '전체 저장';
}
function esc(s) { return (s || '').replace(/&/g, '&').replace(//g, '>'); }