144 lines
4.8 KiB
JavaScript
144 lines
4.8 KiB
JavaScript
// /js/report-viewer-ui.js
|
|
|
|
/**
|
|
* 데이터를 가공하여 UI에 표시하기 좋은 요약 형태로 변환합니다.
|
|
* @param {Array} rawData - 서버에서 받은 원시 데이터 배열
|
|
* @param {string} selectedDate - 선택된 날짜
|
|
* @returns {object} - 요약 정보와 작업자별로 그룹화된 데이터를 포함하는 객체
|
|
*/
|
|
export function processReportData(rawData, selectedDate) {
|
|
if (!Array.isArray(rawData) || rawData.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
const workerGroups = {};
|
|
let totalHours = 0;
|
|
let errorCount = 0;
|
|
|
|
rawData.forEach(item => {
|
|
const workerName = item.worker_name || '미지정';
|
|
const workHours = parseFloat(item.work_hours || 0);
|
|
totalHours += workHours;
|
|
if (item.work_status_id === 2) errorCount++; // '에러' 상태 ID가 2라고 가정
|
|
|
|
if (!workerGroups[workerName]) {
|
|
workerGroups[workerName] = {
|
|
worker_name: workerName,
|
|
total_hours: 0,
|
|
entries: []
|
|
};
|
|
}
|
|
workerGroups[workerName].total_hours += workHours;
|
|
workerGroups[workerName].entries.push(item);
|
|
});
|
|
|
|
return {
|
|
summary: {
|
|
date: selectedDate,
|
|
total_workers: Object.keys(workerGroups).length,
|
|
total_hours: totalHours,
|
|
total_entries: rawData.length,
|
|
error_count: errorCount
|
|
},
|
|
workers: Object.values(workerGroups)
|
|
};
|
|
}
|
|
|
|
function displaySummary(summary) {
|
|
const elements = {
|
|
totalWorkers: summary.total_workers,
|
|
totalHours: `${summary.total_hours}시간`,
|
|
totalEntries: `${summary.total_entries}개`,
|
|
errorCount: `${summary.error_count}개`
|
|
};
|
|
Object.entries(elements).forEach(([id, value]) => {
|
|
const el = document.getElementById(id);
|
|
if (el) el.textContent = value;
|
|
});
|
|
document.getElementById('reportSummary').style.display = 'block';
|
|
}
|
|
|
|
function createWorkEntryElement(entry) {
|
|
const entryDiv = document.createElement('div');
|
|
entryDiv.className = `work-entry ${entry.work_status_id === 2 ? 'error-entry' : ''}`;
|
|
entryDiv.innerHTML = `
|
|
<div class="entry-header">
|
|
<div class="project-name">${entry.project_name || '프로젝트 미지정'}</div>
|
|
<div class="work-hours">${entry.work_hours || 0}시간</div>
|
|
</div>
|
|
<div class="entry-details">
|
|
<div class="entry-detail">
|
|
<span class="detail-label">작업 유형:</span>
|
|
<span class="detail-value">${entry.work_type_name || '-'}</span>
|
|
</div>
|
|
${entry.work_status_id === 2 ? `
|
|
<div class="entry-detail">
|
|
<span class="detail-label">에러 유형:</span>
|
|
<span class="detail-value error-type">${entry.error_type_name || '에러'}</span>
|
|
</div>` : ''}
|
|
</div>
|
|
`;
|
|
return entryDiv;
|
|
}
|
|
|
|
function displayWorkersDetails(workers) {
|
|
const workersListEl = document.getElementById('workersList');
|
|
workersListEl.innerHTML = '';
|
|
workers.forEach(worker => {
|
|
const workerCard = document.createElement('div');
|
|
workerCard.className = 'worker-card';
|
|
workerCard.innerHTML = `
|
|
<div class="worker-header">
|
|
<div class="worker-name">👤 ${worker.worker_name}</div>
|
|
<div class="worker-total-hours">총 ${worker.total_hours}시간</div>
|
|
</div>
|
|
`;
|
|
const entriesContainer = document.createElement('div');
|
|
entriesContainer.className = 'work-entries';
|
|
worker.entries.forEach(entry => entriesContainer.appendChild(createWorkEntryElement(entry)));
|
|
workerCard.appendChild(entriesContainer);
|
|
workersListEl.appendChild(workerCard);
|
|
});
|
|
document.getElementById('workersReport').style.display = 'block';
|
|
}
|
|
|
|
const hideElement = (id) => {
|
|
const el = document.getElementById(id);
|
|
if (el) el.style.display = 'none';
|
|
};
|
|
|
|
/**
|
|
* 가공된 데이터를 받아 화면 전체를 렌더링합니다.
|
|
* @param {object|null} processedData - 가공된 데이터 또는 데이터가 없을 경우 null
|
|
*/
|
|
export function renderReport(processedData) {
|
|
hideElement('loadingSpinner');
|
|
hideElement('errorMessage');
|
|
hideElement('noDataMessage');
|
|
hideElement('reportSummary');
|
|
hideElement('workersReport');
|
|
hideElement('exportSection');
|
|
|
|
if (!processedData) {
|
|
document.getElementById('noDataMessage').style.display = 'block';
|
|
return;
|
|
}
|
|
displaySummary(processedData.summary);
|
|
displayWorkersDetails(processedData.workers);
|
|
document.getElementById('exportSection').style.display = 'block';
|
|
}
|
|
|
|
export function showLoading(isLoading) {
|
|
document.getElementById('loadingSpinner').style.display = isLoading ? 'flex' : 'none';
|
|
if(isLoading) {
|
|
hideElement('errorMessage');
|
|
hideElement('noDataMessage');
|
|
}
|
|
}
|
|
|
|
export function showError(message) {
|
|
const errorEl = document.getElementById('errorMessage');
|
|
errorEl.querySelector('.error-text').textContent = message;
|
|
errorEl.style.display = 'block';
|
|
hideElement('loadingSpinner');
|
|
}
|