/** * Simple UI Components for KSTools License Manager */ class Components { // Modal system static createModal({ title, content, size = 'md' }) { console.log('🔨 Creating modal with title:', title); const modalHtml = ` `; const container = document.getElementById('modalContainer') || document.body; console.log('📍 Modal container:', container); container.insertAdjacentHTML('beforeend', modalHtml); const modal = container.lastElementChild; console.log('✅ Modal created:', modal); return modal; } static showModal(modal) { if (modal) { console.log('👁️ Showing modal...', modal); modal.classList.add('active'); document.body.style.overflow = 'hidden'; console.log('✅ Modal shown with active class'); } else { console.error('❌ Cannot show modal: modal is null or undefined'); } } static closeModal(modal) { if (modal) { modal.classList.remove('active'); setTimeout(() => { modal.remove(); document.body.style.overflow = ''; }, 300); } } // Simple modal method for quick use static modal(title, content, size = 'md') { console.log('🎯 Components.modal called with title:', title); const modal = this.createModal({ title, content, size }); this.showModal(modal); return modal; } // License creation modal static createLicenseModal() { // 防止重複創建 const existingModal = document.querySelector('.modal-overlay'); if (existingModal) { console.log('⚠️ License modal already exists, returning existing one'); return existingModal; } const content = `
此名稱將顯示在授權記錄中
選填:用於聯繫和通知
選填:內部記錄使用
硬體綁定機制說明

• 使用者首次輸入授權碼時會自動綁定硬體

• 系統會自動生成32位硬體指紋 (CPU ProcessorId + 主機板序號)

• 每個授權碼只能在一台設備上啟用使用

`; const modal = this.createModal({ title: '建立新授權', content: content, size: 'lg' }); // Setup form handler const form = modal.querySelector('#licenseForm'); form.addEventListener('submit', async (e) => { e.preventDefault(); await this.handleLicenseCreation(form, modal); }); this.showModal(modal); return modal; } static async handleLicenseCreation(form, modal) { const formData = new FormData(form); // 驗證必要欄位 const userName = formData.get('userName')?.trim(); const validDays = formData.get('validDays'); if (!userName) { Utils.showError('驗證失敗', '請輸入用戶名稱'); return; } if (!validDays) { Utils.showError('驗證失敗', '請選擇有效天數'); return; } const licenseData = { user_name: userName, user_email: formData.get('email')?.trim() || null, expires_days: parseInt(validDays), notes: formData.get('notes')?.trim() || null }; console.log('📝 License Creation Data:', licenseData); const submitBtn = form.querySelector('button[type="submit"]'); const originalContent = submitBtn.innerHTML; try { submitBtn.disabled = true; submitBtn.innerHTML = ' 建立中...'; console.log('🚀 Sending create license request...'); const response = await api.createLicense(licenseData); console.log('✅ Create license response:', response); if (response && response.success) { Utils.showSuccess('授權建立成功'); this.closeModal(modal); // Refresh current page if it has a refresh method if (window.currentPage && window.currentPage.refresh) { window.currentPage.refresh(); } } else { throw new Error(response?.message || '建立授權失敗'); } } catch (error) { console.error('❌ Create license error:', error); Utils.handleError(error, '建立授權時'); submitBtn.disabled = false; submitBtn.innerHTML = originalContent; } } // Chart creation helper static createChart(canvas, config) { if (!window.Chart) { console.error('Chart.js not loaded'); return null; } const ctx = canvas.getContext('2d'); // Default dark theme colors const defaultConfig = { plugins: { legend: { labels: { color: '#e6edf3', font: { size: 12 } } } }, scales: config.type !== 'doughnut' && config.type !== 'pie' ? { x: { ticks: { color: '#7d8590' }, grid: { color: '#30363d' } }, y: { ticks: { color: '#7d8590' }, grid: { color: '#30363d' } } } : undefined }; // Merge configs const finalConfig = { ...config, options: { ...defaultConfig, ...config.options, responsive: true, maintainAspectRatio: false } }; return new Chart(ctx, finalConfig); } // Confirmation dialog static confirm(title, message, onConfirm) { const confirmId = 'confirm_' + Date.now(); const content = `

${message}

`; const modal = this.createModal({ title, content }); this.showModal(modal); // 添加確認按鈕事件監聽器 setTimeout(() => { const confirmBtn = document.getElementById(confirmId); if (confirmBtn) { confirmBtn.addEventListener('click', () => { this.closeModal(modal); if (onConfirm && typeof onConfirm === 'function') { onConfirm(); } }); } }, 100); return modal; } static handleConfirm(button, callback) { const modal = button.closest('.modal-overlay'); this.closeModal(modal); if (callback && typeof callback === 'function') { callback(); } } } // Modal keyboard handling document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { const activeModal = document.querySelector('.modal-overlay.active'); if (activeModal) { Components.closeModal(activeModal); } } });