// System Dashboard JavaScript
console.log('π system-dashboard.js loaded');
import { apiRequest } from './api-helper.js';
import { getCurrentUser } from './auth.js';
console.log('π¦ modules imported successfully');
// μ μ λ³μ
let systemData = {
users: [],
logs: [],
systemStatus: {}
};
// Initialize on page load
document.addEventListener('DOMContentLoaded', function() {
console.log('π DOM loaded, starting initialization');
initializeSystemDashboard();
setupEventListeners();
});
// Setup event listeners
function setupEventListeners() {
// Add event listeners to all data-action buttons
const actionButtons = document.querySelectorAll('[data-action]');
actionButtons.forEach(button => {
const action = button.getAttribute('data-action');
switch(action) {
case 'account-management':
button.addEventListener('click', openAccountManagement);
console.log('β
Account management button listener added');
break;
case 'system-logs':
button.addEventListener('click', openSystemLogs);
console.log('β
System logs button listener added');
break;
case 'database-management':
button.addEventListener('click', openDatabaseManagement);
console.log('β
Database management button listener added');
break;
case 'system-settings':
button.addEventListener('click', openSystemSettings);
console.log('β
System settings button listener added');
break;
case 'backup-management':
button.addEventListener('click', openBackupManagement);
console.log('β
Backup management button listener added');
break;
case 'monitoring':
button.addEventListener('click', openMonitoring);
console.log('β
Monitoring button listener added');
break;
case 'close-modal':
button.addEventListener('click', () => closeModal('account-modal'));
console.log('β
Modal close button listener added');
break;
}
});
console.log(`π― Total ${actionButtons.length} event listeners setup completed`);
}
// Initialize system dashboard
async function initializeSystemDashboard() {
try {
console.log('π Starting system dashboard initialization...');
// Load user info
await loadUserInfo();
console.log('β
User info loaded');
// Load system status
await loadSystemStatus();
console.log('β
System status loaded');
// Load user statistics
await loadUserStats();
console.log('β
User statistics loaded');
// Load recent activities
await loadRecentActivities();
console.log('β
Recent activities loaded');
// Setup auto-refresh (every 30 seconds)
setInterval(refreshSystemStatus, 30000);
console.log('π System dashboard initialization completed');
} catch (error) {
console.error('β System dashboard initialization error:', error);
showNotification('Error loading system dashboard', 'error');
}
}
// μ¬μ©μ μ 보 λ‘λ
async function loadUserInfo() {
try {
const user = getCurrentUser();
if (user && user.name) {
document.getElementById('user-name').textContent = user.name;
}
} catch (error) {
console.error('μ¬μ©μ μ 보 λ‘λ μ€λ₯:', error);
}
}
// μμ€ν
μν λ‘λ
async function loadSystemStatus() {
try {
// μλ² μν νμΈ
const serverStatus = await checkServerStatus();
updateServerStatus(serverStatus);
// λ°μ΄ν°λ² μ΄μ€ μν νμΈ
const dbStatus = await checkDatabaseStatus();
updateDatabaseStatus(dbStatus);
// μμ€ν
μλ¦Ό νμΈ
const alerts = await getSystemAlerts();
updateSystemAlerts(alerts);
} catch (error) {
console.error('μμ€ν
μν λ‘λ μ€λ₯:', error);
}
}
// μλ² μν νμΈ
async function checkServerStatus() {
try {
const response = await apiRequest('/api/system/status', 'GET');
return response.success ? 'online' : 'offline';
} catch (error) {
return 'offline';
}
}
// λ°μ΄ν°λ² μ΄μ€ μν νμΈ
async function checkDatabaseStatus() {
try {
const response = await apiRequest('/api/system/db-status', 'GET');
return response;
} catch (error) {
return { status: 'error', connections: 0 };
}
}
// μμ€ν
μλ¦Ό κ°μ Έμ€κΈ°
async function getSystemAlerts() {
try {
const response = await apiRequest('/api/system/alerts', 'GET');
return response.alerts || [];
} catch (error) {
return [];
}
}
// μλ² μν μ
λ°μ΄νΈ
function updateServerStatus(status) {
const serverCheckTime = document.getElementById('server-check-time');
const statusElements = document.querySelectorAll('.status-value');
if (serverCheckTime) {
serverCheckTime.textContent = new Date().toLocaleTimeString('ko-KR');
}
// μλ² μν νμ μ
λ°μ΄νΈ λ‘μ§ μΆκ°
}
// λ°μ΄ν°λ² μ΄μ€ μν μ
λ°μ΄νΈ
function updateDatabaseStatus(dbStatus) {
const dbConnections = document.getElementById('db-connections');
if (dbConnections && dbStatus.connections !== undefined) {
dbConnections.textContent = dbStatus.connections;
}
}
// μμ€ν
μλ¦Ό μ
λ°μ΄νΈ
function updateSystemAlerts(alerts) {
const systemAlerts = document.getElementById('system-alerts');
if (systemAlerts) {
systemAlerts.textContent = alerts.length;
systemAlerts.className = `status-value ${alerts.length > 0 ? 'warning' : 'online'}`;
}
}
// μ¬μ©μ ν΅κ³ λ‘λ
async function loadUserStats() {
try {
const response = await apiRequest('/api/system/users/stats', 'GET');
if (response.success) {
const activeUsers = document.getElementById('active-users');
const totalUsers = document.getElementById('total-users');
if (activeUsers) activeUsers.textContent = response.data.active || 0;
if (totalUsers) totalUsers.textContent = response.data.total || 0;
}
} catch (error) {
console.error('μ¬μ©μ ν΅κ³ λ‘λ μ€λ₯:', error);
}
}
// μ΅κ·Ό νλ λ‘λ
async function loadRecentActivities() {
try {
const response = await apiRequest('/api/system/recent-activities', 'GET');
if (response.success && response.data) {
displayRecentActivities(response.data);
}
} catch (error) {
console.error('μ΅κ·Ό νλ λ‘λ μ€λ₯:', error);
displayDefaultActivities();
}
}
// μ΅κ·Ό νλ νμ
function displayRecentActivities(activities) {
const container = document.getElementById('recent-activities');
if (!container) return;
if (!activities || activities.length === 0) {
container.innerHTML = '
μ΅κ·Ό νλμ΄ μμ΅λλ€.
';
return;
}
const html = activities.map(activity => `
${activity.title}
${activity.description}
${formatTimeAgo(activity.created_at)}
`).join('');
container.innerHTML = html;
}
// κΈ°λ³Έ νλ νμ (λ°μ΄ν° λ‘λ μ€ν¨ μ)
function displayDefaultActivities() {
const container = document.getElementById('recent-activities');
if (!container) return;
const defaultActivities = [
{
type: 'system',
title: 'μμ€ν
μμ',
description: 'μμ€ν
μ΄ μ μμ μΌλ‘ μμλμμ΅λλ€.',
created_at: new Date().toISOString()
}
];
displayRecentActivities(defaultActivities);
}
// νλ νμ
μ λ°λ₯Έ μμ΄μ½ λ°ν
function getActivityIcon(type) {
const icons = {
'login': 'fa-sign-in-alt',
'user_create': 'fa-user-plus',
'user_update': 'fa-user-edit',
'user_delete': 'fa-user-minus',
'system': 'fa-cog',
'database': 'fa-database',
'backup': 'fa-download',
'error': 'fa-exclamation-triangle'
};
return icons[type] || 'fa-info-circle';
}
// μκ° ν¬λ§·ν
(λͺ λΆ μ , λͺ μκ° μ λ±)
function formatTimeAgo(dateString) {
const now = new Date();
const date = new Date(dateString);
const diffInSeconds = Math.floor((now - date) / 1000);
if (diffInSeconds < 60) {
return 'λ°©κΈ μ ';
} else if (diffInSeconds < 3600) {
return `${Math.floor(diffInSeconds / 60)}λΆ μ `;
} else if (diffInSeconds < 86400) {
return `${Math.floor(diffInSeconds / 3600)}μκ° μ `;
} else {
return `${Math.floor(diffInSeconds / 86400)}μΌ μ `;
}
}
// μμ€ν
μν μλ‘κ³ μΉ¨
async function refreshSystemStatus() {
try {
await loadSystemStatus();
await loadUserStats();
} catch (error) {
console.error('μμ€ν
μν μλ‘κ³ μΉ¨ μ€λ₯:', error);
}
}
// Open account management
function openAccountManagement() {
console.log('π― Account management button clicked');
const modal = document.getElementById('account-modal');
const content = document.getElementById('account-management-content');
console.log('Modal element:', modal);
console.log('Content element:', content);
if (modal && content) {
console.log('β
Modal and content elements found, loading content...');
// Load account management content
loadAccountManagementContent(content);
modal.style.display = 'block';
console.log('β
Modal displayed');
} else {
console.error('β Modal or content element not found');
}
}
// κ³μ κ΄λ¦¬ 컨ν
μΈ λ‘λ
async function loadAccountManagementContent(container) {
try {
container.innerHTML = `
λ‘λ© μ€...
`;
// μ¬μ©μ λͺ©λ‘ λ‘λ
const response = await apiRequest('/api/system/users', 'GET');
if (response.success) {
displayAccountManagement(container, response.data);
} else {
throw new Error(response.error || 'μ¬μ©μ λͺ©λ‘μ λΆλ¬μ¬ μ μμ΅λλ€.');
}
} catch (error) {
console.error('κ³μ κ΄λ¦¬ 컨ν
μΈ λ‘λ μ€λ₯:', error);
container.innerHTML = `
κ³μ μ 보λ₯Ό λΆλ¬μ€λ μ€ μ€λ₯κ° λ°μνμ΅λλ€.
`;
}
}
// κ³μ κ΄λ¦¬ νλ©΄ νμ
function displayAccountManagement(container, users) {
const html = `
`;
container.innerHTML = html;
systemData.users = users;
}
// μ¬μ©μ ν
μ΄λΈ ν μμ±
function generateUsersTableRows(users) {
if (!users || users.length === 0) {
return '| λ±λ‘λ μ¬μ©μκ° μμ΅λλ€. |
';
}
return users.map(user => `
| ${user.user_id} |
${user.username} |
${user.name || '-'} |
${getRoleDisplayName(user.role)}
|
${user.is_active ? 'νμ±' : 'λΉνμ±'}
|
${user.last_login_at ? formatDate(user.last_login_at) : 'μμ'} |
|
`).join('');
}
// κΆν νμλͺ
λ°ν
function getRoleDisplayName(role) {
const roleNames = {
'system': 'μμ€ν
',
'admin': 'κ΄λ¦¬μ',
'leader': 'κ·Έλ£Ήμ₯',
'user': 'μ¬μ©μ'
};
return roleNames[role] || role;
}
// λ μ§ ν¬λ§·ν
function formatDate(dateString) {
if (!dateString) return '-';
const date = new Date(dateString);
return date.toLocaleString('ko-KR');
}
// μμ€ν
λ‘κ·Έ μ΄κΈ°
function openSystemLogs() {
console.log('μμ€ν
λ‘κ·Έ λ²νΌ ν΄λ¦λ¨');
const modal = document.getElementById('account-modal');
const content = document.getElementById('account-management-content');
if (modal && content) {
loadSystemLogsContent(content);
modal.style.display = 'block';
}
}
// μμ€ν
λ‘κ·Έ 컨ν
μΈ λ‘λ
async function loadSystemLogsContent(container) {
try {
container.innerHTML = `
`;
// λ‘κ·Έ λ°μ΄ν° λ‘λ
await loadLogsData();
} catch (error) {
console.error('μμ€ν
λ‘κ·Έ λ‘λ μ€λ₯:', error);
container.innerHTML = `
μμ€ν
λ‘κ·Έλ₯Ό λΆλ¬μ€λ μ€ μ€λ₯κ° λ°μνμ΅λλ€.
`;
}
}
// λ‘κ·Έ λ°μ΄ν° λ‘λ
async function loadLogsData() {
try {
const response = await apiRequest('/api/system/logs/activity', 'GET');
const logsContainer = document.querySelector('.logs-container');
if (response.success && response.data) {
displayLogs(response.data, logsContainer);
} else {
logsContainer.innerHTML = 'λ‘κ·Έ λ°μ΄ν°κ° μμ΅λλ€.
';
}
} catch (error) {
console.error('λ‘κ·Έ λ°μ΄ν° λ‘λ μ€λ₯:', error);
document.querySelector('.logs-container').innerHTML = 'λ‘κ·Έ λ°μ΄ν°λ₯Ό λΆλ¬μ¬ μ μμ΅λλ€.
';
}
}
// λ‘κ·Έ νμ
function displayLogs(logs, container) {
if (!logs || logs.length === 0) {
container.innerHTML = 'νμν λ‘κ·Έκ° μμ΅λλ€.
';
return;
}
const html = `
| μκ° |
μ ν |
μ¬μ©μ |
λ΄μ© |
${logs.map(log => `
| ${formatDate(log.created_at)} |
${log.type} |
${log.username || '-'} |
${log.description} |
`).join('')}
`;
container.innerHTML = html;
}
// λ‘κ·Έ νν°λ§
function filterLogs() {
console.log('λ‘κ·Έ νν°λ§ μ€ν');
// μ€μ ꡬνμ μΆν μΆκ°
showNotification('λ‘κ·Έ νν°λ§ κΈ°λ₯μ κ°λ° μ€μ
λλ€.', 'info');
}
// λ°μ΄ν°λ² μ΄μ€ κ΄λ¦¬ μ΄κΈ°
function openDatabaseManagement() {
console.log('λ°μ΄ν°λ² μ΄μ€ κ΄λ¦¬ λ²νΌ ν΄λ¦λ¨');
showNotification('λ°μ΄ν°λ² μ΄μ€ κ΄λ¦¬ κΈ°λ₯μ κ°λ° μ€μ
λλ€.', 'info');
}
// μμ€ν
μ€μ μ΄κΈ°
function openSystemSettings() {
console.log('μμ€ν
μ€μ λ²νΌ ν΄λ¦λ¨');
showNotification('μμ€ν
μ€μ κΈ°λ₯μ κ°λ° μ€μ
λλ€.', 'info');
}
// λ°±μ
κ΄λ¦¬ μ΄κΈ°
function openBackupManagement() {
console.log('λ°±μ
κ΄λ¦¬ λ²νΌ ν΄λ¦λ¨');
showNotification('λ°±μ
κ΄λ¦¬ κΈ°λ₯μ κ°λ° μ€μ
λλ€.', 'info');
}
// λͺ¨λν°λ§ μ΄κΈ°
function openMonitoring() {
console.log('λͺ¨λν°λ§ λ²νΌ ν΄λ¦λ¨');
showNotification('λͺ¨λν°λ§ κΈ°λ₯μ κ°λ° μ€μ
λλ€.', 'info');
}
// λͺ¨λ¬ λ«κΈ°
function closeModal(modalId) {
const modal = document.getElementById(modalId);
if (modal) {
modal.style.display = 'none';
}
}
// λ‘κ·Έμμ
function logout() {
if (confirm('λ‘κ·Έμμ νμκ² μ΅λκΉ?')) {
localStorage.removeItem('token');
localStorage.removeItem('user');
window.location.href = '/';
}
}
// μλ¦Ό νμ
function showNotification(message, type = 'info') {
// κ°λ¨ν μλ¦Ό νμ (λμ€μ ν μ€νΈ λΌμ΄λΈλ¬λ¦¬λ‘ κ΅μ²΄ κ°λ₯)
const notification = document.createElement('div');
notification.className = `notification notification-${type}`;
notification.textContent = message;
document.body.appendChild(notification);
setTimeout(() => {
notification.remove();
}, 5000);
}
// μ¬μ©μ νΈμ§
async function editUser(userId) {
try {
// μ¬μ©μ μ 보 κ°μ Έμ€κΈ°
const response = await apiRequest(`/api/system/users`, 'GET');
if (!response.success) {
throw new Error('μ¬μ©μ μ 보λ₯Ό κ°μ Έμ¬ μ μμ΅λλ€.');
}
const user = response.data.find(u => u.user_id === userId);
if (!user) {
throw new Error('ν΄λΉ μ¬μ©μλ₯Ό μ°Ύμ μ μμ΅λλ€.');
}
// νΈμ§ νΌ νμ
showUserEditForm(user);
} catch (error) {
console.error('μ¬μ©μ νΈμ§ μ€λ₯:', error);
showNotification('μ¬μ©μ μ 보λ₯Ό λΆλ¬μ€λ μ€ μ€λ₯κ° λ°μνμ΅λλ€.', 'error');
}
}
// μ¬μ©μ νΈμ§ νΌ νμ
function showUserEditForm(user) {
const formHtml = `
`;
const container = document.getElementById('account-management-content');
container.innerHTML = formHtml;
// νΌ μ μΆ μ΄λ²€νΈ 리μ€λ
document.getElementById('edit-user-form').addEventListener('submit', async (e) => {
e.preventDefault();
await updateUser(user.user_id);
});
}
// μ¬μ©μ μ 보 μ
λ°μ΄νΈ
async function updateUser(userId) {
try {
const formData = {
name: document.getElementById('edit-name').value,
email: document.getElementById('edit-email').value || null,
role: document.getElementById('edit-role').value,
access_level: document.getElementById('edit-role').value,
is_active: parseInt(document.getElementById('edit-is-active').value),
worker_id: document.getElementById('edit-worker-id').value || null
};
const response = await apiRequest(`/api/system/users/${userId}`, 'PUT', formData);
if (response.success) {
showNotification('μ¬μ©μ μ λ³΄κ° μ±κ³΅μ μΌλ‘ μ
λ°μ΄νΈλμμ΅λλ€.', 'success');
closeModal('account-modal');
// κ³μ κ΄λ¦¬ λ€μ λ‘λ
setTimeout(() => openAccountManagement(), 500);
} else {
throw new Error(response.error || 'μ
λ°μ΄νΈμ μ€ν¨νμ΅λλ€.');
}
} catch (error) {
console.error('μ¬μ©μ μ
λ°μ΄νΈ μ€λ₯:', error);
showNotification('μ¬μ©μ μ 보 μ
λ°μ΄νΈ μ€ μ€λ₯κ° λ°μνμ΅λλ€.', 'error');
}
}
// μ¬μ©μ μμ
async function deleteUser(userId) {
try {
// μ¬μ©μ μ 보 κ°μ Έμ€κΈ°
const response = await apiRequest(`/api/system/users`, 'GET');
if (!response.success) {
throw new Error('μ¬μ©μ μ 보λ₯Ό κ°μ Έμ¬ μ μμ΅λλ€.');
}
const user = response.data.find(u => u.user_id === userId);
if (!user) {
throw new Error('ν΄λΉ μ¬μ©μλ₯Ό μ°Ύμ μ μμ΅λλ€.');
}
// μμ νμΈ
if (!confirm(`μ λ§λ‘ μ¬μ©μ '${user.username}'λ₯Ό μμ νμκ² μ΅λκΉ?\n\nμ΄ μμ
μ λλ릴 μ μμ΅λλ€.`)) {
return;
}
// μ¬μ©μ μμ μμ²
const deleteResponse = await apiRequest(`/api/system/users/${userId}`, 'DELETE');
if (deleteResponse.success) {
showNotification('μ¬μ©μκ° μ±κ³΅μ μΌλ‘ μμ λμμ΅λλ€.', 'success');
// κ³μ κ΄λ¦¬ λ€μ λ‘λ
setTimeout(() => {
const container = document.getElementById('account-management-content');
if (container) {
loadAccountManagementContent(container);
}
}, 500);
} else {
throw new Error(deleteResponse.error || 'μμ μ μ€ν¨νμ΅λλ€.');
}
} catch (error) {
console.error('μ¬μ©μ μμ μ€λ₯:', error);
showNotification('μ¬μ©μ μμ μ€ μ€λ₯κ° λ°μνμ΅λλ€.', 'error');
}
}
// μ μ¬μ©μ μμ± νΌ μ΄κΈ°
function openCreateUserForm() {
const formHtml = `
`;
const container = document.getElementById('account-management-content');
container.innerHTML = formHtml;
// νΌ μ μΆ μ΄λ²€νΈ 리μ€λ
document.getElementById('create-user-form').addEventListener('submit', async (e) => {
e.preventDefault();
await createUser();
});
}
// μ μ¬μ©μ μμ±
async function createUser() {
try {
const formData = {
username: document.getElementById('create-username').value,
password: document.getElementById('create-password').value,
name: document.getElementById('create-name').value,
email: document.getElementById('create-email').value || null,
role: document.getElementById('create-role').value,
access_level: document.getElementById('create-role').value,
worker_id: document.getElementById('create-worker-id').value || null
};
const response = await apiRequest('/api/system/users', 'POST', formData);
if (response.success) {
showNotification('μ μ¬μ©μκ° μ±κ³΅μ μΌλ‘ μμ±λμμ΅λλ€.', 'success');
// κ³μ κ΄λ¦¬ λͺ©λ‘μΌλ‘ λμκ°κΈ°
setTimeout(() => {
const container = document.getElementById('account-management-content');
loadAccountManagementContent(container);
}, 500);
} else {
throw new Error(response.error || 'μ¬μ©μ μμ±μ μ€ν¨νμ΅λλ€.');
}
} catch (error) {
console.error('μ¬μ©μ μμ± μ€λ₯:', error);
showNotification('μ¬μ©μ μμ± μ€ μ€λ₯κ° λ°μνμ΅λλ€.', 'error');
}
}
// μ¬μ©μ νν°λ§
function filterUsers() {
const searchTerm = document.getElementById('user-search').value.toLowerCase();
const roleFilter = document.getElementById('role-filter').value;
const rows = document.querySelectorAll('#users-tbody tr');
rows.forEach(row => {
const username = row.cells[1].textContent.toLowerCase();
const name = row.cells[2].textContent.toLowerCase();
const role = row.querySelector('.role-badge').textContent.toLowerCase();
const matchesSearch = username.includes(searchTerm) || name.includes(searchTerm);
const matchesRole = !roleFilter || role.includes(roleFilter);
row.style.display = matchesSearch && matchesRole ? '' : 'none';
});
}
// λͺ¨λ¬ κ΄λ ¨ ν¨μλ€λ§ μ μμΌλ‘ λ
ΈμΆ (λμ μΌλ‘ μμ±λλ HTMLμμ μ¬μ©)
window.closeModal = closeModal;
window.editUser = editUser;
window.deleteUser = deleteUser;
window.openCreateUserForm = openCreateUserForm;
window.filterUsers = filterUsers;
window.filterLogs = filterLogs;
// ν
μ€νΈμ© μ μ ν¨μ
window.testFunction = function() {
console.log('π§ͺ ν
μ€νΈ ν¨μ νΈμΆλ¨!');
alert('ν
μ€νΈ ν¨μκ° μ μμ μΌλ‘ μλν©λλ€!');
};
console.log('π μ μ ν¨μλ€ λ
ΈμΆ μλ£');
// λͺ¨λ¬ μΈλΆ ν΄λ¦ μ λ«κΈ°
window.onclick = function(event) {
const modals = document.querySelectorAll('.modal');
modals.forEach(modal => {
if (event.target === modal) {
modal.style.display = 'none';
}
});
};