/** * UI交互增强脚本 * 提供加载状态、视觉反馈、操作提示等功能 */ // 创建Toast容器 function ensureToastContainer() { let container = document.getElementById('toastContainer'); if (!container) { container = document.createElement('div'); container.id = 'toastContainer'; container.className = 'toast-container position-fixed top-0 end-0 p-3'; container.style.zIndex = '1060'; document.body.appendChild(container); } return container; } // 显示成功提示 function showSuccess(message, duration = 3000) { const container = ensureToastContainer(); const toast = document.createElement('div'); toast.className = 'toast align-items-center text-white bg-success border-0'; toast.setAttribute('role', 'alert'); toast.setAttribute('aria-live', 'assertive'); toast.setAttribute('aria-atomic', 'true'); toast.innerHTML = `
${message}
`; container.appendChild(toast); const bsToast = new bootstrap.Toast(toast, { delay: duration }); bsToast.show(); toast.addEventListener('hidden.bs.toast', () => toast.remove()); } // 显示错误提示 function showError(message, duration = 4000) { const container = ensureToastContainer(); const toast = document.createElement('div'); toast.className = 'toast align-items-center text-white bg-danger border-0'; toast.setAttribute('role', 'alert'); toast.setAttribute('aria-live', 'assertive'); toast.setAttribute('aria-atomic', 'true'); toast.innerHTML = `
${message}
`; container.appendChild(toast); const bsToast = new bootstrap.Toast(toast, { delay: duration }); bsToast.show(); toast.addEventListener('hidden.bs.toast', () => toast.remove()); } // 显示警告提示 function showWarning(message, duration = 3000) { const container = ensureToastContainer(); const toast = document.createElement('div'); toast.className = 'toast align-items-center text-white bg-warning border-0'; toast.setAttribute('role', 'alert'); toast.setAttribute('aria-live', 'assertive'); toast.setAttribute('aria-atomic', 'true'); toast.innerHTML = `
${message}
`; container.appendChild(toast); const bsToast = new bootstrap.Toast(toast, { delay: duration }); bsToast.show(); toast.addEventListener('hidden.bs.toast', () => toast.remove()); } // 显示信息提示 function showInfo(message, duration = 3000) { const container = ensureToastContainer(); const toast = document.createElement('div'); toast.className = 'toast align-items-center text-white bg-info border-0'; toast.setAttribute('role', 'alert'); toast.setAttribute('aria-live', 'assertive'); toast.setAttribute('aria-atomic', 'true'); toast.innerHTML = `
${message}
`; container.appendChild(toast); const bsToast = new bootstrap.Toast(toast, { delay: duration }); bsToast.show(); toast.addEventListener('hidden.bs.toast', () => toast.remove()); } // 显示加载状态 function showLoading(elementId, message = '加载中...') { const element = document.getElementById(elementId); if (element) { element.innerHTML = `
${message}

${message}

`; } } // 按钮加载状态 function setButtonLoading(button, loading = true, originalText = null) { if (loading) { if (!button.dataset.originalText) { button.dataset.originalText = button.innerHTML; } button.disabled = true; button.innerHTML = ` 处理中... `; } else { button.disabled = false; button.innerHTML = button.dataset.originalText || originalText || '提交'; delete button.dataset.originalText; } } // 增强的fetch函数(带加载状态和错误处理) async function enhancedFetch(url, options = {}) { const { showLoading: showLoadingId, button: loadingButton, ...fetchOptions } = options; // 显示加载状态 if (showLoadingId) { showLoading(showLoadingId); } // 按钮加载状态 if (loadingButton) { setButtonLoading(loadingButton, true); } try { const response = await fetch(url, fetchOptions); const data = await response.json(); // 恢复按钮状态 if (loadingButton) { setButtonLoading(loadingButton, false); } return { response, data }; } catch (error) { // 恢复按钮状态 if (loadingButton) { setButtonLoading(loadingButton, false); } showError('网络请求失败,请检查网络连接'); throw error; } } // 确认对话框(使用自定义模态框) function confirmAction(message, title = '确认操作', confirmText = '确定', cancelText = '取消') { return new Promise((resolve) => { // 确保自定义模态框已加载 if (typeof CustomModal === 'undefined') { console.error('CustomModal未加载,请先引入custom-modal.js'); // 降级到原生confirm resolve(confirm(message)); return; } const modal = new CustomModal({ title: title, content: `

${message}

`, confirmText: confirmText, cancelText: cancelText, onConfirm: () => { resolve(true); return true; }, onClose: () => { resolve(false); } }); modal.show(); }); } // 表单验证增强 function validateForm(formId) { const form = document.getElementById(formId); if (!form) return false; const requiredFields = form.querySelectorAll('[required]'); let isValid = true; requiredFields.forEach(field => { if (!field.value.trim()) { field.classList.add('is-invalid'); isValid = false; } else { field.classList.remove('is-invalid'); field.classList.add('is-valid'); } }); return isValid; } // 数字格式化 function formatNumber(num, decimals = 2) { return parseFloat(num || 0).toFixed(decimals); } // 日期格式化 function formatDate(date, format = 'YYYY-MM-DD HH:mm:ss') { if (!date) return '-'; const d = new Date(date); const year = d.getFullYear(); const month = String(d.getMonth() + 1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0'); const hours = String(d.getHours()).padStart(2, '0'); const minutes = String(d.getMinutes()).padStart(2, '0'); const seconds = String(d.getSeconds()).padStart(2, '0'); return format .replace('YYYY', year) .replace('MM', month) .replace('DD', day) .replace('HH', hours) .replace('mm', minutes) .replace('ss', seconds); } // 防抖函数 function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } // 节流函数 function throttle(func, limit) { let inThrottle; return function(...args) { if (!inThrottle) { func.apply(this, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; } // 导出到全局 window.UIEnhancements = { showSuccess, showError, showWarning, showInfo, showLoading, setButtonLoading, enhancedFetch, confirmAction, validateForm, formatNumber, formatDate, debounce, throttle };