Spaces:
Sleeping
Sleeping
/** | |
* RAG ๊ฒ์ ์ฑ๋ด ์ฅ์น ์ ์ด JavaScript (ํฌํธ ์ค์บ ๊ธฐ๋ฅ ์ถ๊ฐ๋จ) | |
*/ | |
// ์ฅ์น ์ ์ด ๋ชจ๋ | |
const DeviceControl = { | |
// ์ฅ์น ์ ์ด ์ํ | |
isConnected: false, | |
isStatusChecked: false, | |
isLoadingPrograms: false, | |
programsList: [], | |
// DOM ์์๋ค | |
elements: { | |
// ํญ ๋ฐ ์น์ | |
deviceTab: null, | |
deviceSection: null, | |
// ์ฐ๊ฒฐ ๊ด๋ จ | |
deviceServerUrlInput: null, | |
connectDeviceServerBtn: null, | |
deviceConnectionStatus: null, | |
// ๊ธฐ๋ณธ ๊ธฐ๋ฅ | |
deviceBasicFunctions: null, | |
checkDeviceStatusBtn: null, | |
deviceStatusResult: null, | |
// ํ๋ก๊ทธ๋จ ์คํ (๋ฏธ๋ฆฌ ์ ์๋) | |
deviceProgramControl: null, | |
getProgramsBtn: null, | |
programsList: null, | |
programSelectDropdown: null, | |
executeProgramBtn: null, | |
executeResult: null, | |
// ์ฌ์ฉ์ ์ ์ ํ๋ก๊ทธ๋จ ์คํ | |
deviceCustomControl: null, | |
customCommandInput: null, | |
executeCustomBtn: null, | |
customExecuteResult: null, | |
// ================== ํฌํธ ์ค์บ ์์ ์ถ๊ฐ ================== | |
devicePortScanControl: null, // ํฌํธ ์ค์บ ์น์ ์ปจํ ์ด๋ | |
scanPortsBtn: null, // ํฌํธ ์ค์บ ๋ฒํผ | |
portsStatus: null, // ํฌํธ ์ค์บ ์ํ ํ์ ์์ญ | |
portsResults: null // ํฌํธ ์ค์บ ๊ฒฐ๊ณผ ํ์ ์์ญ | |
// ================== ์ถ๊ฐ ๋ ============================ | |
}, | |
// ๋ชจ๋ ์ด๊ธฐํ | |
init: function() { | |
console.log('์ฅ์น ์ ์ด ๋ชจ๋ ์ด๊ธฐํ ์ค...'); | |
this.initElements(); | |
this.initEventListeners(); | |
console.log('์ฅ์น ์ ์ด ๋ชจ๋ ์ด๊ธฐํ ์๋ฃ'); | |
}, | |
// DOM ์์ ์ฐธ์กฐ ์ด๊ธฐํ | |
initElements: function() { | |
// ํญ ๋ฐ ์น์ | |
this.elements.deviceTab = document.getElementById('deviceTab'); | |
this.elements.deviceSection = document.getElementById('deviceSection'); | |
// ์ฐ๊ฒฐ ๊ด๋ จ | |
this.elements.deviceServerUrlInput = document.getElementById('deviceServerUrlInput'); | |
this.elements.connectDeviceServerBtn = document.getElementById('connectDeviceServerBtn'); | |
this.elements.deviceConnectionStatus = document.getElementById('deviceConnectionStatus'); | |
// ๊ธฐ๋ณธ ๊ธฐ๋ฅ | |
this.elements.deviceBasicFunctions = document.getElementById('deviceBasicFunctions'); | |
this.elements.checkDeviceStatusBtn = document.getElementById('checkDeviceStatusBtn'); | |
this.elements.deviceStatusResult = document.getElementById('deviceStatusResult'); | |
// ํ๋ก๊ทธ๋จ ์คํ (๋ฏธ๋ฆฌ ์ ์๋) | |
this.elements.deviceProgramControl = document.getElementById('deviceProgramControl'); | |
this.elements.getProgramsBtn = document.getElementById('getProgramsBtn'); | |
this.elements.programsList = document.getElementById('programsList'); | |
this.elements.programSelectDropdown = document.getElementById('programSelectDropdown'); | |
this.elements.executeProgramBtn = document.getElementById('executeProgramBtn'); | |
this.elements.executeResult = document.getElementById('executeResult'); | |
// ์ฌ์ฉ์ ์ ์ ํ๋ก๊ทธ๋จ ์คํ | |
this.elements.deviceCustomControl = document.getElementById('deviceCustomControl'); | |
this.elements.customCommandInput = document.getElementById('customCommandInput'); | |
this.elements.executeCustomBtn = document.getElementById('executeCustomBtn'); | |
this.elements.customExecuteResult = document.getElementById('customExecuteResult'); | |
// ================== ํฌํธ ์ค์บ ์์ ์ด๊ธฐํ ์ถ๊ฐ ================== | |
this.elements.devicePortScanControl = document.getElementById('devicePortScanControl'); | |
this.elements.scanPortsBtn = document.getElementById('scanPortsBtn'); | |
this.elements.portsStatus = document.getElementById('portsStatus'); | |
this.elements.portsResults = document.getElementById('portsResults'); | |
// ================== ์ถ๊ฐ ๋ ================================= | |
console.log('์ฅ์น ์ ์ด DOM ์์ ์ฐธ์กฐ ์ด๊ธฐํ ์๋ฃ'); | |
}, | |
// ์ด๋ฒคํธ ๋ฆฌ์ค๋ ๋ฑ๋ก | |
initEventListeners: function() { | |
// ํญ ์ ํ | |
if (this.elements.deviceTab) { | |
this.elements.deviceTab.addEventListener('click', () => { | |
console.log('์ฅ์น ์ ์ด ํญ ํด๋ฆญ'); | |
this.switchToDeviceTab(); | |
}); | |
} | |
// ์๋ฒ ์ฐ๊ฒฐ | |
if (this.elements.connectDeviceServerBtn) { | |
this.elements.connectDeviceServerBtn.addEventListener('click', () => { | |
console.log('์ฅ์น ์๋ฒ ์ฐ๊ฒฐ ๋ฒํผ ํด๋ฆญ'); | |
this.connectServer(); | |
}); | |
} | |
// ์ํฐ ํค๋ก ์ฐ๊ฒฐ | |
if (this.elements.deviceServerUrlInput) { | |
this.elements.deviceServerUrlInput.addEventListener('keydown', (event) => { | |
if (event.key === 'Enter') { | |
console.log('์ฅ์น ์๋ฒ URL ์ ๋ ฅ ํ๋์์ ์ํฐ ํค ๊ฐ์ง'); | |
event.preventDefault(); | |
this.connectServer(); | |
} | |
}); | |
} | |
// ์ฅ์น ์ํ ํ์ธ | |
if (this.elements.checkDeviceStatusBtn) { | |
this.elements.checkDeviceStatusBtn.addEventListener('click', () => { | |
console.log('์ฅ์น ์ํ ํ์ธ ๋ฒํผ ํด๋ฆญ'); | |
this.checkDeviceStatus(); | |
}); | |
} | |
// ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ์กฐํ | |
if (this.elements.getProgramsBtn) { | |
this.elements.getProgramsBtn.addEventListener('click', () => { | |
console.log('ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ์๋ก๊ณ ์นจ ๋ฒํผ ํด๋ฆญ'); | |
this.loadProgramsList(); | |
}); | |
} | |
// ํ๋ก๊ทธ๋จ ์ ํ ๋ณ๊ฒฝ | |
if (this.elements.programSelectDropdown) { | |
this.elements.programSelectDropdown.addEventListener('change', (event) => { | |
console.log(`ํ๋ก๊ทธ๋จ ์ ํ ๋ณ๊ฒฝ: ${event.target.value}`); | |
this.updateExecuteButton(); | |
}); | |
} | |
// ํ๋ก๊ทธ๋จ ์คํ (๋ฏธ๋ฆฌ ์ ์๋) | |
if (this.elements.executeProgramBtn) { | |
this.elements.executeProgramBtn.addEventListener('click', () => { | |
const programId = this.elements.programSelectDropdown.value; | |
console.log(`๋ฏธ๋ฆฌ ์ ์๋ ํ๋ก๊ทธ๋จ ์คํ ๋ฒํผ ํด๋ฆญ, ์ ํ๋ ID: ${programId}`); | |
this.executeProgram(programId); | |
}); | |
} | |
// ์ฌ์ฉ์ ์ ์ ํ๋ก๊ทธ๋จ ์คํ ๋ฒํผ ํด๋ฆญ | |
if (this.elements.executeCustomBtn) { | |
this.elements.executeCustomBtn.addEventListener('click', () => { | |
const command = this.elements.customCommandInput.value; | |
console.log(`์ฌ์ฉ์ ์ ์ ํ๋ก๊ทธ๋จ ์คํ ๋ฒํผ ํด๋ฆญ, ๋ช ๋ น์ด: ${command}`); | |
this.executeCustomProgram(command); | |
}); | |
} | |
// ์ํฐ ํค๋ก ์ฌ์ฉ์ ์ ์ ํ๋ก๊ทธ๋จ ์คํ | |
if (this.elements.customCommandInput) { | |
this.elements.customCommandInput.addEventListener('keydown', (event) => { | |
if (event.key === 'Enter') { | |
console.log('์ฌ์ฉ์ ์ ์ ๋ช ๋ น์ด ์ ๋ ฅ ํ๋์์ ์ํฐ ํค ๊ฐ์ง'); | |
event.preventDefault(); // ํผ ์ ์ถ ๋ฐฉ์ง ๋ฑ ๊ธฐ๋ณธ ๋์ ๋ง๊ธฐ | |
const command = this.elements.customCommandInput.value; | |
this.executeCustomProgram(command); | |
} | |
}); | |
} | |
// ================== ํฌํธ ์ค์บ ์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ถ๊ฐ ================== | |
if (this.elements.scanPortsBtn) { | |
this.elements.scanPortsBtn.addEventListener('click', () => { | |
console.log('์ฅ์น ํฌํธ ์ค์บ ๋ฒํผ ํด๋ฆญ'); | |
this.scanDevicePorts(); | |
}); | |
} | |
// ================== ์ถ๊ฐ ๋ ================================== | |
console.log('์ฅ์น ์ ์ด ์ด๋ฒคํธ ๋ฆฌ์ค๋ ๋ฑ๋ก ์๋ฃ'); | |
}, | |
// ์ฅ์น ์ ์ด ํญ์ผ๋ก ์ ํ | |
switchToDeviceTab: function() { | |
// ๋ชจ๋ ํญ๊ณผ ํญ ์ฝํ ์ธ ๋นํ์ฑํ | |
const tabs = document.querySelectorAll('.tab'); | |
const tabContents = document.querySelectorAll('.tab-content'); | |
tabs.forEach(tab => tab.classList.remove('active')); | |
tabContents.forEach(content => content.classList.remove('active')); | |
// ์ฅ์น ์ ์ด ํญ ํ์ฑํ | |
if(this.elements.deviceTab) this.elements.deviceTab.classList.add('active'); | |
if(this.elements.deviceSection) this.elements.deviceSection.classList.add('active'); | |
console.log('์ฅ์น ์ ์ด ํญ์ผ๋ก ์ ํ ์๋ฃ'); | |
}, | |
// ์๋ฒ ์ฐ๊ฒฐ ํจ์ | |
connectServer: async function() { | |
// URL ๊ฐ์ ธ์ค๊ธฐ (์ ๋ ฅ๋ ๊ฒ์ด ์์ผ๋ฉด ๋ฐฑ์ ์ผ๋ก ์ฌ์ฉ) | |
const inputUrl = this.elements.deviceServerUrlInput.value.trim(); | |
// ์ฐ๊ฒฐ ์๋ ์ค UI ์ ๋ฐ์ดํธ | |
if(this.elements.connectDeviceServerBtn) this.elements.connectDeviceServerBtn.disabled = true; | |
this.updateConnectionStatus('connecting', 'ํ๊ฒฝ๋ณ์์ ์ ์ฅ๋ ์๋ฒ๋ก ์ฐ๊ฒฐ ์๋ ์ค...'); | |
try { | |
console.log('ํ๊ฒฝ๋ณ์์ ์ ์ฅ๋ ์ฅ์น ์๋ฒ๋ก ์ฐ๊ฒฐ ์๋'); | |
// ๋ฐฑ์๋ API ํธ์ถํ์ฌ ์๋ฒ ์ํ ํ์ธ | |
const response = await AppUtils.fetchWithTimeout('/api/device/status', { | |
method: 'GET' | |
}, 10000); // 10์ด ํ์์์ | |
const data = await response.json(); | |
if (response.ok && data.success) { | |
// ํ๊ฒฝ๋ณ์ URL ์ฐ๊ฒฐ ์ฑ๊ณต | |
console.log('ํ๊ฒฝ๋ณ์ ์ค์ ์ฅ์น ์๋ฒ ์ฐ๊ฒฐ ์ฑ๊ณต:', data); | |
this.isConnected = true; | |
// ์๋ฒ ์๋ต์์ ์ํ ๋ฉ์์ง๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ๊ธฐ๋ณธ๊ฐ ์ฌ์ฉ | |
const serverStatusMsg = data?.data?.status || data?.server_status || '์ ์'; | |
this.updateConnectionStatus('connected', `์๋ฒ ์ฐ๊ฒฐ ์ฑ๊ณต! ์ํ: ${serverStatusMsg}`); | |
// ๊ธฐ๋ฅ UI ํ์ฑํ | |
if(this.elements.deviceBasicFunctions) this.elements.deviceBasicFunctions.classList.add('active'); | |
if(this.elements.deviceProgramControl) this.elements.deviceProgramControl.classList.add('active'); | |
if(this.elements.deviceCustomControl) this.elements.deviceCustomControl.classList.add('active'); | |
// ================== ํฌํธ ์ค์บ UI ํ์ฑํ ์ถ๊ฐ ================== | |
if(this.elements.devicePortScanControl) this.elements.devicePortScanControl.classList.add('active'); | |
// ================== ์ถ๊ฐ ๋ ================================== | |
// ์ฅ์น ์ํ ์๋ ์ฒดํฌ | |
this.checkDeviceStatus(); | |
// ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ์๋ ๋ก๋ | |
this.loadProgramsList(); | |
// ์์คํ ์๋ฆผ | |
AppUtils.addSystemNotification(`์ฅ์น ๊ด๋ฆฌ ์๋ฒ ์ฐ๊ฒฐ ์ฑ๊ณต! (ํ๊ฒฝ๋ณ์ URL)`); | |
} else { | |
// ํ๊ฒฝ๋ณ์ URL ์ฐ๊ฒฐ ์คํจ, ์ ๋ ฅ๋ URL๋ก ์๋ | |
console.warn('ํ๊ฒฝ๋ณ์ ์ค์ ์ฅ์น ์๋ฒ ์ฐ๊ฒฐ ์คํจ, ์ ๋ ฅ URL๋ก ์ฌ์๋ํฉ๋๋ค:', data); | |
if (!inputUrl) { | |
console.error('์ ๋ ฅ๋ URL์ด ์์ด ์ฐ๊ฒฐ ์คํจ'); | |
this.isConnected = false; | |
this.updateConnectionStatus('error', 'ํ๊ฒฝ๋ณ์ URL ์ฐ๊ฒฐ ์คํจ ๋ฐ ์ ๋ ฅ๋ URL์ด ์์ต๋๋ค. URL์ ์ ๋ ฅํด์ฃผ์ธ์.'); | |
return; // ์ ๋ ฅ URL ์์ผ๋ฉด ์ฌ๊ธฐ์ ์ข ๋ฃ | |
} | |
// ์ ๋ ฅ URL๋ก ์ฌ์๋ | |
await this.connectWithCustomUrl(inputUrl); | |
} | |
} catch (error) { | |
// ํ๊ฒฝ๋ณ์ URL ์ฐ๊ฒฐ ์๋ ์ค ์์ธ ๋ฐ์ | |
console.error('ํ๊ฒฝ๋ณ์ URL ์๋ฒ ์ฐ๊ฒฐ ์ค ์ค๋ฅ ๋ฐ์:', error); | |
this.isConnected = false; | |
if (inputUrl) { | |
console.warn('ํ๊ฒฝ๋ณ์ URL ์ฐ๊ฒฐ ์ ์ค๋ฅ ๋ฐ์, ์ ๋ ฅ URL๋ก ์ฌ์๋ํฉ๋๋ค'); | |
await this.connectWithCustomUrl(inputUrl); // ์ ๋ ฅ URL ์ฌ์๋ | |
} else { | |
// ์ ๋ ฅ URL๋ ์๋ ๊ฒฝ์ฐ ์ต์ข ์ค๋ฅ ์ฒ๋ฆฌ | |
if (error.message.includes('์๊ฐ์ด ์ด๊ณผ')) { | |
this.updateConnectionStatus('error', 'ํ๊ฒฝ๋ณ์ URL ์ฐ๊ฒฐ ์๊ฐ ์ด๊ณผ. URL์ ์ ๋ ฅํ์ฌ ๋ค์ ์๋ํด์ฃผ์ธ์.'); | |
} else { | |
this.updateConnectionStatus('error', `ํ๊ฒฝ๋ณ์ URL ์ฐ๊ฒฐ ์ค๋ฅ. URL์ ์ ๋ ฅํ์ฌ ๋ค์ ์๋ํด์ฃผ์ธ์: ${error.message}`); | |
} | |
} | |
} finally { | |
// ๋ฒํผ ๋ค์ ํ์ฑํ | |
if(this.elements.connectDeviceServerBtn) this.elements.connectDeviceServerBtn.disabled = false; | |
} | |
}, | |
// ์ฌ์ฉ์ ์ ๋ ฅ URL๋ก ์ฐ๊ฒฐ ์๋ (connectServer ๋ด๋ถ ๋ก์ง ๋ถ๋ฆฌ) | |
connectWithCustomUrl: async function(url) { | |
this.updateConnectionStatus('connecting', `์ ๋ ฅ URL(${url})๋ก ์ฐ๊ฒฐ ์๋ ์ค...`); | |
console.log(`์ ๋ ฅํ URL๋ก ์ฅ์น ์๋ฒ ์ฐ๊ฒฐ ์๋: ${url}`); | |
try { | |
// ๋ฐฑ์๋ API ํธ์ถ - Flask ๋ฐฑ์๋๊ฐ URL ๋ฐ์์ ์ฒ๋ฆฌ | |
const customUrlResponse = await AppUtils.fetchWithTimeout('/api/device/connect', { | |
method: 'POST', | |
headers: { 'Content-Type': 'application/json' }, | |
body: JSON.stringify({ url: url }) | |
}, 10000); | |
const customUrlData = await customUrlResponse.json(); | |
if (customUrlResponse.ok && customUrlData.success) { | |
// ์ ๋ ฅ URL ์ฐ๊ฒฐ ์ฑ๊ณต | |
console.log('์ ๋ ฅ URL ์ฅ์น ์๋ฒ ์ฐ๊ฒฐ ์ฑ๊ณต:', customUrlData); | |
this.isConnected = true; | |
this.updateConnectionStatus('connected', `์๋ฒ ์ฐ๊ฒฐ ์ฑ๊ณต! ์ํ: ${customUrlData.server_status || '์ ์'}`); | |
// ๊ธฐ๋ฅ UI ํ์ฑํ | |
if(this.elements.deviceBasicFunctions) this.elements.deviceBasicFunctions.classList.add('active'); | |
if(this.elements.deviceProgramControl) this.elements.deviceProgramControl.classList.add('active'); | |
if(this.elements.deviceCustomControl) this.elements.deviceCustomControl.classList.add('active'); | |
// ================== ํฌํธ ์ค์บ UI ํ์ฑํ ์ถ๊ฐ ================== | |
if(this.elements.devicePortScanControl) this.elements.devicePortScanControl.classList.add('active'); | |
// ================== ์ถ๊ฐ ๋ ================================== | |
// ์ฅ์น ์ํ ์๋ ์ฒดํฌ | |
this.checkDeviceStatus(); | |
// ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ์๋ ๋ก๋ | |
this.loadProgramsList(); | |
// ์์คํ ์๋ฆผ | |
AppUtils.addSystemNotification(`์ฅ์น ๊ด๋ฆฌ ์๋ฒ ์ฐ๊ฒฐ ์ฑ๊ณต! (${url})`); | |
} else { | |
// ์ ๋ ฅ URL ์ฐ๊ฒฐ ์คํจ | |
console.error('์ ๋ ฅ URL ์ฅ์น ์๋ฒ ์ฐ๊ฒฐ ์คํจ:', customUrlData); | |
this.isConnected = false; | |
this.updateConnectionStatus('error', `์๋ฒ ์ฐ๊ฒฐ ์คํจ: ${customUrlData.error || '์๋ฒ ์๋ต ์ค๋ฅ'}`); | |
} | |
} catch(error) { | |
// ์ ๋ ฅ URL๋ก ์๋ ์ค ์ค๋ฅ | |
console.error('์ ๋ ฅ URL๋ก ์ฌ์๋ ์ค ์ค๋ฅ ๋ฐ์:', error); | |
this.isConnected = false; | |
if (error.message.includes('์๊ฐ์ด ์ด๊ณผ')) { | |
this.updateConnectionStatus('error', '์๋ฒ ์ฐ๊ฒฐ ์๊ฐ ์ด๊ณผ. ์๋ฒ๊ฐ ์คํ ์ค์ธ์ง ํ์ธํด์ฃผ์ธ์.'); | |
} else { | |
this.updateConnectionStatus('error', `์๋ฒ ์ฐ๊ฒฐ ์ค๋ฅ: ${error.message}`); | |
} | |
} | |
}, | |
// ์ฐ๊ฒฐ ์ํ ์ ๋ฐ์ดํธ | |
updateConnectionStatus: function(status, message) { | |
const statusElement = this.elements.deviceConnectionStatus; | |
if (!statusElement) return; // ์์ ์์ผ๋ฉด ์ข ๋ฃ | |
// ๋ชจ๋ ์ํ ํด๋์ค ์ ๊ฑฐ | |
statusElement.classList.remove('connected', 'disconnected', 'error', 'connecting'); | |
// ์ํ์ ๋ฐ๋ผ ํด๋์ค ์ถ๊ฐ | |
statusElement.classList.add(status); | |
// ๋ฉ์์ง ์ ๋ฐ์ดํธ | |
statusElement.textContent = message; | |
console.log(`์ฐ๊ฒฐ ์ํ ์ ๋ฐ์ดํธ: ${status} - ${message}`); | |
}, | |
// ์ฅ์น ์ํ ํ์ธ | |
checkDeviceStatus: async function() { | |
if (!this.isConnected) { | |
if(this.elements.deviceStatusResult) this.elements.deviceStatusResult.value = '์ค๋ฅ: ๋จผ์ ์๋ฒ์ ์ฐ๊ฒฐํด์ผ ํฉ๋๋ค.'; | |
console.error('์ฅ์น ์ํ ํ์ธ ์๋ ์ค ์ค๋ฅ: ์๋ฒ ์ฐ๊ฒฐ ์๋จ'); | |
return; | |
} | |
// ์ํ ํ์ธ ์ค UI ์ ๋ฐ์ดํธ | |
if(this.elements.checkDeviceStatusBtn) this.elements.checkDeviceStatusBtn.disabled = true; | |
if(this.elements.deviceStatusResult) this.elements.deviceStatusResult.value = '์ฅ์น ์ํ ํ์ธ ์ค...'; | |
try { | |
console.log('์ฅ์น ์ํ ํ์ธ ์์ฒญ ์ ์ก'); | |
// ๋ฐฑ์๋ API ํธ์ถ | |
const response = await AppUtils.fetchWithTimeout('/api/device/status', { method: 'GET' }); | |
const data = await response.json(); | |
if (response.ok && data.success) { | |
console.log('์ฅ์น ์ํ ํ์ธ ์ฑ๊ณต:', data); | |
this.isStatusChecked = true; | |
// JSON ๋ฐ์ดํฐ๋ฅผ ๋ณด๊ธฐ ์ข๊ฒ ํฌ๋งทํ ํ์ฌ ํ์ | |
if(this.elements.deviceStatusResult) this.elements.deviceStatusResult.value = JSON.stringify(data.data || data, null, 2); // data.data ์ฐ์ ํ์ธ | |
} else { | |
console.error('์ฅ์น ์ํ ํ์ธ ์คํจ:', data); | |
if(this.elements.deviceStatusResult) this.elements.deviceStatusResult.value = `์ํ ํ์ธ ์คํจ: ${data.error || '์ ์ ์๋ ์ค๋ฅ'}`; | |
} | |
} catch (error) { | |
console.error('์ฅ์น ์ํ ํ์ธ ์ค ์ค๋ฅ ๋ฐ์:', error); | |
if(this.elements.deviceStatusResult) this.elements.deviceStatusResult.value = `์ํ ํ์ธ ์ค ์ค๋ฅ ๋ฐ์: ${error.message}`; | |
} finally { | |
if(this.elements.checkDeviceStatusBtn) this.elements.checkDeviceStatusBtn.disabled = false; | |
} | |
}, | |
// ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ์กฐํ | |
loadProgramsList: async function() { | |
if (!this.isConnected) { | |
this.showProgramsError('์ค๋ฅ: ๋จผ์ ์๋ฒ์ ์ฐ๊ฒฐํด์ผ ํฉ๋๋ค.'); | |
console.error('ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ์กฐํ ์๋ ์ค ์ค๋ฅ: ์๋ฒ ์ฐ๊ฒฐ ์๋จ'); | |
return; | |
} | |
if (this.isLoadingPrograms) { | |
console.log('์ด๋ฏธ ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ๋ก๋ฉ ์ค'); | |
return; | |
} | |
// ๋ก๋ฉ ์ค UI ์ ๋ฐ์ดํธ | |
this.isLoadingPrograms = true; | |
if(this.elements.getProgramsBtn) this.elements.getProgramsBtn.disabled = true; | |
if(this.elements.programsList) { | |
this.elements.programsList.innerHTML = `<div class="loading-message">${AppUtils.createLoadingSpinner()} ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ๋ก๋ ์ค...</div>`; | |
} | |
try { | |
console.log('ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ์กฐํ ์์ฒญ ์ ์ก'); | |
// ๋ฐฑ์๋ API ํธ์ถ | |
const response = await AppUtils.fetchWithTimeout('/api/device/programs', { method: 'GET' }); | |
const data = await response.json(); | |
if (response.ok && data.success) { | |
console.log('ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ์กฐํ ์ฑ๊ณต:', data); | |
this.programsList = data.programs || []; | |
this.displayProgramsList(); | |
this.updateProgramsDropdown(); | |
this.updateExecuteButton(); | |
} else { | |
console.error('ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ์กฐํ ์คํจ:', data); | |
this.showProgramsError(`ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ์กฐํ ์คํจ: ${data.error || '์ ์ ์๋ ์ค๋ฅ'}`); | |
} | |
} catch (error) { | |
console.error('ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ์กฐํ ์ค ์ค๋ฅ ๋ฐ์:', error); | |
this.showProgramsError(`ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ์กฐํ ์ค ์ค๋ฅ ๋ฐ์: ${error.message}`); | |
} finally { | |
this.isLoadingPrograms = false; | |
if(this.elements.getProgramsBtn) this.elements.getProgramsBtn.disabled = false; | |
} | |
}, | |
// ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ํ์ | |
displayProgramsList: function() { | |
const programsListElement = this.elements.programsList; | |
if (!programsListElement) return; | |
if (!this.programsList || this.programsList.length === 0) { | |
programsListElement.innerHTML = `<div class="no-programs-message"><i class="fas fa-info-circle"></i> ๋ฑ๋ก๋ ํ๋ก๊ทธ๋จ์ด ์์ต๋๋ค.</div>`; | |
return; | |
} | |
// ํ ์ด๋ธ ํํ๋ก ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ํ์ | |
let html = `<table class="program-list"><thead><tr><th>์ด๋ฆ</th><th>์ค๋ช </th><th>๊ฒฝ๋ก</th></tr></thead><tbody>`; | |
this.programsList.forEach(program => { | |
html += `<tr> | |
<td>${AppUtils.escapeHtml(program.name || '์ ์ ์์')}</td> | |
<td>${AppUtils.escapeHtml(program.description || '-')}</td> | |
<td>${AppUtils.escapeHtml(program.path || '-')}</td> | |
</tr>`; | |
}); | |
html += `</tbody></table><div style="margin-top: 10px; font-size: 0.9em; color: #666;">์ด ${this.programsList.length}๊ฐ ํ๋ก๊ทธ๋จ</div>`; | |
programsListElement.innerHTML = html; | |
}, | |
// ํ๋ก๊ทธ๋จ ๋๋กญ๋ค์ด ์ ๋ฐ์ดํธ | |
updateProgramsDropdown: function() { | |
const dropdown = this.elements.programSelectDropdown; | |
if (!dropdown) return; | |
dropdown.innerHTML = ''; // ๊ธฐ์กด ์ต์ ์ ๊ฑฐ | |
const defaultOption = document.createElement('option'); | |
defaultOption.value = ''; | |
defaultOption.textContent = this.programsList.length > 0 ? '-- ์คํํ ํ๋ก๊ทธ๋จ ์ ํ --' : '-- ํ๋ก๊ทธ๋จ ์์ --'; | |
dropdown.appendChild(defaultOption); | |
this.programsList.forEach(program => { | |
const option = document.createElement('option'); | |
option.value = program.id || ''; | |
option.textContent = program.name || '์ ์ ์์'; | |
if (program.description) { | |
option.textContent += ` (${program.description})`; | |
} | |
dropdown.appendChild(option); | |
}); | |
}, | |
// ์คํ ๋ฒํผ ์ํ ์ ๋ฐ์ดํธ | |
updateExecuteButton: function() { | |
const dropdown = this.elements.programSelectDropdown; | |
const executeBtn = this.elements.executeProgramBtn; | |
if (!dropdown || !executeBtn) return; | |
executeBtn.disabled = !dropdown.value; // ์ ํ๋ ํ๋ก๊ทธ๋จ์ด ์์ ๋๋ง ํ์ฑํ | |
}, | |
// ํ๋ก๊ทธ๋จ ์คํ (๋ฏธ๋ฆฌ ์ ์๋) | |
executeProgram: async function(programId) { | |
if (!this.isConnected) { | |
this.showExecuteResult('error', '์ค๋ฅ: ๋จผ์ ์๋ฒ์ ์ฐ๊ฒฐํด์ผ ํฉ๋๋ค.'); | |
return; | |
} | |
if (!programId) { | |
this.showExecuteResult('error', '์ค๋ฅ: ์คํํ ํ๋ก๊ทธ๋จ์ ์ ํํด์ฃผ์ธ์.'); | |
return; | |
} | |
// ์คํ ์ค UI ์ ๋ฐ์ดํธ | |
if(this.elements.executeProgramBtn) this.elements.executeProgramBtn.disabled = true; | |
this.showExecuteResult('loading', 'ํ๋ก๊ทธ๋จ ์คํ ์ค...'); | |
try { | |
console.log(`ํ๋ก๊ทธ๋จ ์คํ ์์ฒญ ์ ์ก: ${programId}`); | |
// ๋ฐฑ์๋ API ํธ์ถ | |
const response = await AppUtils.fetchWithTimeout(`/api/device/programs/${programId}/execute`, { | |
method: 'POST', | |
headers: { 'Content-Type': 'application/json' }, | |
body: JSON.stringify({}) | |
}, 15000); // 15์ด ํ์์์ | |
const data = await response.json(); | |
if (response.ok && data.success) { | |
console.log('ํ๋ก๊ทธ๋จ ์คํ ์ฑ๊ณต:', data); | |
this.showExecuteResult('success', `์คํ ์ฑ๊ณต: ${data.message || 'ํ๋ก๊ทธ๋จ์ด ์ฑ๊ณต์ ์ผ๋ก ์คํ๋์์ต๋๋ค.'}`); | |
AppUtils.addSystemNotification(`ํ๋ก๊ทธ๋จ ์คํ ์ฑ๊ณต: ${this.getSelectedProgramName()}`); | |
} else { | |
console.error('ํ๋ก๊ทธ๋จ ์คํ ์คํจ:', data); | |
this.showExecuteResult('error', `์คํ ์คํจ: ${data.error || '์ ์ ์๋ ์ค๋ฅ'}`); | |
} | |
} catch (error) { | |
console.error('ํ๋ก๊ทธ๋จ ์คํ ์ค ์ค๋ฅ ๋ฐ์:', error); | |
if (error.message.includes('์๊ฐ์ด ์ด๊ณผ')) { | |
this.showExecuteResult('error', 'ํ๋ก๊ทธ๋จ ์คํ ์์ฒญ ์๊ฐ ์ด๊ณผ. ์๋ฒ ์๋ต์ด ์์ต๋๋ค.'); | |
} else { | |
this.showExecuteResult('error', `ํ๋ก๊ทธ๋จ ์คํ ์ค ์ค๋ฅ ๋ฐ์: ${error.message}`); | |
} | |
} finally { | |
if(this.elements.executeProgramBtn) this.elements.executeProgramBtn.disabled = false; | |
} | |
}, | |
// ์ ํ๋ ํ๋ก๊ทธ๋จ ์ด๋ฆ ๊ฐ์ ธ์ค๊ธฐ | |
getSelectedProgramName: function() { | |
const dropdown = this.elements.programSelectDropdown; | |
if (!dropdown || dropdown.selectedIndex < 0) return '์ ์ ์๋ ํ๋ก๊ทธ๋จ'; // ์ธ๋ฑ์ค ์ฒดํฌ ์ถ๊ฐ | |
const selectedOption = dropdown.options[dropdown.selectedIndex]; | |
return selectedOption ? selectedOption.textContent : '์ ์ ์๋ ํ๋ก๊ทธ๋จ'; | |
}, | |
// ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ์ค๋ฅ ํ์ | |
showProgramsError: function(errorMessage) { | |
const programsListElement = this.elements.programsList; | |
if (!programsListElement) return; | |
programsListElement.innerHTML = `<div class="error-message"><i class="fas fa-exclamation-circle"></i> ${errorMessage} <button class="retry-button" id="retryLoadProgramsBtn"><i class="fas fa-sync"></i> ๋ค์ ์๋</button></div>`; | |
const retryBtn = document.getElementById('retryLoadProgramsBtn'); | |
if (retryBtn) { | |
// ๊ธฐ์กด ๋ฆฌ์ค๋ ์ ๊ฑฐ ํ ์ถ๊ฐ (์ค๋ณต ๋ฐฉ์ง) | |
retryBtn.replaceWith(retryBtn.cloneNode(true)); | |
document.getElementById('retryLoadProgramsBtn').addEventListener('click', () => { | |
console.log('ํ๋ก๊ทธ๋จ ๋ชฉ๋ก ์ฌ์๋ ๋ฒํผ ํด๋ฆญ'); | |
this.loadProgramsList(); | |
}); | |
} | |
}, | |
// ์คํ ๊ฒฐ๊ณผ ํ์ (๋ฏธ๋ฆฌ ์ ์๋ ํ๋ก๊ทธ๋จ ์ฉ) | |
showExecuteResult: function(status, message) { | |
const resultElement = this.elements.executeResult; | |
if (!resultElement) return; | |
resultElement.classList.remove('success', 'error', 'warning'); // ๋ชจ๋ ์ํ ํด๋์ค ์ ๊ฑฐ | |
resultElement.innerHTML = ''; // ๋ด์ฉ ์ด๊ธฐํ | |
switch (status) { | |
case 'success': | |
resultElement.classList.add('success'); | |
resultElement.innerHTML = `<i class="fas fa-check-circle"></i> ${message}`; | |
break; | |
case 'error': | |
resultElement.classList.add('error'); | |
resultElement.innerHTML = `<i class="fas fa-exclamation-circle"></i> ${message}`; | |
break; | |
case 'warning': | |
resultElement.classList.add('warning'); | |
resultElement.innerHTML = `<i class="fas fa-exclamation-triangle"></i> ${message}`; | |
break; | |
case 'loading': | |
resultElement.innerHTML = `${AppUtils.createLoadingSpinner()} ${message}`; | |
break; | |
default: | |
resultElement.textContent = message; | |
} | |
}, | |
// ์ฌ์ฉ์ ์ ์ ํ๋ก๊ทธ๋จ ์คํ | |
executeCustomProgram: async function(command) { | |
if (!this.isConnected) { | |
this.showCustomExecuteResult('error', '์ค๋ฅ: ๋จผ์ ์๋ฒ์ ์ฐ๊ฒฐํด์ผ ํฉ๋๋ค.'); | |
return; | |
} | |
if (!command || command.trim() === '') { | |
this.showCustomExecuteResult('error', '์ค๋ฅ: ์คํํ ๋ช ๋ น์ด๋ฅผ ์ ๋ ฅํด์ฃผ์ธ์.'); | |
return; | |
} | |
// ์คํ ์ค UI ์ ๋ฐ์ดํธ | |
if(this.elements.executeCustomBtn) this.elements.executeCustomBtn.disabled = true; | |
this.showCustomExecuteResult('loading', '๋ช ๋ น์ด ์คํ ์ค...'); | |
try { | |
console.log(`์ฌ์ฉ์ ์ ์ ํ๋ก๊ทธ๋จ ์คํ ์์ฒญ ์ ์ก: ${command}`); | |
// ๋ฐฑ์๋ API ํธ์ถ | |
const response = await AppUtils.fetchWithTimeout('/api/device/execute-custom', { | |
method: 'POST', | |
headers: { 'Content-Type': 'application/json' }, | |
body: JSON.stringify({ command: command }) | |
}, 15000); // 15์ด ํ์์์ | |
const data = await response.json(); | |
if (response.ok && data.success) { | |
console.log('์ฌ์ฉ์ ์ ์ ํ๋ก๊ทธ๋จ ์คํ ์ฑ๊ณต:', data); | |
let successMessage = `๋ช ๋ น์ด ์คํ ์ฑ๊ณต: ${data.message || ''}`; | |
if (data.output && data.output.trim()) { | |
successMessage += `<div class="command-output"><pre>${AppUtils.escapeHtml(data.output)}</pre></div>`; | |
} | |
this.showCustomExecuteResult('success', successMessage); | |
AppUtils.addSystemNotification(`์ฌ์ฉ์ ์ ์ ๋ช ๋ น์ด ์คํ ์ฑ๊ณต: ${command}`); | |
} else { | |
console.error('์ฌ์ฉ์ ์ ์ ํ๋ก๊ทธ๋จ ์คํ ์คํจ:', data); | |
let errorMessage = `์คํ ์คํจ: ${data.error || '์ ์ ์๋ ์ค๋ฅ'}`; | |
if (data.error_output && data.error_output.trim()) { | |
errorMessage += `<div class="command-error"><pre>${AppUtils.escapeHtml(data.error_output)}</pre></div>`; | |
} | |
this.showCustomExecuteResult('error', errorMessage); | |
} | |
} catch (error) { | |
console.error('์ฌ์ฉ์ ์ ์ ํ๋ก๊ทธ๋จ ์คํ ์ค ์ค๋ฅ ๋ฐ์:', error); | |
if (error.message.includes('์๊ฐ์ด ์ด๊ณผ')) { | |
this.showCustomExecuteResult('error', '๋ช ๋ น์ด ์คํ ์์ฒญ ์๊ฐ ์ด๊ณผ. ์๋ฒ ์๋ต์ด ์์ต๋๋ค.'); | |
} else { | |
this.showCustomExecuteResult('error', `๋ช ๋ น์ด ์คํ ์ค ์ค๋ฅ ๋ฐ์: ${error.message}`); | |
} | |
} finally { | |
if(this.elements.executeCustomBtn) this.elements.executeCustomBtn.disabled = false; | |
} | |
}, | |
// ์ฌ์ฉ์ ์ ์ ํ๋ก๊ทธ๋จ ์คํ ๊ฒฐ๊ณผ ํ์ | |
showCustomExecuteResult: function(status, message) { | |
const resultElement = this.elements.customExecuteResult; | |
if (!resultElement) return; | |
resultElement.classList.remove('success', 'error', 'warning'); // ๋ชจ๋ ์ํ ํด๋์ค ์ ๊ฑฐ | |
resultElement.innerHTML = ''; // ๋ด์ฉ ์ด๊ธฐํ | |
switch (status) { | |
case 'success': | |
resultElement.classList.add('success'); | |
resultElement.innerHTML = `<i class="fas fa-check-circle"></i> ${message}`; | |
break; | |
case 'error': | |
resultElement.classList.add('error'); | |
resultElement.innerHTML = `<i class="fas fa-exclamation-circle"></i> ${message}`; | |
break; | |
case 'warning': | |
resultElement.classList.add('warning'); | |
resultElement.innerHTML = `<i class="fas fa-exclamation-triangle"></i> ${message}`; | |
break; | |
case 'loading': | |
resultElement.innerHTML = `${AppUtils.createLoadingSpinner()} ${message}`; | |
break; | |
default: | |
resultElement.textContent = message; // ๊ธฐ๋ณธ์ ํ ์คํธ๋ง ํ์ | |
} | |
}, | |
// ================== ํฌํธ ์ค์บ ํจ์ ์ถ๊ฐ ================== | |
// ์ฅ์น ํฌํธ ์ค์บ ํจ์ | |
scanDevicePorts: async function() { | |
if (!this.isConnected) { | |
this.showPortsStatus('error', '์ค๋ฅ: ๋จผ์ ์๋ฒ์ ์ฐ๊ฒฐํด์ผ ํฉ๋๋ค.'); | |
console.error('์ฅ์น ํฌํธ ์ค์บ ์๋ ์ค ์ค๋ฅ: ์๋ฒ ์ฐ๊ฒฐ ์๋จ'); | |
return; | |
} | |
// ์ค์บ ์ค UI ์ ๋ฐ์ดํธ | |
if(this.elements.scanPortsBtn) this.elements.scanPortsBtn.disabled = true; | |
this.showPortsStatus('loading', '์ฅ์น ํฌํธ ์ค์บ ์ค...'); | |
try { | |
console.log('์ฅ์น ํฌํธ ์ค์บ ์์ฒญ ์ ์ก'); | |
// ๋ฐฑ์๋ API ํธ์ถ | |
const response = await AppUtils.fetchWithTimeout('/api/device/scan-ports', { | |
method: 'GET' | |
}, 30000); // ์ฅ์น ์ค์บ์ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆด ์ ์์ผ๋ฏ๋ก ํ์์์ 30์ด๋ก ์ค์ | |
const data = await response.json(); | |
if (response.ok && data.success) { | |
// ์ค์บ ์ฑ๊ณต | |
console.log('์ฅ์น ํฌํธ ์ค์บ ์ฑ๊ณต:', data); | |
// ๊ฒฐ๊ณผ ํ์ | |
this.displayPortsResults(data); | |
this.showPortsStatus('success', '์ฅ์น ํฌํธ ์ค์บ์ด ์๋ฃ๋์์ต๋๋ค.'); | |
} else { | |
// ์ค์บ ์คํจ | |
console.error('์ฅ์น ํฌํธ ์ค์บ ์คํจ:', data); | |
this.showPortsStatus('error', `์ค์บ ์คํจ: ${data.error || '์ ์ ์๋ ์ค๋ฅ'}`); | |
} | |
} catch (error) { | |
// ์์ธ ๋ฐ์ | |
console.error('์ฅ์น ํฌํธ ์ค์บ ์ค ์ค๋ฅ ๋ฐ์:', error); | |
if (error.message.includes('์๊ฐ์ด ์ด๊ณผ')) { | |
this.showPortsStatus('error', '์ฅ์น ํฌํธ ์ค์บ ์์ฒญ ์๊ฐ ์ด๊ณผ. ์๋ฒ ์๋ต์ด ์์ต๋๋ค.'); | |
} else { | |
this.showPortsStatus('error', `์ฅ์น ํฌํธ ์ค์บ ์ค ์ค๋ฅ ๋ฐ์: ${error.message}`); | |
} | |
} finally { | |
// ๋ฒํผ ๋ค์ ํ์ฑํ | |
if(this.elements.scanPortsBtn) this.elements.scanPortsBtn.disabled = false; | |
} | |
}, | |
// ์ฅ์น ํฌํธ ์ค์บ ๊ฒฐ๊ณผ ํ์ | |
displayPortsResults: function(data) { | |
const portsResultsElement = this.elements.portsResults; | |
if (!portsResultsElement) return; // ์์ ์์ผ๋ฉด ์ข ๋ฃ | |
// ์์คํ ์ ๋ณด | |
const systemInfo = data.system_info || {}; | |
const devices = data.devices || {}; | |
const serialPorts = devices.serial || []; | |
const usbDevices = devices.usb || []; | |
const windowsUsbDevices = devices.windows_usb || []; // windows_usb ํค ์ถ๊ฐ | |
// HTML ์์ฑ ์์ | |
let html = `<div class="ports-results-container">`; | |
// ์์คํ ์ ๋ณด ์น์ | |
html += `<div class="ports-section"> | |
<h4>์์คํ ์ ๋ณด</h4> | |
<div class="info-row"><span class="info-label">OS:</span><span class="info-value">${AppUtils.escapeHtml(systemInfo.os || '์ ์ ์์')} ${AppUtils.escapeHtml(systemInfo.version || '')}</span></div> | |
<div class="info-row"><span class="info-label">์์คํ :</span><span class="info-value">${AppUtils.escapeHtml(systemInfo.platform || '์ ์ ์์')}</span></div> | |
<div class="info-row"><span class="info-label">์กฐํ ์๊ฐ:</span><span class="info-value">${AppUtils.escapeHtml(data.timestamp || '์ ์ ์์')}</span></div> | |
</div>`; | |
// ์๋ฆฌ์ผ ํฌํธ ์น์ | |
html += `<div class="ports-section"><h4>์๋ฆฌ์ผ ํฌํธ (${serialPorts.length}๊ฐ)</h4>`; | |
if (serialPorts.length === 0) { | |
html += `<p class="no-ports-message">๋ฐ๊ฒฌ๋ ์๋ฆฌ์ผ ํฌํธ๊ฐ ์์ต๋๋ค.</p>`; | |
} else { | |
html += `<table class="ports-table"><thead><tr><th>ํฌํธ</th><th>์ค๋ช </th><th>์ ์กฐ์ฌ</th><th>VID:PID</th></tr></thead><tbody>`; | |
serialPorts.forEach(port => { | |
const vidPid = (port.vid && port.pid) ? `${port.vid}:${port.pid}` : '์ ์ ์์'; | |
html += `<tr> | |
<td>${AppUtils.escapeHtml(port.port || '')}</td> | |
<td>${AppUtils.escapeHtml(port.description || '')}</td> | |
<td>${AppUtils.escapeHtml(port.manufacturer || '')}</td> | |
<td>${AppUtils.escapeHtml(vidPid)}</td> | |
</tr>`; | |
}); | |
html += `</tbody></table>`; | |
} | |
html += `</div>`; | |
// USB ์ฅ์น ์น์ (pyserial list_ports ๊ธฐ๋ฐ) | |
html += `<div class="ports-section"><h4>USB ์ฅ์น (pyserial) (${usbDevices.length}๊ฐ)</h4>`; | |
if (usbDevices.length === 0) { | |
html += `<p class="no-ports-message">๋ฐ๊ฒฌ๋ USB ์ฅ์น๊ฐ ์์ต๋๋ค.</p>`; | |
} else { | |
html += `<table class="ports-table"><thead><tr><th>VID:PID</th><th>์ ํ๋ช </th><th>์ ์กฐ์ฌ</th><th>์์น</th></tr></thead><tbody>`; | |
usbDevices.forEach(device => { | |
const vidPid = (device.vid && device.pid) ? `${device.vid}:${device.pid}` : '์ ์ ์์'; | |
html += `<tr> | |
<td>${AppUtils.escapeHtml(vidPid)}</td> | |
<td>${AppUtils.escapeHtml(device.product || '')}</td> | |
<td>${AppUtils.escapeHtml(device.manufacturer || '')}</td> | |
<td>${AppUtils.escapeHtml(device.location || '')}</td> | |
</tr>`; | |
}); | |
html += `</tbody></table>`; | |
} | |
html += `</div>`; | |
// Windows WMI USB ์ฅ์น ์น์ (์๋ ๊ฒฝ์ฐ) | |
if (windowsUsbDevices && windowsUsbDevices.length > 0) { | |
html += `<div class="ports-section"><h4>Windows USB ์ฅ์น (WMI) (${windowsUsbDevices.length}๊ฐ)</h4>`; | |
html += `<table class="ports-table"><thead><tr><th>์ด๋ฆ</th><th>์ค๋ช </th><th>์ ์กฐ์ฌ</th><th>VID:PID</th></tr></thead><tbody>`; | |
windowsUsbDevices.forEach(device => { | |
const vidPid = (device.vid && device.pid) ? `${device.vid}:${device.pid}` : '์ ์ ์์'; | |
html += `<tr> | |
<td>${AppUtils.escapeHtml(device.name || '')}</td> | |
<td>${AppUtils.escapeHtml(device.description || '')}</td> | |
<td>${AppUtils.escapeHtml(device.manufacturer || '')}</td> | |
<td>${AppUtils.escapeHtml(vidPid)}</td> | |
</tr>`; | |
}); | |
html += `</tbody></table></div>`; | |
} | |
// ์ปจํ ์ด๋ ๋ซ๊ธฐ | |
html += `</div>`; | |
// HTML ์ค์ | |
portsResultsElement.innerHTML = html; | |
}, | |
// ํฌํธ ์ค์บ ์ํ ํ์ | |
showPortsStatus: function(status, message) { | |
const statusElement = this.elements.portsStatus; | |
if (!statusElement) return; // ์์ ์์ผ๋ฉด ์ข ๋ฃ | |
// ๋ชจ๋ ์ํ ํด๋์ค ์ ๊ฑฐ | |
statusElement.classList.remove('success', 'error', 'warning'); | |
// ๋ด์ฉ ์ด๊ธฐํ | |
statusElement.innerHTML = ''; | |
// ์ํ์ ๋ฐ๋ผ ์ฒ๋ฆฌ | |
switch (status) { | |
case 'success': | |
statusElement.classList.add('success'); | |
statusElement.innerHTML = `<i class="fas fa-check-circle"></i> ${message}`; | |
break; | |
case 'error': | |
statusElement.classList.add('error'); | |
statusElement.innerHTML = `<i class="fas fa-exclamation-circle"></i> ${message}`; | |
break; | |
case 'warning': | |
statusElement.classList.add('warning'); | |
statusElement.innerHTML = `<i class="fas fa-exclamation-triangle"></i> ${message}`; | |
break; | |
case 'loading': | |
statusElement.innerHTML = `${AppUtils.createLoadingSpinner()} ${message}`; | |
break; | |
default: | |
statusElement.textContent = message; | |
} | |
} | |
// ================== ์ถ๊ฐ ๋ ============================ | |
}; // DeviceControl ๊ฐ์ฒด ๋ | |
// ํ์ด์ง ๋ก๋ ์๋ฃ ์ ๋ชจ๋ ์ด๊ธฐํ | |
document.addEventListener('DOMContentLoaded', function() { | |
console.log('์ฅ์น ์ ์ด ๋ชจ๋ ๋ก๋๋จ'); | |
// DOM์ด ์์ ํ ๋ก๋๋ ํ ์ฝ๊ฐ์ ์ง์ฐ์ ๋๊ณ ์ด๊ธฐํ | |
// DOM ์์๊ฐ ํ์คํ ๋ก๋๋ ํ์ ์ด๊ธฐํํ๊ธฐ ์ํจ | |
setTimeout(() => { | |
// AppUtils๊ฐ ์ ์๋์๋์ง ํ์ธ (์์กด์ฑ) | |
if (typeof AppUtils === 'undefined') { | |
console.error('AppUtils๊ฐ ์ ์๋์ง ์์ DeviceControl ์ด๊ธฐํ ์คํจ.'); | |
// ํ์ํ๋ค๋ฉด ์ฌ์ฉ์์๊ฒ ์๋ฆผ ํ์ | |
alert('ํ์ด์ง ์ด๊ธฐํ ์ค๋ฅ: ํ์ ์ ํธ๋ฆฌํฐ(AppUtils)๋ฅผ ๋ก๋ํ ์ ์์ต๋๋ค.'); | |
return; | |
} | |
DeviceControl.init(); | |
}, 100); | |
}); |