Files
tk-factory-services/tksafety/web/static/js/tksafety-education.js
Hyungi Ahn b800792152 feat: 구매/안전 시스템 전면 개편 — tkpurchase 개편 + tksafety 신규 + 권한 보강
Phase 1: tkuser 협력업체 CRUD 이관 (읽기전용 → 전체 CRUD)
Phase 2: tkpurchase 개편 — 일용공 신청/확정, 작업일정, 업무현황, 계정관리, 협력업체 포털
Phase 3: tksafety 신규 시스템 — 방문관리 + 안전교육 신고
Phase 4: SSO 인증 보강 (partner_company_id JWT, 만료일 체크), 권한 테이블 기반 접근 제어

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 17:42:59 +09:00

144 lines
6.9 KiB
JavaScript

/* ===== Education Management ===== */
let educationList = [];
let editingEducationId = null;
async function loadEducation() {
try {
const dateFrom = document.getElementById('eduDateFrom')?.value || '';
const dateTo = document.getElementById('eduDateTo')?.value || '';
const targetType = document.getElementById('eduTargetType')?.value || '';
const params = new URLSearchParams();
if (dateFrom) params.set('date_from', dateFrom);
if (dateTo) params.set('date_to', dateTo);
if (targetType) params.set('target_type', targetType);
const r = await api('/education?' + params.toString());
educationList = r.data || [];
renderEducationList();
} catch (e) {
showToast('교육 목록 로드 실패: ' + e.message, 'error');
}
}
function renderEducationList() {
const tbody = document.getElementById('educationTableBody');
if (!educationList.length) {
tbody.innerHTML = '<tr><td colspan="7" class="text-center text-gray-400 py-8">등록된 안전교육이 없습니다</td></tr>';
return;
}
const typeLabels = { day_labor: '일용공', partner_schedule: '협력업체', manual: '수동등록' };
const statusLabels = { planned: '예정', completed: '완료', cancelled: '취소' };
const statusColors = { planned: 'badge-amber', completed: 'badge-green', cancelled: 'badge-gray' };
tbody.innerHTML = educationList.map(e => {
const attendeeCount = e.attendees ? (typeof e.attendees === 'string' ? JSON.parse(e.attendees) : e.attendees).length : 0;
return `<tr>
<td>${formatDate(e.education_date)}</td>
<td><span class="badge ${e.target_type === 'day_labor' ? 'badge-blue' : e.target_type === 'partner_schedule' ? 'badge-green' : 'badge-gray'}">${typeLabels[e.target_type] || e.target_type}</span></td>
<td>${escapeHtml(e.educator) || '-'}</td>
<td class="text-center">${attendeeCount}명</td>
<td><span class="badge ${statusColors[e.status] || 'badge-gray'}">${statusLabels[e.status] || e.status}</span></td>
<td class="hide-mobile">${escapeHtml(e.notes) || '-'}</td>
<td class="text-right">
<button onclick="openEditEducation(${e.id})" class="text-gray-400 hover:text-gray-600 text-xs" title="수정"><i class="fas fa-pen"></i></button>
<button onclick="doDeleteEducation(${e.id})" class="text-gray-400 hover:text-red-500 text-xs ml-1" title="삭제"><i class="fas fa-trash"></i></button>
</td>
</tr>`;
}).join('');
}
/* ===== Add education modal ===== */
function openAddEducation() {
document.getElementById('addEducationModal').classList.remove('hidden');
}
function closeAddEducation() {
document.getElementById('addEducationModal').classList.add('hidden');
document.getElementById('addEducationForm').reset();
}
async function submitAddEducation(e) {
e.preventDefault();
const attendeesRaw = document.getElementById('newAttendees').value.trim();
const attendees = attendeesRaw ? attendeesRaw.split('\n').map(line => {
const parts = line.split(',').map(s => s.trim());
return { name: parts[0] || '', company: parts[1] || '' };
}).filter(a => a.name) : [];
const data = {
target_type: document.getElementById('newTargetType').value,
education_date: document.getElementById('newEducationDate').value,
educator: document.getElementById('newEducator').value.trim() || null,
attendees: attendees,
status: document.getElementById('newEduStatus').value || 'planned',
notes: document.getElementById('newEduNotes').value.trim() || null,
};
if (!data.education_date) { showToast('교육일은 필수입니다', 'error'); return; }
try {
await api('/education', { method: 'POST', body: JSON.stringify(data) });
showToast('안전교육이 등록되었습니다');
closeAddEducation();
await loadEducation();
} catch (e) { showToast(e.message, 'error'); }
}
/* ===== Edit education ===== */
function openEditEducation(id) {
const edu = educationList.find(x => x.id === id);
if (!edu) return;
editingEducationId = id;
document.getElementById('editTargetType').value = edu.target_type;
document.getElementById('editEducationDate').value = formatDate(edu.education_date);
document.getElementById('editEducator').value = edu.educator || '';
document.getElementById('editEduStatus').value = edu.status;
document.getElementById('editEduNotes').value = edu.notes || '';
const attendees = edu.attendees ? (typeof edu.attendees === 'string' ? JSON.parse(edu.attendees) : edu.attendees) : [];
document.getElementById('editAttendees').value = attendees.map(a => `${a.name}${a.company ? ', ' + a.company : ''}`).join('\n');
document.getElementById('editEducationModal').classList.remove('hidden');
}
function closeEditEducation() {
document.getElementById('editEducationModal').classList.add('hidden');
editingEducationId = null;
}
async function submitEditEducation(e) {
e.preventDefault();
if (!editingEducationId) return;
const attendeesRaw = document.getElementById('editAttendees').value.trim();
const attendees = attendeesRaw ? attendeesRaw.split('\n').map(line => {
const parts = line.split(',').map(s => s.trim());
return { name: parts[0] || '', company: parts[1] || '' };
}).filter(a => a.name) : [];
const data = {
target_type: document.getElementById('editTargetType').value,
education_date: document.getElementById('editEducationDate').value,
educator: document.getElementById('editEducator').value.trim() || null,
attendees: attendees,
status: document.getElementById('editEduStatus').value,
notes: document.getElementById('editEduNotes').value.trim() || null,
};
try {
await api(`/education/${editingEducationId}`, { method: 'PUT', body: JSON.stringify(data) });
showToast('수정되었습니다');
closeEditEducation();
await loadEducation();
} catch (e) { showToast(e.message, 'error'); }
}
async function doDeleteEducation(id) {
if (!confirm('이 교육 기록을 삭제하시겠습니까?')) return;
try {
await api(`/education/${id}`, { method: 'DELETE' });
showToast('삭제되었습니다');
await loadEducation();
} catch (e) { showToast(e.message, 'error'); }
}
function initEducationPage() {
if (!initAuth()) return;
document.getElementById('addEducationForm').addEventListener('submit', submitAddEducation);
document.getElementById('editEducationForm').addEventListener('submit', submitEditEducation);
document.getElementById('eduDateFrom')?.addEventListener('change', loadEducation);
document.getElementById('eduDateTo')?.addEventListener('change', loadEducation);
document.getElementById('eduTargetType')?.addEventListener('change', loadEducation);
loadEducation();
}