/** * Project Master Overseas Inquiries JS * 기능: 문의사항 로드, 필터링, 답변 관리, 아코디언 및 이미지 모달 */ // --- 초기화 --- let allInquiries = []; let currentSort = { field: 'no', direction: 'desc' }; async function loadInquiries() { initStickyHeader(); const pmType = document.getElementById('filterPmType').value; const category = document.getElementById('filterCategory').value; const keyword = document.getElementById('searchKeyword').value; const params = new URLSearchParams({ pm_type: pmType, category: category, keyword: keyword }); try { const response = await fetch(`${API.INQUIRIES}?${params}`); allInquiries = await response.json(); refreshInquiryBoard(); } catch (e) { console.error("데이터 로딩 중 오류 발생:", e); } } function refreshInquiryBoard() { const status = document.getElementById('filterStatus').value; // 1. 상태 필터링 let filteredData = status ? allInquiries.filter(item => item.status === status) : [...allInquiries]; // 2. 정렬 적용 filteredData = sortData(filteredData); // 3. 통계 및 리스트 렌더링 updateStats(allInquiries); updateSortUI(); renderInquiryList(filteredData); } function handleSort(field) { if (currentSort.field === field) { currentSort.direction = currentSort.direction === 'asc' ? 'desc' : 'asc'; } else { currentSort.field = field; currentSort.direction = 'asc'; } refreshInquiryBoard(); } function sortData(data) { const { field, direction } = currentSort; const modifier = direction === 'asc' ? 1 : -1; return data.sort((a, b) => { let valA = a[field]; let valB = b[field]; // 숫자형 변환 시도 (No 필드 등) if (field === 'no' || !isNaN(valA)) { valA = Number(valA); valB = Number(valB); } // null/undefined 처리 if (valA === null || valA === undefined) valA = ""; if (valB === null || valB === undefined) valB = ""; if (valA < valB) return -1 * modifier; if (valA > valB) return 1 * modifier; return 0; }); } function updateSortUI() { // 모든 헤더 클래스 및 아이콘 초기화 document.querySelectorAll('.inquiry-table thead th.sortable').forEach(th => { th.classList.remove('active-sort'); const icon = th.querySelector('.sort-icon'); if (icon) { // 레이아웃 시프트 방지를 위해 투명한 기본 아이콘(또는 공백) 유지 icon.textContent = "▲"; icon.style.opacity = "0"; } }); // 현재 정렬된 헤더 강조 및 아이콘 표시 const activeTh = document.querySelector(`.inquiry-table thead th[onclick*="'${currentSort.field}'"]`); if (activeTh) { activeTh.classList.add('active-sort'); const icon = activeTh.querySelector('.sort-icon'); if (icon) { icon.textContent = currentSort.direction === 'asc' ? "▲" : "▼"; icon.style.opacity = "1"; } } } function initStickyHeader() { const header = document.getElementById('stickyHeader'); const thead = document.querySelector('.inquiry-table thead'); if (header && thead) { const headerHeight = header.offsetHeight; const totalOffset = 36 + headerHeight; document.querySelectorAll('.inquiry-table thead th').forEach(th => { th.style.top = totalOffset + 'px'; }); } } function renderInquiryList(data) { const tbody = document.getElementById('inquiryList'); tbody.innerHTML = data.map(item => ` ${item.no} ${item.image_url ? `thumbnail` : '없음'} ${item.pm_type} ${item.browser || 'Chrome'} ${item.category} ${item.project_nm} ${item.content} ${item.author} ${item.reg_date} ${item.reply || '-'} ${item.status}
작성자: ${item.author}
등록일: ${item.reg_date}
시스템: ${item.pm_type}
환경: ${item.browser || 'Chrome'} / ${item.device || 'PC'}

[질문 내용]

${item.content}
${item.image_url ? `

🖼️ [첨부 이미지] (클릭 시 크게 보기)

` : ''}

[조치 및 답변]

${item.handled_date ? `
최종 수정일: ${item.handled_date}
` : ''}
`).join(''); } function enableEdit(id) { const form = document.getElementById(`reply-form-${id}`); form.classList.replace('readonly', 'editable'); const elements = [`reply-text-${id}`, `reply-status-${id}`, `reply-handler-${id}`]; elements.forEach(elId => document.getElementById(elId).disabled = false); document.getElementById(`reply-text-${id}`).focus(); } async function cancelEdit(id) { try { const response = await fetch(`${API.INQUIRIES}/${id}`); const item = await response.json(); const txt = document.getElementById(`reply-text-${id}`); const status = document.getElementById(`reply-status-${id}`); const handler = document.getElementById(`reply-handler-${id}`); txt.value = item.reply || ''; status.value = item.status; handler.value = item.handler || ''; [txt, status, handler].forEach(el => el.disabled = true); document.getElementById(`reply-form-${id}`).classList.replace('editable', 'readonly'); } catch { loadInquiries(); } } async function saveReply(id) { const reply = document.getElementById(`reply-text-${id}`).value; const status = document.getElementById(`reply-status-${id}`).value; const handler = document.getElementById(`reply-handler-${id}`).value; if (!reply.trim() || !handler.trim()) return alert("내용과 처리자를 모두 입력해 주세요."); try { const response = await fetch(`${API.INQUIRIES}/${id}/reply`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ reply, status, handler }) }); if ((await response.json()).success) { alert("저장되었습니다."); loadInquiries(); } } catch { alert("저장 중 오류가 발생했습니다."); } } async function deleteReply(id) { if (!confirm("답변을 삭제하시겠습니까?")) return; try { const response = await fetch(`${API.INQUIRIES}/${id}/reply`, { method: 'DELETE' }); if ((await response.json()).success) { alert("삭제되었습니다."); loadInquiries(); } } catch { alert("삭제 중 오류가 발생했습니다."); } } function toggleAccordion(id) { const detailRow = document.getElementById(`detail-${id}`); if (!detailRow) return; const inquiryRow = detailRow.previousElementSibling; const isActive = detailRow.classList.contains('active'); document.querySelectorAll('.detail-row.active').forEach(row => { if (row.id !== `detail-${id}`) { row.classList.remove('active'); if (row.previousElementSibling) row.previousElementSibling.classList.remove('active-row'); } }); if (isActive) { detailRow.classList.remove('active'); inquiryRow.classList.remove('active-row'); } else { detailRow.classList.add('active'); inquiryRow.classList.add('active-row'); scrollToRow(inquiryRow); } } function scrollToRow(row) { setTimeout(() => { const headerHeight = document.getElementById('stickyHeader').offsetHeight; const totalOffset = 36 + headerHeight + 40; const offsetPosition = (row.getBoundingClientRect().top + window.pageYOffset) - totalOffset; window.scrollTo({ top: offsetPosition, behavior: 'smooth' }); }, 100); } function updateStats(data) { const counts = { Total: data.length, Complete: data.filter(i => i.status === '완료').length, Working: data.filter(i => i.status === '작업 중').length, Checking: data.filter(i => i.status === '확인 중').length, Pending: data.filter(i => i.status === '개발예정').length, Unconfirmed: data.filter(i => i.status === '미확인').length }; Object.keys(counts).forEach(k => { const el = document.getElementById(`count${k}`); if (el) el.textContent = counts[k].toLocaleString(); }); } function openImageModal(src) { document.getElementById('modalImage').src = src; ModalManager.open('imageModal'); } function toggleImageSection(id) { const section = document.getElementById(`img-section-${id}`); const content = document.getElementById(`img-content-${id}`); const icon = section.querySelector('.toggle-icon'); const isCollapsed = content.classList.toggle('collapsed'); section.classList.toggle('active', !isCollapsed); icon.textContent = isCollapsed ? '▼' : '▲'; } document.addEventListener('DOMContentLoaded', loadInquiries); window.addEventListener('resize', initStickyHeader);