后端变更: - 移除 tasks_manager.py 和 core/auth.py,简化架构 - 新增 core/scheduler.py 验证调度器,替代原有任务管理 - 大幅优化 api_server.py:统一错误处理、增强参数验证、支持调度器控制 - validator.py 增强 SOCKS4/SOCKS5 代理验证支持 - config.py 清理废弃配置(WebSocket、API Key、认证开关) - SQLite 数据库操作性能优化 前端变更: - 移除任务管理页面 (CrawlerTasks) 和 WebSocket 相关代码 - 路由简化为 4 个核心页面:总览、代理列表、插件管理、设置 - 提取前端工具函数(clipboard、confirm、format)和 API 类型定义 - 优化 CSS 架构:完善 variables、utilities、element-plus 样式 - Dashboard、Plugins、ProxyList、Settings 页面 UI/UX 优化 - App.vue 响应式侧边栏和页面过渡动画优化 其他: - 移除 PowerShell 启动脚本,简化 Windows 批处理脚本 - 新增 README_SOCKS.md SOCKS 代理支持文档 - .env.example 和 .gitignore 更新
109 lines
2.6 KiB
JavaScript
109 lines
2.6 KiB
JavaScript
/**
|
|
* 格式化工具函数
|
|
*/
|
|
|
|
/**
|
|
* 格式化日期时间
|
|
* @param {string|Date|number} dateTimeStr
|
|
* @param {string} [fallback] - 无效日期时的回退文本
|
|
* @returns {string}
|
|
*/
|
|
export function formatDateTime(dateTimeStr, fallback = '-') {
|
|
if (!dateTimeStr) return fallback
|
|
|
|
const date = new Date(dateTimeStr)
|
|
if (isNaN(date.getTime())) return fallback
|
|
|
|
const pad = (n) => String(n).padStart(2, '0')
|
|
|
|
const year = date.getFullYear()
|
|
const month = pad(date.getMonth() + 1)
|
|
const day = pad(date.getDate())
|
|
const hours = pad(date.getHours())
|
|
const minutes = pad(date.getMinutes())
|
|
const seconds = pad(date.getSeconds())
|
|
|
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
|
}
|
|
|
|
/**
|
|
* 格式化时间(简化版)
|
|
* @param {string|Date|number} timeStr
|
|
* @param {string} [fallback]
|
|
* @returns {string}
|
|
*/
|
|
export function formatTime(timeStr, fallback = '-') {
|
|
if (!timeStr) return fallback
|
|
|
|
const date = new Date(timeStr)
|
|
if (isNaN(date.getTime())) return fallback
|
|
|
|
return date.toLocaleString('zh-CN')
|
|
}
|
|
|
|
/**
|
|
* 格式化数字(添加千分位)
|
|
* @param {number} num
|
|
* @param {number} [decimals] - 小数位数
|
|
* @returns {string}
|
|
*/
|
|
export function formatNumber(num, decimals = 0) {
|
|
if (typeof num !== 'number' || isNaN(num)) return '-'
|
|
return num.toLocaleString('zh-CN', {
|
|
minimumFractionDigits: decimals,
|
|
maximumFractionDigits: decimals
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 格式化百分比
|
|
* @param {number} value
|
|
* @param {number} [total]
|
|
* @param {number} [decimals]
|
|
* @returns {string}
|
|
*/
|
|
export function formatPercent(value, total, decimals = 1) {
|
|
if (total !== undefined) {
|
|
if (!total) return '0%'
|
|
value = (value / total) * 100
|
|
}
|
|
return `${value.toFixed(decimals)}%`
|
|
}
|
|
|
|
/**
|
|
* 格式化文件大小
|
|
* @param {number} bytes
|
|
* @param {number} [decimals]
|
|
* @returns {string}
|
|
*/
|
|
export function formatFileSize(bytes, decimals = 2) {
|
|
if (bytes === 0) return '0 B'
|
|
|
|
const k = 1024
|
|
const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
|
|
return `${(bytes / Math.pow(k, i)).toFixed(decimals)} ${sizes[i]}`
|
|
}
|
|
|
|
/**
|
|
* 格式化时长(秒转可读文本)
|
|
* @param {number} seconds
|
|
* @returns {string}
|
|
*/
|
|
export function formatDuration(seconds) {
|
|
if (!seconds || 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}秒`
|
|
}
|
|
}
|