- API, UI, Controller 로직을 work-report-api.js, work-report-ui.js, work-report-create.js로 분리 - 관심사 분리를 통해 코드의 재사용성 및 유지보수성 향상
141 lines
4.9 KiB
JavaScript
141 lines
4.9 KiB
JavaScript
// /js/work-report-ui.js
|
|
|
|
const DEFAULT_PROJECT_ID = '13'; // 나중에는 API나 설정에서 받아오는 것이 좋음
|
|
const DEFAULT_TASK_ID = '15';
|
|
|
|
/**
|
|
* 주어진 데이터를 바탕으로 <select> 요소의 <option>들을 생성합니다.
|
|
* @param {Array<object>} items - 옵션으로 만들 데이터 배열
|
|
* @param {string} valueField - <option>의 value 속성에 사용할 필드 이름
|
|
* @param {string} textField - <option>의 텍스트에 사용할 필드 이름
|
|
* @returns {string} - 생성된 HTML 옵션 문자열
|
|
*/
|
|
function createOptions(items, valueField, textField) {
|
|
return items.map(item => `<option value="${item[valueField]}">${textField(item)}</option>`).join('');
|
|
}
|
|
|
|
/**
|
|
* 테이블의 모든 행 번호를 다시 매깁니다.
|
|
* @param {HTMLTableSectionElement} tableBody - tbody 요소
|
|
*/
|
|
function updateRowNumbers(tableBody) {
|
|
tableBody.querySelectorAll('tr').forEach((tr, index) => {
|
|
tr.cells[0].textContent = index + 1;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 하나의 작업 보고서 행(tr)을 생성합니다.
|
|
* @param {object} worker - 작업자 정보
|
|
* @param {Array} projects - 전체 프로젝트 목록
|
|
* @param {Array} tasks - 전체 태스크 목록
|
|
* @param {number} index - 행 번호
|
|
* @returns {HTMLTableRowElement} - 생성된 tr 요소
|
|
*/
|
|
function createReportRow(worker, projects, tasks, index) {
|
|
const tr = document.createElement('tr');
|
|
|
|
tr.innerHTML = `
|
|
<td>${index + 1}</td>
|
|
<td>
|
|
<input type="hidden" name="worker_id" value="${worker.worker_id}">
|
|
${worker.worker_name}
|
|
</td>
|
|
<td><select name="project_id">${createOptions(projects, 'project_id', p => p.project_name)}</select></td>
|
|
<td><select name="task_id">${createOptions(tasks, 'task_id', t => `${t.category}:${t.subcategory}`)}</select></td>
|
|
<td>
|
|
<select name="overtime">
|
|
<option value="">없음</option>
|
|
${[1, 2, 3, 4].map(n => `<option>${n}</option>`).join('')}
|
|
</select>
|
|
</td>
|
|
<td>
|
|
<select name="work_type">
|
|
${['근무', '연차', '유급', '반차', '반반차', '조퇴', '휴무'].map(t => `<option>${t}</option>`).join('')}
|
|
</select>
|
|
</td>
|
|
<td><input type="text" name="memo" placeholder="메모"></td>
|
|
<td><button type="button" class="remove-btn">x</button></td>
|
|
`;
|
|
|
|
// 이벤트 리스너 설정
|
|
const workTypeSelect = tr.querySelector('[name="work_type"]');
|
|
const projectSelect = tr.querySelector('[name="project_id"]');
|
|
const taskSelect = tr.querySelector('[name="task_id"]');
|
|
|
|
workTypeSelect.addEventListener('change', () => {
|
|
const isDisabled = ['연차', '휴무', '유급'].includes(workTypeSelect.value);
|
|
projectSelect.disabled = isDisabled;
|
|
taskSelect.disabled = isDisabled;
|
|
if (isDisabled) {
|
|
projectSelect.value = DEFAULT_PROJECT_ID;
|
|
taskSelect.value = DEFAULT_TASK_ID;
|
|
}
|
|
});
|
|
|
|
tr.querySelector('.remove-btn').addEventListener('click', () => {
|
|
tr.remove();
|
|
updateRowNumbers(tr.parentElement);
|
|
});
|
|
|
|
return tr;
|
|
}
|
|
|
|
/**
|
|
* 작업 보고서 테이블을 초기화하고 데이터를 채웁니다.
|
|
* @param {{workers: Array, projects: Array, tasks: Array}} initialData - 초기 데이터
|
|
*/
|
|
export function initializeReportTable(initialData) {
|
|
const tableBody = document.getElementById('reportBody');
|
|
if (!tableBody) return;
|
|
|
|
tableBody.innerHTML = ''; // 기존 내용 초기화
|
|
const { workers, projects, tasks } = initialData;
|
|
|
|
if (!workers || workers.length === 0) {
|
|
tableBody.innerHTML = '<tr><td colspan="8" class="text-center">등록할 작업자 정보가 없습니다.</td></tr>';
|
|
return;
|
|
}
|
|
|
|
workers.forEach((worker, index) => {
|
|
const row = createReportRow(worker, projects, tasks, index);
|
|
tableBody.appendChild(row);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 테이블에서 폼 데이터를 추출하여 배열로 반환합니다.
|
|
* @returns {Array<object>|null} - 추출된 데이터 배열 또는 유효성 검사 실패 시 null
|
|
*/
|
|
export function getReportData() {
|
|
const tableBody = document.getElementById('reportBody');
|
|
const rows = tableBody.querySelectorAll('tr');
|
|
|
|
if (rows.length === 0 || (rows.length === 1 && rows[0].cells.length < 2)) {
|
|
alert('등록할 내용이 없습니다.');
|
|
return null;
|
|
}
|
|
|
|
const reportData = [];
|
|
const workerIds = new Set();
|
|
|
|
for (const tr of rows) {
|
|
const workerId = tr.querySelector('[name="worker_id"]').value;
|
|
if (workerIds.has(workerId)) {
|
|
alert(`오류: 작업자 '${tr.cells[1].textContent.trim()}'가 중복 등록되었습니다.`);
|
|
return null;
|
|
}
|
|
workerIds.add(workerId);
|
|
|
|
reportData.push({
|
|
worker_id: workerId,
|
|
project_id: tr.querySelector('[name="project_id"]').value,
|
|
task_id: tr.querySelector('[name="task_id"]').value,
|
|
overtime_hours: tr.querySelector('[name="overtime"]').value || 0,
|
|
work_details: tr.querySelector('[name="work_type"]').value,
|
|
memo: tr.querySelector('[name="memo"]').value
|
|
});
|
|
}
|
|
|
|
return reportData;
|
|
}
|