178 lines
4.7 KiB
JavaScript
178 lines
4.7 KiB
JavaScript
/* ProxyAuto Pro - 主 JavaScript 文件 */
|
|
|
|
// Toast 通知
|
|
function showToast(type, message, duration = 4000) {
|
|
const container = document.getElementById('toast-container');
|
|
|
|
const toast = document.createElement('div');
|
|
toast.className = `toast ${type}`;
|
|
toast.innerHTML = `
|
|
<span class="toast-message">${escapeHtml(message)}</span>
|
|
<button class="toast-close" onclick="this.parentElement.remove()">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<line x1="18" y1="6" x2="6" y2="18"/>
|
|
<line x1="6" y1="6" x2="18" y2="18"/>
|
|
</svg>
|
|
</button>
|
|
`;
|
|
|
|
container.appendChild(toast);
|
|
|
|
// 自动移除
|
|
setTimeout(() => {
|
|
toast.style.opacity = '0';
|
|
toast.style.transform = 'translateX(20px)';
|
|
setTimeout(() => toast.remove(), 300);
|
|
}, duration);
|
|
}
|
|
|
|
// HTML 转义
|
|
function escapeHtml(text) {
|
|
const div = document.createElement('div');
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|
|
|
|
// 通用 API 请求函数
|
|
async function apiRequest(url, options = {}) {
|
|
const defaultOptions = {
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
};
|
|
|
|
const mergedOptions = {
|
|
...defaultOptions,
|
|
...options,
|
|
headers: {
|
|
...defaultOptions.headers,
|
|
...options.headers,
|
|
},
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(url, mergedOptions);
|
|
const data = await response.json();
|
|
|
|
if (!response.ok) {
|
|
throw new Error(data.message || `HTTP ${response.status}`);
|
|
}
|
|
|
|
return data;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 格式化日期时间
|
|
function formatDateTime(isoString) {
|
|
if (!isoString) return '--';
|
|
|
|
const date = new Date(isoString);
|
|
return date.toLocaleString('zh-CN', {
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit',
|
|
});
|
|
}
|
|
|
|
// 格式化时间
|
|
function formatTime(isoString) {
|
|
if (!isoString) return '--';
|
|
|
|
const date = new Date(isoString);
|
|
return date.toLocaleTimeString('zh-CN', {
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit',
|
|
});
|
|
}
|
|
|
|
// 确认对话框
|
|
function confirmAction(message) {
|
|
return confirm(message);
|
|
}
|
|
|
|
// 页面加载完成后的初始化
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// 可以在这里添加全局初始化逻辑
|
|
console.log('ProxyAuto Pro initialized');
|
|
});
|
|
|
|
// 移动端侧边栏切换
|
|
function toggleSidebar() {
|
|
const sidebar = document.getElementById('sidebar');
|
|
const overlay = document.querySelector('.sidebar-overlay');
|
|
if (sidebar) {
|
|
sidebar.classList.toggle('open');
|
|
if (overlay) {
|
|
overlay.classList.toggle('active');
|
|
}
|
|
}
|
|
}
|
|
|
|
// 格式化倒计时
|
|
function formatCountdown(seconds) {
|
|
if (seconds <= 0) return '即将更换';
|
|
|
|
const hours = Math.floor(seconds / 3600);
|
|
const minutes = Math.floor((seconds % 3600) / 60);
|
|
const secs = Math.floor(seconds % 60);
|
|
|
|
if (hours > 0) {
|
|
return `${hours}时${minutes}分${secs}秒`;
|
|
} else if (minutes > 0) {
|
|
return `${minutes}分${secs}秒`;
|
|
} else {
|
|
return `${secs}秒`;
|
|
}
|
|
}
|
|
|
|
// 格式化24小时制时间
|
|
function formatTime24(isoString) {
|
|
if (!isoString) return '--';
|
|
|
|
const date = new Date(isoString);
|
|
const pad = n => n.toString().padStart(2, '0');
|
|
|
|
return `${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
|
|
}
|
|
|
|
// 更新所有倒计时
|
|
function updateCountdowns() {
|
|
const countdownElements = document.querySelectorAll('[data-next-run]');
|
|
const now = Date.now();
|
|
|
|
countdownElements.forEach(el => {
|
|
const nextRunTime = new Date(el.dataset.nextRun).getTime();
|
|
const remaining = Math.max(0, Math.floor((nextRunTime - now) / 1000));
|
|
|
|
const countdownSpan = el.querySelector('.countdown-value');
|
|
if (countdownSpan) {
|
|
countdownSpan.textContent = formatCountdown(remaining);
|
|
}
|
|
});
|
|
}
|
|
|
|
// 启动倒计时更新器
|
|
let countdownInterval = null;
|
|
function startCountdownUpdater() {
|
|
if (countdownInterval) clearInterval(countdownInterval);
|
|
updateCountdowns();
|
|
countdownInterval = setInterval(updateCountdowns, 1000);
|
|
}
|
|
|
|
// 最小加载时间包装器
|
|
async function withMinLoadTime(promise, minMs = 500) {
|
|
const start = Date.now();
|
|
const result = await promise;
|
|
const elapsed = Date.now() - start;
|
|
if (elapsed < minMs) {
|
|
await new Promise(resolve => setTimeout(resolve, minMs - elapsed));
|
|
}
|
|
return result;
|
|
}
|