/**
* 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 = `
`;
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 = `
`;
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 = `
`;
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 = `
`;
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 = `
`;
}
}
// 按钮加载状态
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
};