RAG6_AgenticAI / app /static /js /app-device.js
jeongsoo's picture
fix
bc73d45
raw
history blame
18.8 kB
/**
* RAG ๊ฒ€์ƒ‰ ์ฑ—๋ด‡ ์žฅ์น˜ ๊ด€๋ฆฌ JavaScript
*/
// DOM ์š”์†Œ
const deviceTab = document.getElementById('deviceTab');
const deviceSection = document.getElementById('deviceSection');
const checkDeviceStatusButton = document.getElementById('checkDeviceStatusButton');
const deviceStatusLoading = document.getElementById('deviceStatusLoading');
const deviceStatusResult = document.getElementById('deviceStatusResult');
const statusIcon = document.getElementById('statusIcon');
const statusText = document.getElementById('statusText');
const refreshDevicesButton = document.getElementById('refreshDevicesButton');
const deviceList = document.getElementById('deviceList');
const devicesLoading = document.getElementById('devicesLoading');
const noDevicesMessage = document.getElementById('noDevicesMessage');
const loadProgramsButton = document.getElementById('loadProgramsButton');
const programsLoading = document.getElementById('programsLoading');
const programsList = document.getElementById('programsList');
const noProgramsMessage = document.getElementById('noProgramsMessage');
// ์žฅ์น˜ ์„œ๋ฒ„ URL ์„ค์ •
// ์ง์ ‘ ์ ‘๊ทผ ์„ค์ •: ๋นˆ ๋ฌธ์ž์—ด์ด๋ฉด ํ˜„์žฌ ํ˜ธ์ŠคํŠธ์˜ 5050 ํฌํŠธ๋ฅผ ์‚ฌ์šฉ
let DEVICE_SERVER_URL = ''; // ์„œ๋ฒ„์—์„œ ์ „๋‹ฌ๋œ URL์ด ์žˆ์œผ๋ฉด ์ดˆ๊ธฐํ™” ์‹œ ์„ค์ •๋จ
/**
* ์žฅ์น˜ ์„œ๋ฒ„ API ๊ฒฝ๋กœ ์ƒ์„ฑ ํ•จ์ˆ˜
* @param {string} endpoint - API ์—”๋“œํฌ์ธํŠธ ๊ฒฝ๋กœ
* @returns {string} - ์™„์ „ํ•œ API URL
*/
function getDeviceApiUrl(endpoint) {
// ์ง์ ‘ ์ ‘๊ทผ ๋ชจ๋“œ์ธ ๊ฒฝ์šฐ (๋ณ„๋„ ์„œ๋ฒ„์— ์ง์ ‘ ์š”์ฒญ)
if (DEVICE_SERVER_URL) {
return `${DEVICE_SERVER_URL}${endpoint}`;
}
// ํ”„๋ก์‹œ ๋ชจ๋“œ์ธ ๊ฒฝ์šฐ (๋‚ด๋ถ€ API ๊ฒฝ๋กœ ์‚ฌ์šฉ)
return endpoint;
}
/**
* ์žฅ์น˜ ์„œ๋ฒ„ ์„ค์ • ์ดˆ๊ธฐํ™” (ํŽ˜์ด์ง€ ๋กœ๋“œ ์‹œ ํ˜ธ์ถœ)
*/
function initDeviceServerSettings() {
console.log("์žฅ์น˜ ์„œ๋ฒ„ ์„ค์ • ์ดˆ๊ธฐํ™” ์‹œ์ž‘");
// ์„œ๋ฒ„ URL ์„ค์ • (์›น ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์„ค์ • ๋ถˆ๋Ÿฌ์˜ค๊ธฐ)
fetch('/api/device/settings')
.then(response => {
if (!response.ok) {
throw new Error('์„ค์ •์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค');
}
return response.json();
})
.then(data => {
if (data.server_url) {
console.log(`์žฅ์น˜ ์„œ๋ฒ„ URL ์„ค์ •๋จ: ${data.server_url}`);
DEVICE_SERVER_URL = data.server_url;
} else {
// ์„ค์ • ์—†์Œ - ์ž๋™ ์ƒ์„ฑ (ํ˜„์žฌ ํ˜ธ์ŠคํŠธ + ํฌํŠธ 5050)
const currentHost = window.location.hostname;
const protocol = window.location.protocol;
DEVICE_SERVER_URL = `${protocol}//${currentHost}:5051`;
console.log(`์žฅ์น˜ ์„œ๋ฒ„ URL ์ž๋™ ์„ค์ •: ${DEVICE_SERVER_URL}`);
}
})
.catch(error => {
console.error('์žฅ์น˜ ์„œ๋ฒ„ ์„ค์ • ์ดˆ๊ธฐํ™” ์˜ค๋ฅ˜:', error);
// ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์„ค์ • (ํ˜„์žฌ ํ˜ธ์ŠคํŠธ + ํฌํŠธ 5051)
const currentHost = window.location.hostname;
const protocol = window.location.protocol;
DEVICE_SERVER_URL = `${protocol}//${currentHost}:5051`;
console.log(`์žฅ์น˜ ์„œ๋ฒ„ URL ๊ธฐ๋ณธ๊ฐ’ ์„ค์ •: ${DEVICE_SERVER_URL}`);
});
}
// ํŽ˜์ด์ง€ ๋กœ๋“œ ์‹œ ์ดˆ๊ธฐํ™”
document.addEventListener('DOMContentLoaded', () => {
console.log("์žฅ์น˜ ๊ด€๋ฆฌ ๋ชจ๋“ˆ ์ดˆ๊ธฐํ™”");
// ์žฅ์น˜ ์„œ๋ฒ„ ์„ค์ • ์ดˆ๊ธฐํ™”
initDeviceServerSettings();
// ํƒญ ์ „ํ™˜ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋Š” ์ด๋ฏธ app.js์—์„œ ๋“ฑ๋ก๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ์—ฌ๊ธฐ์„œ๋Š” ๋“ฑ๋กํ•˜์ง€ ์•Š์Œ
// ๋Œ€์‹  ์ „์—ญ ํ•จ์ˆ˜๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ
if (typeof window.switchTab !== 'function') {
console.log("window.switchTab ํ•จ์ˆ˜๊ฐ€ ์ •์˜๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.");
} else {
console.log("window.switchTab ํ•จ์ˆ˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.");
}
// ์žฅ์น˜ ์ƒํƒœ ํ™•์ธ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ
checkDeviceStatusButton.addEventListener('click', () => {
console.log("์žฅ์น˜ ์ƒํƒœ ํ™•์ธ ๋ฒ„ํŠผ ํด๋ฆญ");
checkDeviceStatus();
});
// ์žฅ์น˜ ๋ชฉ๋ก ์ƒˆ๋กœ๊ณ ์นจ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ
refreshDevicesButton.addEventListener('click', () => {
console.log("์žฅ์น˜ ๋ชฉ๋ก ์ƒˆ๋กœ๊ณ ์นจ ๋ฒ„ํŠผ ํด๋ฆญ");
loadDevices();
});
// ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ๋กœ๋“œ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ
loadProgramsButton.addEventListener('click', () => {
console.log("ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ๋กœ๋“œ ๋ฒ„ํŠผ ํด๋ฆญ");
loadPrograms();
});
});
/**
* ์—๋Ÿฌ ์ฒ˜๋ฆฌ ํ—ฌํผ ํ•จ์ˆ˜
* @param {Error} error - ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜
* @returns {string} - ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œํ•  ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€
*/
function handleError(error) {
console.error("์˜ค๋ฅ˜ ๋ฐœ์ƒ:", error);
if (error.name === 'AbortError') {
return '์š”์ฒญ ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ์‘๋‹ตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.';
}
if (error.message && (error.message.includes('NetworkError') || error.message.includes('Failed to fetch'))) {
return '๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.';
}
return `์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: ${error.message || '์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜'}`;
}
/**
* HTML ์ด์Šค์ผ€์ดํ”„ ํ•จ์ˆ˜ (XSS ๋ฐฉ์ง€)
* @param {string} unsafe - ์ด์Šค์ผ€์ดํ”„ ์ „ ๋ฌธ์ž์—ด
* @returns {string} - ์ด์Šค์ผ€์ดํ”„ ํ›„ ๋ฌธ์ž์—ด
*/
function escapeHtml(unsafe) {
if (typeof unsafe !== 'string') return unsafe;
return unsafe
.replace(/&/g, "&")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
/**
* ์žฅ์น˜ ๊ด€๋ฆฌ ์„œ๋ฒ„ ์ƒํƒœ ํ™•์ธ ํ•จ์ˆ˜ - ์ „์—ญ ํ•จ์ˆ˜๋กœ export
*/
async function checkDeviceStatus() {
console.log("์žฅ์น˜ ์ƒํƒœ ํ™•์ธ ์ค‘...");
// UI ์—…๋ฐ์ดํŠธ
deviceStatusResult.classList.add('hidden');
deviceStatusLoading.classList.remove('hidden');
try {
// ํƒ€์ž„์•„์›ƒ ์„ค์ •์„ ์œ„ํ•œ ์ปจํŠธ๋กค๋Ÿฌ
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5์ดˆ ํƒ€์ž„์•„์›ƒ
// API ์š”์ฒญ - ์ˆ˜์ •๋œ URL ๊ตฌ์„ฑ ์‚ฌ์šฉ
const response = await fetch(getDeviceApiUrl('/api/status'), {
signal: controller.signal
});
clearTimeout(timeoutId); // ํƒ€์ž„์•„์›ƒ ํ•ด์ œ
// ์‘๋‹ต ์ฒ˜๋ฆฌ
if (!response.ok) {
throw new Error(`HTTP ์˜ค๋ฅ˜: ${response.status}`);
}
const data = await response.json();
console.log("์žฅ์น˜ ์ƒํƒœ ์‘๋‹ต:", data);
// UI ์—…๋ฐ์ดํŠธ
deviceStatusLoading.classList.add('hidden');
deviceStatusResult.classList.remove('hidden');
if (data.status === "online") {
// ์˜จ๋ผ์ธ ์ƒํƒœ์ธ ๊ฒฝ์šฐ
statusIcon.innerHTML = '<i class="fas fa-circle online"></i>';
statusText.textContent = `์„œ๋ฒ„ ์ƒํƒœ: ${data.status || '์ •์ƒ'}`;
// ์ž๋™์œผ๋กœ ์žฅ์น˜ ๋ชฉ๋ก ๋กœ๋“œ
loadDevices();
} else {
// ์˜คํ”„๋ผ์ธ ๋˜๋Š” ์˜ค๋ฅ˜ ์ƒํƒœ์ธ ๊ฒฝ์šฐ
statusIcon.innerHTML = '<i class="fas fa-circle offline"></i>';
statusText.textContent = `์„œ๋ฒ„ ์˜ค๋ฅ˜: ${data.error || '์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜'}`;
}
} catch (error) {
console.error("์žฅ์น˜ ์ƒํƒœ ํ™•์ธ ์˜ค๋ฅ˜:", error);
// UI ์—…๋ฐ์ดํŠธ
deviceStatusLoading.classList.add('hidden');
deviceStatusResult.classList.remove('hidden');
statusIcon.innerHTML = '<i class="fas fa-circle offline"></i>';
statusText.textContent = handleError(error);
}
}
/**
* ์žฅ์น˜ ๋ชฉ๋ก ๋กœ๋“œ ํ•จ์ˆ˜
*/
async function loadDevices() {
console.log("์žฅ์น˜ ๋ชฉ๋ก ๋กœ๋“œ ์ค‘...");
// UI ์—…๋ฐ์ดํŠธ
deviceList.innerHTML = '';
noDevicesMessage.classList.add('hidden');
devicesLoading.classList.remove('hidden');
try {
// ํƒ€์ž„์•„์›ƒ ์„ค์ •์„ ์œ„ํ•œ ์ปจํŠธ๋กค๋Ÿฌ
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5์ดˆ ํƒ€์ž„์•„์›ƒ
// API ์š”์ฒญ - ์ˆ˜์ •๋œ URL ๊ตฌ์„ฑ ์‚ฌ์šฉ
const response = await fetch(getDeviceApiUrl('/api/devices'), {
signal: controller.signal
});
clearTimeout(timeoutId); // ํƒ€์ž„์•„์›ƒ ํ•ด์ œ
// ์‘๋‹ต ์ฒ˜๋ฆฌ
if (!response.ok) {
throw new Error(`HTTP ์˜ค๋ฅ˜: ${response.status}`);
}
const data = await response.json();
console.log("์žฅ์น˜ ๋ชฉ๋ก ์‘๋‹ต:", data);
// UI ์—…๋ฐ์ดํŠธ
devicesLoading.classList.add('hidden');
if (data.devices && data.devices.length > 0) {
// ์žฅ์น˜ ๋ชฉ๋ก ํ‘œ์‹œ
data.devices.forEach(device => {
const deviceElement = createDeviceItem(device);
deviceList.appendChild(deviceElement);
});
} else {
// ์žฅ์น˜ ์—†์Œ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ
noDevicesMessage.classList.remove('hidden');
}
} catch (error) {
console.error("์žฅ์น˜ ๋ชฉ๋ก ๋กœ๋“œ ์˜ค๋ฅ˜:", error);
// UI ์—…๋ฐ์ดํŠธ
devicesLoading.classList.add('hidden');
noDevicesMessage.classList.remove('hidden');
noDevicesMessage.textContent = handleError(error);
}
}
/**
* ์žฅ์น˜ ์•„์ดํ…œ ์ƒ์„ฑ ํ•จ์ˆ˜
* @param {Object} device - ์žฅ์น˜ ์ •๋ณด ๊ฐ์ฒด
* @returns {HTMLElement} - ์žฅ์น˜ ์•„์ดํ…œ DOM ์š”์†Œ
*/
function createDeviceItem(device) {
const deviceItem = document.createElement('div');
deviceItem.classList.add('device-item');
// ์ƒํƒœ์— ๋”ฐ๋ฅธ ํด๋ž˜์Šค ์ถ”๊ฐ€
if (device.status === 'online' || device.status === '์˜จ๋ผ์ธ') {
deviceItem.classList.add('online');
} else if (device.status === 'offline' || device.status === '์˜คํ”„๋ผ์ธ') {
deviceItem.classList.add('offline');
} else if (device.status === 'warning' || device.status === '๊ฒฝ๊ณ ') {
deviceItem.classList.add('warning');
}
// ์žฅ์น˜ ํ—ค๋” (์ด๋ฆ„ ๋ฐ ์ƒํƒœ)
const deviceHeader = document.createElement('div');
deviceHeader.classList.add('device-item-header');
const deviceName = document.createElement('div');
deviceName.classList.add('device-name');
deviceName.textContent = device.name || '์•Œ ์ˆ˜ ์—†๋Š” ์žฅ์น˜';
const deviceStatusBadge = document.createElement('div');
deviceStatusBadge.classList.add('device-status-badge');
// ์ƒํƒœ์— ๋”ฐ๋ฅธ ๋ฐฐ์ง€ ์„ค์ •
if (device.status === 'online' || device.status === '์˜จ๋ผ์ธ') {
deviceStatusBadge.classList.add('online');
deviceStatusBadge.textContent = '์˜จ๋ผ์ธ';
} else if (device.status === 'offline' || device.status === '์˜คํ”„๋ผ์ธ') {
deviceStatusBadge.classList.add('offline');
deviceStatusBadge.textContent = '์˜คํ”„๋ผ์ธ';
} else if (device.status === 'warning' || device.status === '๊ฒฝ๊ณ ') {
deviceStatusBadge.classList.add('warning');
deviceStatusBadge.textContent = '๊ฒฝ๊ณ ';
} else {
deviceStatusBadge.textContent = device.status || '์•Œ ์ˆ˜ ์—†์Œ';
}
deviceHeader.appendChild(deviceName);
deviceHeader.appendChild(deviceStatusBadge);
// ์žฅ์น˜ ์ •๋ณด
const deviceInfo = document.createElement('div');
deviceInfo.classList.add('device-info');
deviceInfo.textContent = `์œ ํ˜•: ${device.type || '์•Œ ์ˆ˜ ์—†์Œ'}`;
// ์žฅ์น˜ ์„ธ๋ถ€ ์ •๋ณด
const deviceDetails = document.createElement('div');
deviceDetails.classList.add('device-details');
// ์ถ”๊ฐ€ ์ •๋ณด๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ํ‘œ์‹œ
if (device.ip) {
deviceDetails.textContent += `IP: ${device.ip}`;
}
if (device.mac) {
deviceDetails.textContent += (deviceDetails.textContent ? ', ' : '') + `MAC: ${device.mac}`;
}
if (device.lastSeen) {
deviceDetails.textContent += (deviceDetails.textContent ? ', ' : '') + `๋งˆ์ง€๋ง‰ ํ™œ๋™: ${device.lastSeen}`;
}
// ์•„์ดํ…œ์— ์š”์†Œ ์ถ”๊ฐ€
deviceItem.appendChild(deviceHeader);
deviceItem.appendChild(deviceInfo);
if (deviceDetails.textContent) {
deviceItem.appendChild(deviceDetails);
}
return deviceItem;
}
/**
* ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ๋กœ๋“œ ํ•จ์ˆ˜
*/
async function loadPrograms() {
console.log("ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ๋กœ๋“œ ์ค‘...");
// UI ์—…๋ฐ์ดํŠธ
programsList.innerHTML = '';
noProgramsMessage.classList.add('hidden');
programsLoading.classList.remove('hidden');
try {
// ํƒ€์ž„์•„์›ƒ ์„ค์ •์„ ์œ„ํ•œ ์ปจํŠธ๋กค๋Ÿฌ
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5์ดˆ ํƒ€์ž„์•„์›ƒ
// API ์š”์ฒญ - ์ˆ˜์ •๋œ URL ๊ตฌ์„ฑ ์‚ฌ์šฉ
const response = await fetch(getDeviceApiUrl('/api/programs'), {
signal: controller.signal
});
clearTimeout(timeoutId); // ํƒ€์ž„์•„์›ƒ ํ•ด์ œ
// ์‘๋‹ต ์ฒ˜๋ฆฌ
if (!response.ok) {
throw new Error(`HTTP ์˜ค๋ฅ˜: ${response.status}`);
}
const data = await response.json();
console.log("ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ์‘๋‹ต:", data);
// UI ์—…๋ฐ์ดํŠธ
programsLoading.classList.add('hidden');
if (data.programs && data.programs.length > 0) {
// ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ํ‘œ์‹œ
data.programs.forEach(program => {
const programElement = createProgramItem(program);
programsList.appendChild(programElement);
});
} else {
// ํ”„๋กœ๊ทธ๋žจ ์—†์Œ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ
noProgramsMessage.classList.remove('hidden');
}
} catch (error) {
console.error("ํ”„๋กœ๊ทธ๋žจ ๋ชฉ๋ก ๋กœ๋“œ ์˜ค๋ฅ˜:", error);
// UI ์—…๋ฐ์ดํŠธ
programsLoading.classList.add('hidden');
noProgramsMessage.classList.remove('hidden');
noProgramsMessage.textContent = handleError(error);
}
}
/**
* ํ”„๋กœ๊ทธ๋žจ ์•„์ดํ…œ ์ƒ์„ฑ ํ•จ์ˆ˜
* @param {Object} program - ํ”„๋กœ๊ทธ๋žจ ์ •๋ณด ๊ฐ์ฒด
* @returns {HTMLElement} - ํ”„๋กœ๊ทธ๋žจ ์•„์ดํ…œ DOM ์š”์†Œ
*/
function createProgramItem(program) {
const programItem = document.createElement('div');
programItem.classList.add('program-item');
// ํ”„๋กœ๊ทธ๋žจ ํ—ค๋” (์ด๋ฆ„)
const programHeader = document.createElement('div');
programHeader.classList.add('program-item-header');
const programName = document.createElement('div');
programName.classList.add('program-name');
programName.textContent = program.name || '์•Œ ์ˆ˜ ์—†๋Š” ํ”„๋กœ๊ทธ๋žจ';
programHeader.appendChild(programName);
// ํ”„๋กœ๊ทธ๋žจ ์„ค๋ช…
if (program.description) {
const programDescription = document.createElement('div');
programDescription.classList.add('program-description');
programDescription.textContent = program.description;
programItem.appendChild(programDescription);
}
// ์‹คํ–‰ ๋ฒ„ํŠผ
const executeButton = document.createElement('button');
executeButton.classList.add('execute-btn');
executeButton.textContent = '์‹คํ–‰';
executeButton.addEventListener('click', () => {
executeProgram(program.id, program.name);
});
// ์•„์ดํ…œ์— ์š”์†Œ ์ถ”๊ฐ€
programItem.appendChild(programHeader);
programItem.appendChild(executeButton);
return programItem;
}
/**
* ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ํ•จ์ˆ˜
* @param {string} programId - ์‹คํ–‰ํ•  ํ”„๋กœ๊ทธ๋žจ ID
* @param {string} programName - ํ”„๋กœ๊ทธ๋žจ ์ด๋ฆ„ (์•Œ๋ฆผ์šฉ)
*/
async function executeProgram(programId, programName) {
if (!programId) return;
console.log(`ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์š”์ฒญ: ${programId} (${programName})`);
// ์‹คํ–‰ ํ™•์ธ
if (!confirm(`'${programName}' ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?`)) {
console.log('ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์ทจ์†Œ๋จ');
return;
}
try {
// ๋กœ๋”ฉ ์•Œ๋ฆผ ํ‘œ์‹œ
showNotification(`'${programName}' ์‹คํ–‰ ์ค‘...`, 'info');
// API ์š”์ฒญ - ์ˆ˜์ •๋œ URL ๊ตฌ์„ฑ ์‚ฌ์šฉ
const response = await fetch(getDeviceApiUrl(`/api/programs/${programId}/execute`), {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({}) // ํ•„์š” ์‹œ ์ถ”๊ฐ€ ํŒŒ๋ผ๋ฏธํ„ฐ ์ „๋‹ฌ
});
// ์‘๋‹ต ์ฒ˜๋ฆฌ
if (!response.ok) {
throw new Error(`HTTP ์˜ค๋ฅ˜: ${response.status}`);
}
const data = await response.json();
console.log(`ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‘๋‹ต:`, data);
// ๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ
if (data.success) {
showNotification(`'${programName}' ์‹คํ–‰ ์„ฑ๊ณต: ${data.message}`, 'success');
} else {
showNotification(`'${programName}' ์‹คํ–‰ ์‹คํŒจ: ${data.message || '์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜'}`, 'error');
}
} catch (error) {
console.error(`ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์˜ค๋ฅ˜ (${programId}):`, error);
showNotification(`'${programName}' ์‹คํ–‰ ์˜ค๋ฅ˜: ${handleError(error)}`, 'error');
}
}
/**
* ์•Œ๋ฆผ ํ‘œ์‹œ ํ•จ์ˆ˜
* @param {string} message - ์•Œ๋ฆผ ๋ฉ”์‹œ์ง€
* @param {string} type - ์•Œ๋ฆผ ์œ ํ˜• ('success', 'error', 'warning')
*/
function showNotification(message, type = 'info') {
// ๊ธฐ์กด ์•Œ๋ฆผ์ด ์žˆ์œผ๋ฉด ์ œ๊ฑฐ
const existingNotification = document.querySelector('.notification');
if (existingNotification) {
existingNotification.remove();
}
// ์ƒˆ ์•Œ๋ฆผ ์ƒ์„ฑ
const notification = document.createElement('div');
notification.classList.add('notification', type);
notification.textContent = message;
// ์•Œ๋ฆผ ๋‹ซ๊ธฐ ๋ฒ„ํŠผ
const closeButton = document.createElement('button');
closeButton.classList.add('notification-close');
closeButton.innerHTML = '&times;';
closeButton.addEventListener('click', () => {
notification.remove();
});
notification.appendChild(closeButton);
// ๋ฌธ์„œ์— ์•Œ๋ฆผ ์ถ”๊ฐ€
document.body.appendChild(notification);
// ์ผ์ • ์‹œ๊ฐ„ ํ›„ ์ž๋™์œผ๋กœ ์‚ฌ๋ผ์ง€๋„๋ก ์„ค์ •
setTimeout(() => {
if (document.body.contains(notification)) {
notification.remove();
}
}, 5000); // 5์ดˆ ํ›„ ์‚ฌ๋ผ์ง
}
// checkDeviceStatus ํ•จ์ˆ˜๋ฅผ ์ „์—ญ์œผ๋กœ ๋…ธ์ถœ
window.checkDeviceStatus = checkDeviceStatus;