/* 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 = `
${escapeHtml(message)}
`;
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;
}