class VNCServerApp { constructor() { this.apiBase = '/api/vncserver'; this.init(); } init() { this.bindEvents(); this.loadServerList(); this.checkVNCStatus(); } bindEvents() { // 서버 추가 버튼 document.getElementById('addServerBtn').addEventListener('click', () => { this.showServerModal(); }); // 모달 취소 버튼 document.getElementById('cancelBtn').addEventListener('click', () => { this.hideServerModal(); }); // 서버 폼 제출 document.getElementById('serverForm').addEventListener('submit', (e) => { e.preventDefault(); this.saveServer(); }); // 확인 모달 이벤트 document.getElementById('confirmCancel').addEventListener('click', () => { this.hideConfirmModal(); }); document.getElementById('confirmOk').addEventListener('click', () => { this.executeConfirmAction(); }); } async loadServerList() { try { const response = await fetch(`${this.apiBase}/list`); if (!response.ok) throw new Error('서버 목록을 불러올 수 없습니다.'); const servers = await response.json(); this.renderServerList(servers); } catch (error) { this.showError('서버 목록을 불러오는 중 오류가 발생했습니다: ' + error.message); } } renderServerList(servers) { const serverList = document.getElementById('serverList'); if (servers.length === 0) { serverList.innerHTML = `

등록된 서버가 없습니다.

새 서버를 추가해보세요.

`; return; } serverList.innerHTML = servers.map(server => `

${this.escapeHtml(server.user)}@${this.escapeHtml(server.ip)}

IP: ${this.escapeHtml(server.ip)}

${server.category ? `

카테고리: ${this.escapeHtml(server.category)}

` : ''} ${server.description ? `

설명: ${this.escapeHtml(server.description)}

` : ''} ${server.argument ? `

인수: ${this.escapeHtml(server.argument)}

` : ''}
`).join(''); } async checkVNCStatus() { try { const response = await fetch(`${this.apiBase}/vnc-status`); if (!response.ok) throw new Error('VNC 상태를 확인할 수 없습니다.'); const status = await response.json(); this.showVNCStatus(status); } catch (error) { this.showError('VNC 상태 확인 중 오류가 발생했습니다: ' + error.message); } } showVNCStatus(status) { const statusDiv = document.getElementById('status'); if (status.isInstalled) { statusDiv.innerHTML = `
VNC Viewer가 설치되어 있습니다.
`; } else { statusDiv.innerHTML = `
VNC Viewer가 설치되어 있지 않습니다. 경로: ${status.path}
`; } } showServerModal(server = null) { const modal = document.getElementById('serverModal'); const title = document.getElementById('modalTitle'); const form = document.getElementById('serverForm'); if (server) { title.textContent = '서버 편집'; document.getElementById('serverUser').value = server.user; document.getElementById('serverIp').value = server.ip; document.getElementById('serverCategory').value = server.category || ''; document.getElementById('serverDescription').value = server.description || ''; document.getElementById('serverPassword').value = server.password || ''; document.getElementById('serverArgument').value = server.argument || ''; } else { title.textContent = '서버 추가'; form.reset(); } modal.classList.remove('hidden'); } hideServerModal() { document.getElementById('serverModal').classList.add('hidden'); } async saveServer() { const serverUser = document.getElementById('serverUser').value; const serverIp = document.getElementById('serverIp').value; const serverData = { user: serverUser, ip: serverIp, category: document.getElementById('serverCategory').value, description: document.getElementById('serverDescription').value, password: document.getElementById('serverPassword').value, argument: document.getElementById('serverArgument').value }; try { const url = serverUser && serverIp ? `${this.apiBase}/update` : `${this.apiBase}/add`; const method = serverUser && serverIp ? 'PUT' : 'POST'; const response = await fetch(url, { method: method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(serverData) }); if (!response.ok) throw new Error('서버 저장에 실패했습니다.'); const result = await response.json(); this.showSuccess(result.message); this.hideServerModal(); this.loadServerList(); } catch (error) { this.showError('서버 저장 중 오류가 발생했습니다: ' + error.message); } } async editServer(user, ip) { try { const response = await fetch(`${this.apiBase}/get/${encodeURIComponent(user)}/${encodeURIComponent(ip)}`); if (!response.ok) throw new Error('서버 정보를 불러올 수 없습니다.'); const server = await response.json(); this.showServerModal(server); } catch (error) { this.showError('서버 정보를 불러오는 중 오류가 발생했습니다: ' + error.message); } } deleteServer(user, ip, name) { this.showConfirmModal( `"${name}" 서버를 삭제하시겠습니까?`, () => this.executeDeleteServer(user, ip) ); } async executeDeleteServer(user, ip) { try { const response = await fetch(`${this.apiBase}/delete/${encodeURIComponent(user)}/${encodeURIComponent(ip)}`, { method: 'DELETE' }); if (!response.ok) throw new Error('서버 삭제에 실패했습니다.'); const result = await response.json(); this.showSuccess(result.message); this.loadServerList(); } catch (error) { this.showError('서버 삭제 중 오류가 발생했습니다: ' + error.message); } } async connectToServer(user, ip) { try { const response = await fetch(`${this.apiBase}/connect/${encodeURIComponent(user)}/${encodeURIComponent(ip)}`, { method: 'POST' }); if (!response.ok) throw new Error('VNC 연결에 실패했습니다.'); const result = await response.json(); this.showSuccess(result.message); } catch (error) { this.showError('VNC 연결 중 오류가 발생했습니다: ' + error.message); } } showConfirmModal(message, onConfirm) { document.getElementById('confirmMessage').textContent = message; document.getElementById('confirmModal').classList.remove('hidden'); this.confirmAction = onConfirm; } hideConfirmModal() { document.getElementById('confirmModal').classList.add('hidden'); this.confirmAction = null; } executeConfirmAction() { if (this.confirmAction) { this.confirmAction(); } this.hideConfirmModal(); } showSuccess(message) { this.showNotification(message, 'success'); } showError(message) { this.showNotification(message, 'error'); } showNotification(message, type) { const notification = document.createElement('div'); notification.className = `fixed top-4 right-4 px-6 py-3 rounded-lg text-white z-50 transition-all duration-300 transform translate-x-full ${ type === 'success' ? 'bg-green-500' : 'bg-red-500' }`; notification.textContent = message; document.body.appendChild(notification); // 애니메이션 setTimeout(() => { notification.classList.remove('translate-x-full'); }, 100); // 자동 제거 setTimeout(() => { notification.classList.add('translate-x-full'); setTimeout(() => { document.body.removeChild(notification); }, 300); }, 3000); } escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } } // 앱 초기화 const app = new VNCServerApp();