/* ===== Departments CRUD ===== */
let departments = [], departmentsLoaded = false;
const APPROVAL_TYPE_LABELS = { VACATION: '휴가', PURCHASE: '구매', DOCUMENT: '문서' };
async function loadDepartments() {
try {
const r = await api('/departments'); departments = r.data || r;
departmentsLoaded = true;
displayDepartments();
} catch (err) {
document.getElementById('departmentList').innerHTML = `
`;
}
}
let selectedDeptForMembers = null;
function displayDepartments() {
const c = document.getElementById('departmentList');
if (!departments.length) { c.innerHTML = '등록된 부서가 없습니다.
'; return; }
c.innerHTML = departments.map(d => `
`).join('');
}
async function showDeptMembers(deptId) {
selectedDeptForMembers = deptId;
displayDepartments();
const panel = document.getElementById('deptMembersPanel');
const list = document.getElementById('deptMembersList');
panel.classList.remove('hidden');
list.innerHTML = '
';
let deptUsers = users;
if (!deptUsers || !deptUsers.length) {
try {
const r = await api('/users');
deptUsers = r.data || r;
} catch (e) {
list.innerHTML = `${e.message}
`;
return;
}
}
const members = deptUsers.filter(u => u.department_id === deptId);
const dept = departments.find(d => d.department_id === deptId);
const title = panel.querySelector('h3');
if (title) title.innerHTML = ` 소속 인원 — ${dept ? escHtml(dept.department_name) : ''}`;
if (!members.length) {
list.innerHTML = '소속 인원이 없습니다
';
} else {
list.innerHTML = members.map(u => `
${(u.name || u.username).charAt(0)}
${u.name || u.username}
${u.username}
${u.role === 'admin' ? '관리자' : '사용자'}
${u.is_active === 0 || u.is_active === false ? '비활성 ' : '활성 '}
`).join('');
}
loadApprovalAuthorities(deptId);
}
document.getElementById('addDepartmentForm').addEventListener('submit', async e => {
e.preventDefault();
try {
await api('/departments', { method: 'POST', body: JSON.stringify({
department_name: document.getElementById('newDeptName').value.trim(),
description: document.getElementById('newDeptDescription').value.trim() || null,
display_order: parseInt(document.getElementById('newDeptOrder').value) || 0
})});
showToast('부서가 추가되었습니다.'); document.getElementById('addDepartmentForm').reset(); await loadDepartments();
} catch(e) { showToast(e.message, 'error'); }
});
async function editDepartment(id) {
const d = departments.find(x => x.department_id === id); if (!d) return;
document.getElementById('editDeptId').value = d.department_id;
document.getElementById('editDeptName').value = d.department_name;
document.getElementById('editDeptDescription').value = d.description || '';
document.getElementById('editDeptOrder').value = d.display_order || 0;
// Populate leader dropdown
const leaderSel = document.getElementById('editDeptLeader');
leaderSel.innerHTML = '미지정 ';
let deptUsers = users;
if (!deptUsers || !deptUsers.length) {
try { const r = await api('/users'); deptUsers = r.data || r; } catch(e) { /* ignore */ }
}
const activeUsers = (deptUsers || []).filter(u => u.is_active !== 0 && u.is_active !== false);
const byDept = {};
activeUsers.forEach(u => {
const dName = deptLabel(u.department, u.department_id);
if (!byDept[dName]) byDept[dName] = [];
byDept[dName].push(u);
});
const currentDeptName = d.department_name;
const sortedKeys = Object.keys(byDept).sort((a, b) => {
if (a === currentDeptName) return -1;
if (b === currentDeptName) return 1;
return a.localeCompare(b, 'ko');
});
sortedKeys.forEach(dName => {
const grp = document.createElement('optgroup');
grp.label = dName;
byDept[dName].forEach(u => {
const o = document.createElement('option');
o.value = u.user_id;
o.textContent = u.name || u.username;
if (d.leader_user_id && d.leader_user_id === u.user_id) o.selected = true;
grp.appendChild(o);
});
leaderSel.appendChild(grp);
});
document.getElementById('editDepartmentModal').classList.remove('hidden');
}
function closeDepartmentModal() { document.getElementById('editDepartmentModal').classList.add('hidden'); }
document.getElementById('editDepartmentForm').addEventListener('submit', async e => {
e.preventDefault();
try {
const leaderId = document.getElementById('editDeptLeader').value;
await api(`/departments/${document.getElementById('editDeptId').value}`, { method: 'PUT', body: JSON.stringify({
department_name: document.getElementById('editDeptName').value.trim(),
description: document.getElementById('editDeptDescription').value.trim() || null,
display_order: parseInt(document.getElementById('editDeptOrder').value) || 0,
leader_user_id: leaderId ? parseInt(leaderId) : null
})});
showToast('수정되었습니다.'); closeDepartmentModal(); await loadDepartments();
await loadDepartmentsForSelect();
} catch(e) { showToast(e.message, 'error'); }
});
async function deleteDepartment(id, name) {
if (!confirm(`"${name}" 부서를 삭제하시겠습니까? 소속 인원은 부서 미지정으로 변경됩니다.`)) return;
try { await api(`/departments/${id}`, { method: 'DELETE' }); showToast('부서가 삭제되었습니다'); await loadDepartments(); } catch(e) { showToast(e.message, 'error'); }
}
/* ===== Approval Authorities ===== */
async function loadApprovalAuthorities(deptId) {
const section = document.getElementById('deptApprovalSection');
if (!section) return;
try {
const r = await api(`/departments/${deptId}/approval-authorities`);
const data = r.data || r;
section.classList.remove('hidden');
renderApprovalAuthorities(deptId, data);
} catch (e) {
section.classList.add('hidden');
}
}
function renderApprovalAuthorities(deptId, data) {
const list = document.getElementById('deptApprovalList');
if (!data || !data.length) {
list.innerHTML = '등록된 승인권한이 없습니다
';
return;
}
list.innerHTML = `
유형
승인자
순서
${data.map(a => `
${APPROVAL_TYPE_LABELS[a.approval_type] || a.approval_type}
${escHtml(a.approver_name || '')}
${a.approval_order || 1}
`).join('')}
`;
}
function openApprovalModal() {
if (!selectedDeptForMembers) return;
document.getElementById('approvalDeptId').value = selectedDeptForMembers;
document.getElementById('approvalAuthorityForm').reset();
document.getElementById('approvalOrder').value = '1';
// Populate approver dropdown
const sel = document.getElementById('approvalUserId');
sel.innerHTML = '선택 ';
let availUsers = users;
if (availUsers && availUsers.length) {
availUsers.filter(u => u.is_active !== 0 && u.is_active !== false).forEach(u => {
sel.innerHTML += `${escHtml(u.name || u.username)} `;
});
}
document.getElementById('approvalAuthorityModal').classList.remove('hidden');
}
function closeApprovalModal() { document.getElementById('approvalAuthorityModal').classList.add('hidden'); }
document.getElementById('approvalAuthorityForm').addEventListener('submit', async e => {
e.preventDefault();
const deptId = document.getElementById('approvalDeptId').value;
try {
await api(`/departments/${deptId}/approval-authorities`, { method: 'POST', body: JSON.stringify({
approval_type: document.getElementById('approvalType').value,
approver_user_id: parseInt(document.getElementById('approvalUserId').value),
approval_order: parseInt(document.getElementById('approvalOrder').value) || 1
})});
showToast('승인권한이 추가되었습니다.');
closeApprovalModal();
await loadApprovalAuthorities(parseInt(deptId));
} catch (e) { showToast(e.message, 'error'); }
});
async function deleteApprovalAuthority(deptId, authId) {
if (!confirm('이 승인권한을 삭제하시겠습니까?')) return;
try {
await api(`/departments/${deptId}/approval-authorities/${authId}`, { method: 'DELETE' });
showToast('삭제되었습니다.');
await loadApprovalAuthorities(deptId);
} catch (e) { showToast(e.message, 'error'); }
}