264 lines
11 KiB
JavaScript
264 lines
11 KiB
JavaScript
// script.js - 정리된 버전
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// CSRF 토큰
|
|
// ─────────────────────────────────────────────────────────────
|
|
const csrfToken = document.querySelector('input[name="csrf_token"]')?.value || '';
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// 진행바 업데이트
|
|
// ─────────────────────────────────────────────────────────────
|
|
window.updateProgress = function(percent) {
|
|
const bar = document.getElementById('progressBar');
|
|
if (!bar) return;
|
|
const v = Math.max(0, Math.min(100, Number(percent) || 0));
|
|
bar.style.width = v + '%';
|
|
bar.setAttribute('aria-valuenow', v);
|
|
bar.innerHTML = `<span class="fw-semibold small">${v}%</span>`;
|
|
};
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// 줄 수 카운터
|
|
// ─────────────────────────────────────────────────────────────
|
|
function updateLineCount(textareaId, badgeId) {
|
|
const textarea = document.getElementById(textareaId);
|
|
const badge = document.getElementById(badgeId);
|
|
|
|
if (!textarea || !badge) return;
|
|
|
|
const updateCount = () => {
|
|
const text = textarea.value.trim();
|
|
if (text === '') {
|
|
badge.textContent = '0줄';
|
|
return;
|
|
}
|
|
const lines = text.split('\n').filter(line => line.trim().length > 0);
|
|
badge.textContent = `${lines.length}줄`;
|
|
};
|
|
|
|
updateCount();
|
|
textarea.addEventListener('input', updateCount);
|
|
textarea.addEventListener('change', updateCount);
|
|
textarea.addEventListener('keyup', updateCount);
|
|
textarea.addEventListener('paste', () => setTimeout(updateCount, 10));
|
|
}
|
|
|
|
updateLineCount('ips', 'ipLineCount');
|
|
updateLineCount('server_list_content', 'serverLineCount');
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// 스크립트 선택 시 XML 드롭다운 토글
|
|
// ─────────────────────────────────────────────────────────────
|
|
const TARGET_SCRIPT = "02-set_config.py";
|
|
const scriptSelect = document.getElementById('script');
|
|
const xmlGroup = document.getElementById('xmlFileGroup');
|
|
|
|
function toggleXml() {
|
|
if (!scriptSelect || !xmlGroup) return;
|
|
xmlGroup.style.display = (scriptSelect.value === TARGET_SCRIPT) ? 'block' : 'none';
|
|
}
|
|
|
|
if (scriptSelect) {
|
|
toggleXml();
|
|
scriptSelect.addEventListener('change', toggleXml);
|
|
}
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// 파일 보기 모달
|
|
// ─────────────────────────────────────────────────────────────
|
|
const modalEl = document.getElementById('fileViewModal');
|
|
const titleEl = document.getElementById('fileViewModalLabel');
|
|
const contentEl = document.getElementById('fileViewContent');
|
|
|
|
if (modalEl) {
|
|
modalEl.addEventListener('show.bs.modal', async (ev) => {
|
|
const btn = ev.relatedTarget;
|
|
const folder = btn?.getAttribute('data-folder') || '';
|
|
const date = btn?.getAttribute('data-date') || '';
|
|
const filename = btn?.getAttribute('data-filename') || '';
|
|
|
|
titleEl.innerHTML = `<i class="bi bi-file-text me-2"></i>${filename || '파일'}`;
|
|
contentEl.textContent = '불러오는 중...';
|
|
|
|
const params = new URLSearchParams();
|
|
if (folder) params.set('folder', folder);
|
|
if (date) params.set('date', date);
|
|
if (filename) params.set('filename', filename);
|
|
|
|
try {
|
|
const res = await fetch(`/view_file?${params.toString()}`, { cache: 'no-store' });
|
|
if (!res.ok) throw new Error('HTTP ' + res.status);
|
|
|
|
const data = await res.json();
|
|
contentEl.textContent = data?.content ?? '(빈 파일)';
|
|
} catch (e) {
|
|
contentEl.textContent = '파일을 불러오지 못했습니다: ' + (e?.message || e);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// 공통 POST 함수
|
|
// ─────────────────────────────────────────────────────────────
|
|
async function postFormAndHandle(url) {
|
|
const res = await fetch(url, {
|
|
method: 'POST',
|
|
credentials: 'same-origin',
|
|
headers: {
|
|
'X-CSRFToken': csrfToken,
|
|
'Accept': 'application/json, text/html;q=0.9,*/*;q=0.8',
|
|
},
|
|
});
|
|
|
|
const ct = (res.headers.get('content-type') || '').toLowerCase();
|
|
|
|
if (ct.includes('application/json')) {
|
|
const data = await res.json();
|
|
if (data.success === false) {
|
|
throw new Error(data.error || ('HTTP ' + res.status));
|
|
}
|
|
return data;
|
|
}
|
|
|
|
return { success: true, html: true };
|
|
}
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// MAC 파일 이동
|
|
// ─────────────────────────────────────────────────────────────
|
|
const macForm = document.getElementById('macMoveForm');
|
|
if (macForm) {
|
|
macForm.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const btn = macForm.querySelector('button');
|
|
const originalHtml = btn.innerHTML;
|
|
btn.disabled = true;
|
|
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>처리 중...';
|
|
|
|
try {
|
|
await postFormAndHandle(macForm.action);
|
|
location.reload();
|
|
} catch (err) {
|
|
alert('MAC 이동 중 오류: ' + (err?.message || err));
|
|
btn.disabled = false;
|
|
btn.innerHTML = originalHtml;
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// GUID 파일 이동
|
|
// ─────────────────────────────────────────────────────────────
|
|
const guidForm = document.getElementById('guidMoveForm');
|
|
if (guidForm) {
|
|
guidForm.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const btn = guidForm.querySelector('button');
|
|
const originalHtml = btn.innerHTML;
|
|
btn.disabled = true;
|
|
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>처리 중...';
|
|
|
|
try {
|
|
await postFormAndHandle(guidForm.action);
|
|
location.reload();
|
|
} catch (err) {
|
|
alert('GUID 이동 중 오류: ' + (err?.message || err));
|
|
btn.disabled = false;
|
|
btn.innerHTML = originalHtml;
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// IP 폼 제출 및 진행률 폴링
|
|
// ─────────────────────────────────────────────────────────────
|
|
const ipForm = document.getElementById("ipForm");
|
|
if (ipForm) {
|
|
ipForm.addEventListener("submit", async (ev) => {
|
|
ev.preventDefault();
|
|
|
|
const formData = new FormData(ipForm);
|
|
const btn = ipForm.querySelector('button[type="submit"]');
|
|
const originalHtml = btn.innerHTML;
|
|
btn.disabled = true;
|
|
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>처리 중...';
|
|
|
|
try {
|
|
const res = await fetch(ipForm.action, {
|
|
method: "POST",
|
|
body: formData
|
|
});
|
|
|
|
if (!res.ok) throw new Error("HTTP " + res.status);
|
|
|
|
const data = await res.json();
|
|
console.log("[DEBUG] process_ips 응답:", data);
|
|
|
|
if (data.job_id) {
|
|
pollProgress(data.job_id);
|
|
} else {
|
|
window.updateProgress(100);
|
|
setTimeout(() => location.reload(), 1000);
|
|
}
|
|
} catch (err) {
|
|
console.error("처리 중 오류:", err);
|
|
alert("처리 중 오류 발생: " + err.message);
|
|
btn.disabled = false;
|
|
btn.innerHTML = originalHtml;
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// 진행률 폴링 함수
|
|
// ─────────────────────────────────────────────────────────────
|
|
function pollProgress(jobId) {
|
|
const interval = setInterval(async () => {
|
|
try {
|
|
const res = await fetch(`/progress_status/${jobId}`);
|
|
if (!res.ok) {
|
|
clearInterval(interval);
|
|
return;
|
|
}
|
|
|
|
const data = await res.json();
|
|
|
|
if (data.progress !== undefined) {
|
|
window.updateProgress(data.progress);
|
|
}
|
|
|
|
if (data.progress >= 100) {
|
|
clearInterval(interval);
|
|
window.updateProgress(100);
|
|
setTimeout(() => location.reload(), 1500);
|
|
}
|
|
} catch (err) {
|
|
console.error('진행률 확인 중 오류:', err);
|
|
clearInterval(interval);
|
|
}
|
|
}, 500);
|
|
}
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// 알림 자동 닫기 (5초 후)
|
|
// ─────────────────────────────────────────────────────────────
|
|
setTimeout(() => {
|
|
document.querySelectorAll('.alert').forEach(alert => {
|
|
const bsAlert = new bootstrap.Alert(alert);
|
|
bsAlert.close();
|
|
});
|
|
}, 5000);
|
|
|
|
}); |