RAG5_2_ChooseLLM / app /static /js /app-device.js
jeongsoo's picture
Succeed:local server control!2
7cef4b0
/**
* 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
},
// ๋ชจ๋“ˆ ์ดˆ๊ธฐํ™”
init: function() {
console.log('์žฅ์น˜ ์ œ์–ด ๋ชจ๋“ˆ ์ดˆ๊ธฐํ™” ์ค‘...');
// DOM ์š”์†Œ ์ฐธ์กฐ ๊ฐ€์ ธ์˜ค๊ธฐ
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');
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);
});
}
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'));
// ์žฅ์น˜ ์ œ์–ด ํƒญ ํ™œ์„ฑํ™”
this.elements.deviceTab.classList.add('active');
this.elements.deviceSection.classList.add('active');
console.log('์žฅ์น˜ ์ œ์–ด ํƒญ์œผ๋กœ ์ „ํ™˜ ์™„๋ฃŒ');
},
// ์„œ๋ฒ„ ์—ฐ๊ฒฐ ํ•จ์ˆ˜
connectServer: async function() {
// URL ๊ฐ€์ ธ์˜ค๊ธฐ (์ž…๋ ฅ๋œ ๊ฒƒ์ด ์žˆ์œผ๋ฉด ๋ฐฑ์—…์œผ๋กœ ์‚ฌ์šฉ)
const inputUrl = this.elements.deviceServerUrlInput.value.trim();
// ์—ฐ๊ฒฐ ์‹œ๋„ ์ค‘ UI ์—…๋ฐ์ดํŠธ
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) {
// ์—ฐ๊ฒฐ ์„ฑ๊ณต
console.log('ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ • ์žฅ์น˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์„ฑ๊ณต:', data);
this.isConnected = true;
this.updateConnectionStatus('connected', `์„œ๋ฒ„ ์—ฐ๊ฒฐ ์„ฑ๊ณต! ์ƒํƒœ: ${data.server_status || '์ •์ƒ'}`);
// ๊ธฐ๋Šฅ UI ํ™œ์„ฑํ™”
this.elements.deviceBasicFunctions.classList.add('active');
this.elements.deviceProgramControl.classList.add('active');
// ์žฅ์น˜ ์ƒํƒœ ์ž๋™ ์ฒดํฌ
this.checkDeviceStatus();
// ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์ž๋™ ๋กœ๋“œ
this.loadProgramsList();
// ์‹œ์Šคํ…œ ์•Œ๋ฆผ
AppUtils.addSystemNotification(`์žฅ์น˜ ๊ด€๋ฆฌ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์„ฑ๊ณต! (ํ™˜๊ฒฝ๋ณ€์ˆ˜ URL)`);
} else {
// ํ™˜๊ฒฝ๋ณ€์ˆ˜ URL ์—ฐ๊ฒฐ ์‹คํŒจ, ์ž…๋ ฅ๋œ URL๋กœ ์‹œ๋„
console.warn('ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ • ์žฅ์น˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹คํŒจ, ์ž…๋ ฅ URL๋กœ ์žฌ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค:', data);
// ์ž…๋ ฅ URL์ด ์žˆ๋Š”์ง€ ํ™•์ธ
if (!inputUrl) {
console.error('์ž…๋ ฅ๋œ URL์ด ์—†์–ด ์—ฐ๊ฒฐ ์‹คํŒจ');
this.isConnected = false;
this.updateConnectionStatus('error', 'ํ™˜๊ฒฝ๋ณ€์ˆ˜ URL ์—ฐ๊ฒฐ ์‹คํŒจ ๋ฐ ์ž…๋ ฅ๋œ URL์ด ์—†์Šต๋‹ˆ๋‹ค. URL์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.');
return;
}
// ์ž…๋ ฅ URL๋กœ ์žฌ์‹œ๋„
this.updateConnectionStatus('connecting', `์ž…๋ ฅ URL(${inputUrl})๋กœ ์—ฐ๊ฒฐ ์‹œ๋„ ์ค‘...`);
console.log(`์ž…๋ ฅํ•œ URL๋กœ ์žฅ์น˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹œ๋„: ${inputUrl}`);
// ๋ฐฑ์—”๋“œ API ํ˜ธ์ถœ - ์ž…๋ ฅ URL ์‚ฌ์šฉ
const customUrlResponse = await AppUtils.fetchWithTimeout('/api/device/connect', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ url: inputUrl })
}, 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 ํ™œ์„ฑํ™”
this.elements.deviceBasicFunctions.classList.add('active');
this.elements.deviceProgramControl.classList.add('active');
// ์žฅ์น˜ ์ƒํƒœ ์ž๋™ ์ฒดํฌ
this.checkDeviceStatus();
// ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์ž๋™ ๋กœ๋“œ
this.loadProgramsList();
// ์‹œ์Šคํ…œ ์•Œ๋ฆผ
AppUtils.addSystemNotification(`์žฅ์น˜ ๊ด€๋ฆฌ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์„ฑ๊ณต! (${inputUrl})`);
} else {
// ์ž…๋ ฅ URL ์—ฐ๊ฒฐ ์‹คํŒจ
console.error('์ž…๋ ฅ URL ์žฅ์น˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹คํŒจ:', customUrlData);
this.isConnected = false;
this.updateConnectionStatus('error', `์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹คํŒจ: ${customUrlData.error || '์„œ๋ฒ„ ์‘๋‹ต ์˜ค๋ฅ˜'}`);
}
}
} catch (error) {
// ์˜ˆ์™ธ ๋ฐœ์ƒ
console.error('์„œ๋ฒ„ ์—ฐ๊ฒฐ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:', error);
this.isConnected = false;
// ํ™˜๊ฒฝ๋ณ€์ˆ˜ URL ์—ฐ๊ฒฐ ์‹คํŒจ, ์ž…๋ ฅ๋œ URL๋กœ ์‹œ๋„
if (inputUrl) {
console.warn('ํ™˜๊ฒฝ๋ณ€์ˆ˜ URL ์—ฐ๊ฒฐ ์‹œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ, ์ž…๋ ฅ URL๋กœ ์žฌ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค');
try {
// ์ž…๋ ฅ URL๋กœ ์žฌ์‹œ๋„
this.updateConnectionStatus('connecting', `์ž…๋ ฅ URL(${inputUrl})๋กœ ์—ฐ๊ฒฐ ์‹œ๋„ ์ค‘...`);
console.log(`์ž…๋ ฅํ•œ URL๋กœ ์žฅ์น˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹œ๋„: ${inputUrl}`);
// ๋ฐฑ์—”๋“œ API ํ˜ธ์ถœ - ์ž…๋ ฅ URL ์‚ฌ์šฉ
const customUrlResponse = await AppUtils.fetchWithTimeout('/api/device/connect', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ url: inputUrl })
}, 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 ํ™œ์„ฑํ™”
this.elements.deviceBasicFunctions.classList.add('active');
this.elements.deviceProgramControl.classList.add('active');
// ์žฅ์น˜ ์ƒํƒœ ์ž๋™ ์ฒดํฌ
this.checkDeviceStatus();
// ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์ž๋™ ๋กœ๋“œ
this.loadProgramsList();
// ์‹œ์Šคํ…œ ์•Œ๋ฆผ
AppUtils.addSystemNotification(`์žฅ์น˜ ๊ด€๋ฆฌ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์„ฑ๊ณต! (${inputUrl})`);
return; // ์„ฑ๊ณตํ•˜๋ฉด ์—ฌ๊ธฐ์„œ ์ข…๋ฃŒ
} else {
// ์ž…๋ ฅ URL ์—ฐ๊ฒฐ ์‹คํŒจ
console.error('์ž…๋ ฅ URL ์žฅ์น˜ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹คํŒจ:', customUrlData);
this.updateConnectionStatus('error', `์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹คํŒจ: ${customUrlData.error || '์„œ๋ฒ„ ์‘๋‹ต ์˜ค๋ฅ˜'}`);
}
} catch (inputUrlError) {
// ์ž…๋ ฅ URL๋กœ ์žฌ์‹œ๋„ ์ค‘ ์˜ค๋ฅ˜
console.error('์ž…๋ ฅ URL๋กœ ์žฌ์‹œ๋„ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:', inputUrlError);
if (inputUrlError.message.includes('์‹œ๊ฐ„์ด ์ดˆ๊ณผ')) {
this.updateConnectionStatus('error', '์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹œ๊ฐ„ ์ดˆ๊ณผ. ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”.');
} else {
this.updateConnectionStatus('error', `์„œ๋ฒ„ ์—ฐ๊ฒฐ ์˜ค๋ฅ˜: ${inputUrlError.message}`);
}
}
} else {
// ํ…์ŠคํŠธ๋ฐ•์Šค์— URL์ด ์—†๋Š” ๊ฒฝ์šฐ
if (error.message.includes('์‹œ๊ฐ„์ด ์ดˆ๊ณผ')) {
this.updateConnectionStatus('error', 'ํ™˜๊ฒฝ๋ณ€์ˆ˜ URL ์—ฐ๊ฒฐ ์‹œ๊ฐ„ ์ดˆ๊ณผ. URL์„ ์ž…๋ ฅํ•˜์—ฌ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.');
} else {
this.updateConnectionStatus('error', `ํ™˜๊ฒฝ๋ณ€์ˆ˜ URL ์—ฐ๊ฒฐ ์˜ค๋ฅ˜. URL์„ ์ž…๋ ฅํ•˜์—ฌ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”: ${error.message}`);
}
}
} finally {
// ๋ฒ„ํŠผ ๋‹ค์‹œ ํ™œ์„ฑํ™”
this.elements.connectDeviceServerBtn.disabled = false;
}
},
// ์—ฐ๊ฒฐ ์ƒํƒœ ์—…๋ฐ์ดํŠธ
updateConnectionStatus: function(status, message) {
const statusElement = this.elements.deviceConnectionStatus;
// ๋ชจ๋“  ์ƒํƒœ ํด๋ž˜์Šค ์ œ๊ฑฐ
statusElement.classList.remove('connected', 'disconnected', 'error', 'connecting');
// ์ƒํƒœ์— ๋”ฐ๋ผ ํด๋ž˜์Šค ์ถ”๊ฐ€
statusElement.classList.add(status);
// ๋ฉ”์‹œ์ง€ ์—…๋ฐ์ดํŠธ
statusElement.textContent = message;
console.log(`์—ฐ๊ฒฐ ์ƒํƒœ ์—…๋ฐ์ดํŠธ: ${status} - ${message}`);
},
// ์žฅ์น˜ ์ƒํƒœ ํ™•์ธ
checkDeviceStatus: async function() {
if (!this.isConnected) {
this.elements.deviceStatusResult.value = '์˜ค๋ฅ˜: ๋จผ์ € ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.';
console.error('์žฅ์น˜ ์ƒํƒœ ํ™•์ธ ์‹œ๋„ ์ค‘ ์˜ค๋ฅ˜: ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์•ˆ๋จ');
return;
}
// ์ƒํƒœ ํ™•์ธ ์ค‘ UI ์—…๋ฐ์ดํŠธ
this.elements.checkDeviceStatusBtn.disabled = true;
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;
this.elements.deviceStatusResult.value = JSON.stringify(data, null, 2);
} else {
// ์ƒํƒœ ํ™•์ธ ์‹คํŒจ
console.error('์žฅ์น˜ ์ƒํƒœ ํ™•์ธ ์‹คํŒจ:', data);
this.elements.deviceStatusResult.value = `์ƒํƒœ ํ™•์ธ ์‹คํŒจ: ${data.error || '์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜'}`;
}
} catch (error) {
// ์˜ˆ์™ธ ๋ฐœ์ƒ
console.error('์žฅ์น˜ ์ƒํƒœ ํ™•์ธ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:', error);
this.elements.deviceStatusResult.value = `์ƒํƒœ ํ™•์ธ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: ${error.message}`;
} finally {
// ๋ฒ„ํŠผ ๋‹ค์‹œ ํ™œ์„ฑํ™”
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;
this.elements.getProgramsBtn.disabled = true;
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;
this.elements.getProgramsBtn.disabled = false;
}
},
// ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ํ‘œ์‹œ
displayProgramsList: function() {
const programsListElement = this.elements.programsList;
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;
// ๊ธฐ์กด ์˜ต์…˜ ์ œ๊ฑฐ
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;
// ์„ ํƒ๋œ ํ”„๋กœ๊ทธ๋žจ์ด ์žˆ์„ ๋•Œ๋งŒ ๋ฒ„ํŠผ ํ™œ์„ฑํ™”
executeBtn.disabled = !dropdown.value;
},
// ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰
executeProgram: async function(programId) {
if (!this.isConnected) {
this.showExecuteResult('error', '์˜ค๋ฅ˜: ๋จผ์ € ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.');
console.error('ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‹œ๋„ ์ค‘ ์˜ค๋ฅ˜: ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์•ˆ๋จ');
return;
}
if (!programId) {
this.showExecuteResult('error', '์˜ค๋ฅ˜: ์‹คํ–‰ํ•  ํ”„๋กœ๊ทธ๋žจ์„ ์„ ํƒํ•ด์ฃผ์„ธ์š”.');
console.error('ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‹œ๋„ ์ค‘ ์˜ค๋ฅ˜: ํ”„๋กœ๊ทธ๋žจ ID ์—†์Œ');
return;
}
// ์‹คํ–‰ ์ค‘ UI ์—…๋ฐ์ดํŠธ
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 {
// ๋ฒ„ํŠผ ๋‹ค์‹œ ํ™œ์„ฑํ™”
this.elements.executeProgramBtn.disabled = false;
}
},
// ์„ ํƒ๋œ ํ”„๋กœ๊ทธ๋žจ ์ด๋ฆ„ ๊ฐ€์ ธ์˜ค๊ธฐ
getSelectedProgramName: function() {
const dropdown = this.elements.programSelectDropdown;
const selectedOption = dropdown.options[dropdown.selectedIndex];
return selectedOption ? selectedOption.textContent : '์•Œ ์ˆ˜ ์—†๋Š” ํ”„๋กœ๊ทธ๋žจ';
},
// ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์˜ค๋ฅ˜ ํ‘œ์‹œ
showProgramsError: function(errorMessage) {
this.elements.programsList.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>
`;
// ์žฌ์‹œ๋„ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ
document.getElementById('retryLoadProgramsBtn').addEventListener('click', () => {
console.log('ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์žฌ์‹œ๋„ ๋ฒ„ํŠผ ํด๋ฆญ');
this.loadProgramsList();
});
},
// ์‹คํ–‰ ๊ฒฐ๊ณผ ํ‘œ์‹œ
showExecuteResult: function(status, message) {
const resultElement = this.elements.executeResult;
// ๋ชจ๋“  ์ƒํƒœ ํด๋ž˜์Šค ์ œ๊ฑฐ
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;
}
}
};
// ํŽ˜์ด์ง€ ๋กœ๋“œ ์™„๋ฃŒ ์‹œ ๋ชจ๋“ˆ ์ดˆ๊ธฐํ™”
document.addEventListener('DOMContentLoaded', function() {
console.log('์žฅ์น˜ ์ œ์–ด ๋ชจ๋“ˆ ๋กœ๋“œ๋จ');
// DOM์ด ์™„์ „ํžˆ ๋กœ๋“œ๋œ ํ›„ ์•ฝ๊ฐ„์˜ ์ง€์—ฐ์„ ๋‘๊ณ  ์ดˆ๊ธฐํ™”
setTimeout(() => {
DeviceControl.init();
}, 100);
});