105 lines
3.8 KiB
JavaScript
105 lines
3.8 KiB
JavaScript
// ========== Confirm Dialog ==========
|
|
function confirmAction(msg) {
|
|
return confirm(msg || '确定要执行此操作吗?');
|
|
}
|
|
|
|
// ========== Delete with Confirm ==========
|
|
function deleteItem(url, msg) {
|
|
if (confirmAction(msg || '确定要删除吗?此操作不可恢复。')) {
|
|
fetch(url, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' }
|
|
}).then(res => res.json()).then(data => {
|
|
if (data.success) {
|
|
showToast('操作成功', 'success');
|
|
setTimeout(() => location.reload(), 800);
|
|
} else {
|
|
showToast(data.message || '操作失败', 'danger');
|
|
}
|
|
}).catch(() => {
|
|
showToast('网络错误', 'danger');
|
|
});
|
|
}
|
|
}
|
|
|
|
// ========== Toast Notification ==========
|
|
function showToast(message, type) {
|
|
type = type || 'success';
|
|
var toastEl = document.createElement('div');
|
|
toastEl.className = 'toast align-items-center text-bg-' + type + ' border-0 show';
|
|
toastEl.setAttribute('role', 'alert');
|
|
toastEl.style.cssText = 'position:fixed;top:24px;right:24px;z-index:9999;min-width:260px;border-radius:16px;box-shadow:-4px -4px 10px rgba(255,255,255,0.8),4px 4px 10px rgba(163,163,200,0.35);';
|
|
toastEl.innerHTML = '<div class="d-flex"><div class="toast-body">' + message + '</div><button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button></div>';
|
|
document.body.appendChild(toastEl);
|
|
setTimeout(function() {
|
|
toastEl.remove();
|
|
}, 3000);
|
|
}
|
|
|
|
// ========== Auto-dismiss alerts ==========
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
var alerts = document.querySelectorAll('.alert:not(.alert-permanent)');
|
|
alerts.forEach(function(alert) {
|
|
setTimeout(function() {
|
|
var bsAlert = new bootstrap.Alert(alert);
|
|
bsAlert.close();
|
|
}, 3000);
|
|
});
|
|
});
|
|
|
|
// ========== Sidebar Toggle (mobile) ==========
|
|
function toggleSidebar() {
|
|
document.querySelector('.sidebar').classList.toggle('show');
|
|
}
|
|
|
|
// ========== Format Number ==========
|
|
function formatNumber(num) {
|
|
if (num === null || num === undefined) return '0';
|
|
return parseFloat(num).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
}
|
|
|
|
// ========== Form Validation ==========
|
|
(function() {
|
|
'use strict';
|
|
var forms = document.querySelectorAll('.needs-validation');
|
|
forms.forEach(function(form) {
|
|
form.addEventListener('submit', function(event) {
|
|
if (!form.checkValidity()) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
}
|
|
form.classList.add('was-validated');
|
|
}, false);
|
|
});
|
|
})();
|
|
|
|
// ========== Date Range Picker Helper ==========
|
|
function setQuickDateRange(startInput, endInput, days) {
|
|
var end = new Date();
|
|
var start = new Date();
|
|
start.setDate(start.getDate() - days);
|
|
startInput.value = start.toISOString().split('T')[0];
|
|
endInput.value = end.toISOString().split('T')[0];
|
|
}
|
|
|
|
// ========== Export Table to CSV ==========
|
|
function exportTableToCSV(tableId, filename) {
|
|
var table = document.getElementById(tableId);
|
|
if (!table) return;
|
|
var rows = table.querySelectorAll('tr');
|
|
var csv = [];
|
|
rows.forEach(function(row) {
|
|
var cols = row.querySelectorAll('td, th');
|
|
var rowData = [];
|
|
cols.forEach(function(col) {
|
|
rowData.push('"' + col.innerText.replace(/"/g, '""') + '"');
|
|
});
|
|
csv.push(rowData.join(','));
|
|
});
|
|
var blob = new Blob(['\uFEFF' + csv.join('\n')], { type: 'text/csv;charset=utf-8;' });
|
|
var link = document.createElement('a');
|
|
link.href = URL.createObjectURL(blob);
|
|
link.download = filename || 'export.csv';
|
|
link.click();
|
|
}
|