feat: add monthly history controls for organization view

This commit is contained in:
hyunho
2026-03-30 10:08:00 +09:00
parent 2053791589
commit bbebe24763
4 changed files with 178 additions and 11 deletions

View File

@@ -8,6 +8,7 @@ let emptyStateMessage = '서버에 조직 데이터가 없습니다. 상단의
let photoPreviewObjectUrl = null;
let seatMapLayoutCache = null;
let activeAsOfDate = '';
let isHistoricalSnapshot = false;
const listViewState = {
mode: 'current',
snapshotDate: '',
@@ -165,7 +166,7 @@ async function loadMembers(message) {
if (message) {
emptyStateMessage = message;
}
const payload = await apiFetch('/api/members');
const payload = await apiFetch(withAsOf('/api/members'));
setMembers(payload.items || []);
if (!members.length) {
emptyStateMessage = '서버에 조직 데이터가 없습니다. 상단의 업로드 버튼으로 초기 데이터를 넣어주세요.';
@@ -185,7 +186,7 @@ async function loadSeatMapLayouts(force = false) {
if (!seatMap?.id) {
return null;
}
return await apiFetch(`/api/seat-maps/${seatMap.id}/layout`);
return await apiFetch(withAsOf(`/api/seat-maps/${seatMap.id}/layout`));
} catch {
return null;
}
@@ -643,6 +644,10 @@ function render() {
}
function toggleAdminMode(checked) {
if (checked && isHistoricalSnapshot) {
alert('월말 히스토리 조회 중에는 수정할 수 없습니다. 최신 월로 돌아간 뒤 수정해주세요.');
return;
}
isAdmin = checked;
const button = document.getElementById('admin-mode-btn');
if (isAdmin) {
@@ -670,7 +675,7 @@ function updateFabMenu() {
let html = '<button class="fab-sub shadow-xl" data-label="리스트" onclick="openListViewModal(event)">📋</button>';
html += '<button class="fab-sub shadow-xl" data-label="조직도 인쇄(A3)" onclick="printA3()">🖨️</button>';
html += '<button class="fab-sub shadow-xl" data-label="자리배치도" onclick="openSeatMapView(event)">🪑</button>';
if (isAdmin) {
if (isAdmin && !isHistoricalSnapshot) {
html += '<button class="fab-sub shadow-xl" data-label="조직현황 업로드" onclick="triggerUpload(event)">⬆️</button>';
html += '<button class="fab-sub shadow-xl" data-label="신규 구성원" onclick="openAddModal(event)">👤</button>';
html += '<button class="fab-sub shadow-xl" data-label="신규 팀/그룹/셀" onclick="openUnitAddModal(event)">🏢</button>';
@@ -678,6 +683,19 @@ function updateFabMenu() {
menu.innerHTML = html;
}
async function openHistoryCompareModal(fromDate, toDate) {
openListViewModal();
const fromInput = document.getElementById('list-compare-from');
const toInput = document.getElementById('list-compare-to');
if (fromInput) {
fromInput.value = fromDate || '';
}
if (toInput) {
toInput.value = toDate || '';
}
await loadCompareListView();
}
function openSeatMapView(event) {
event.stopPropagation();
document.getElementById('fab-container').classList.remove('active');
@@ -695,6 +713,25 @@ window.addEventListener('message', (event) => {
activeAsOfDate = String(data.endDate || '').slice(0, 10);
return;
}
if (data.type === 'organization-history-view') {
activeAsOfDate = String(data.asOfDate || '').slice(0, 10);
isHistoricalSnapshot = Boolean(data.historical);
if (isHistoricalSnapshot && isAdmin) {
toggleAdminMode(false);
} else {
updateFabMenu();
render();
}
seatMapLayoutCache = null;
loadMembers().catch(() => { });
return;
}
if (data.type === 'open-history-compare') {
openHistoryCompareModal(String(data.fromDate || ''), String(data.toDate || '')).catch((error) => {
alert(error.message || '변경 비교를 불러오지 못했습니다.');
});
return;
}
if (data.type === 'seatmap-layout-updated') {
handleSeatMapLayoutUpdated();
}