Files
file-transfer-go/web/static/js/common.js
MatrixSeven 70ad644a71 第一版本
2025-07-28 16:33:10 +08:00

394 lines
12 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 通用JavaScript工具函数
// 工具函数
const Utils = {
// 格式化文件大小
formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
},
// 格式化时间
formatTime(date) {
return new Date(date).toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
},
// 生成随机字符串
randomString(length) {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
},
// 复制到剪贴板
async copyToClipboard(text) {
try {
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(text);
return true;
} else {
// 兼容性处理
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
textArea.style.top = '-999999px';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
const result = document.execCommand('copy');
document.body.removeChild(textArea);
return result;
}
} catch (error) {
console.error('复制失败:', error);
return false;
}
},
// 获取文件类型图标
getFileIcon(fileName, fileType) {
const ext = fileName.split('.').pop().toLowerCase();
// 根据MIME类型
if (fileType) {
if (fileType.startsWith('image/')) return '🖼️';
if (fileType.startsWith('video/')) return '🎥';
if (fileType.startsWith('audio/')) return '🎵';
if (fileType.includes('pdf')) return '📄';
if (fileType.includes('text')) return '📝';
if (fileType.includes('zip') || fileType.includes('rar')) return '📦';
}
// 根据文件扩展名
switch (ext) {
case 'pdf': return '📄';
case 'doc':
case 'docx': return '📝';
case 'xls':
case 'xlsx': return '📊';
case 'ppt':
case 'pptx': return '📈';
case 'txt': return '📄';
case 'epub':
case 'mobi': return '📚';
case 'zip':
case 'rar':
case '7z': return '📦';
case 'jpg':
case 'jpeg':
case 'png':
case 'gif':
case 'bmp': return '🖼️';
case 'mp4':
case 'avi':
case 'mov':
case 'wmv': return '🎥';
case 'mp3':
case 'wav':
case 'flac':
case 'aac': return '🎵';
case 'js':
case 'html':
case 'css':
case 'py':
case 'java':
case 'cpp': return '💻';
default: return '📁';
}
},
// 验证取件码格式
validateCode(code) {
return /^[A-Z0-9]{6}$/.test(code);
},
// 获取浏览器信息
getBrowserInfo() {
const ua = navigator.userAgent;
let browser = 'Unknown';
let version = 'Unknown';
if (ua.indexOf('Chrome') > -1) {
browser = 'Chrome';
version = ua.match(/Chrome\/(\d+)/)[1];
} else if (ua.indexOf('Firefox') > -1) {
browser = 'Firefox';
version = ua.match(/Firefox\/(\d+)/)[1];
} else if (ua.indexOf('Safari') > -1 && ua.indexOf('Chrome') === -1) {
browser = 'Safari';
version = ua.match(/Version\/(\d+)/)[1];
} else if (ua.indexOf('Edge') > -1) {
browser = 'Edge';
version = ua.match(/Edge\/(\d+)/)[1];
} else if (ua.indexOf('360SE') > -1) {
browser = '360浏览器';
} else if (ua.indexOf('QQBrowser') > -1) {
browser = 'QQ浏览器';
version = ua.match(/QQBrowser\/(\d+)/)[1];
}
return { browser, version };
},
// 检查WebRTC支持
checkWebRTCSupport() {
return !!(window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection);
},
// 检查文件API支持
checkFileAPISupport() {
return !!(window.File && window.FileReader && window.FileList && window.Blob);
},
// 节流函数
throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
}
},
// 防抖函数
debounce(func, delay) {
let timeoutId;
return function() {
const args = arguments;
const context = this;
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(context, args), delay);
}
}
};
// 通知系统
const Notification = {
// 显示成功消息
success(message, duration = 3000) {
this.show(message, 'success', duration);
},
// 显示错误消息
error(message, duration = 5000) {
this.show(message, 'error', duration);
},
// 显示警告消息
warning(message, duration = 4000) {
this.show(message, 'warning', duration);
},
// 显示信息消息
info(message, duration = 3000) {
this.show(message, 'info', duration);
},
// 显示通知
show(message, type = 'info', duration = 3000) {
// 创建通知容器(如果不存在)
let container = document.getElementById('notification-container');
if (!container) {
container = document.createElement('div');
container.id = 'notification-container';
container.className = 'fixed top-4 right-4 z-50 space-y-2';
document.body.appendChild(container);
}
// 创建通知元素
const notification = document.createElement('div');
notification.className = `max-w-sm w-full bg-white shadow-lg rounded-lg pointer-events-auto flex ring-1 ring-black ring-opacity-5 fade-in`;
const bgColor = {
success: 'bg-green-50 border-green-200',
error: 'bg-red-50 border-red-200',
warning: 'bg-yellow-50 border-yellow-200',
info: 'bg-blue-50 border-blue-200'
}[type] || 'bg-gray-50 border-gray-200';
const iconEmoji = {
success: '✅',
error: '❌',
warning: '⚠️',
info: ''
}[type] || '';
notification.innerHTML = `
<div class="flex-1 w-0 p-4">
<div class="flex items-start">
<div class="flex-shrink-0">
<span class="text-xl">${iconEmoji}</span>
</div>
<div class="ml-3 w-0 flex-1 pt-0.5">
<p class="text-sm font-medium text-gray-900">${message}</p>
</div>
</div>
</div>
<div class="flex border-l border-gray-200">
<button onclick="this.parentElement.parentElement.remove()"
class="w-full border border-transparent rounded-none rounded-r-lg p-4 flex items-center justify-center text-sm font-medium text-gray-600 hover:text-gray-500 focus:outline-none">
×
</button>
</div>
`;
notification.className += ` ${bgColor}`;
container.appendChild(notification);
// 自动移除
if (duration > 0) {
setTimeout(() => {
if (notification.parentNode) {
notification.style.opacity = '0';
notification.style.transform = 'translateX(100%)';
setTimeout(() => notification.remove(), 300);
}
}, duration);
}
}
};
// 加载管理器
const Loading = {
show(message = '加载中...') {
this.hide(); // 先隐藏现有的加载提示
const overlay = document.createElement('div');
overlay.id = 'loading-overlay';
overlay.className = 'fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50';
overlay.innerHTML = `
<div class="bg-white rounded-lg p-6 flex items-center space-x-3">
<div class="animate-spin rounded-full h-6 w-6 border-b-2 border-blue-500"></div>
<span class="text-gray-700">${message}</span>
</div>
`;
document.body.appendChild(overlay);
},
hide() {
const overlay = document.getElementById('loading-overlay');
if (overlay) {
overlay.remove();
}
}
};
// API请求工具
const API = {
async request(url, options = {}) {
const defaultOptions = {
headers: {
'Content-Type': 'application/json',
},
};
const config = { ...defaultOptions, ...options };
try {
const response = await fetch(url, config);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return await response.json();
} else {
return await response.text();
}
} catch (error) {
console.error('API请求失败:', error);
throw error;
}
},
async get(url, params = {}) {
const urlObj = new URL(url, window.location.origin);
Object.keys(params).forEach(key =>
urlObj.searchParams.append(key, params[key])
);
return this.request(urlObj.toString());
},
async post(url, data = {}) {
return this.request(url, {
method: 'POST',
body: JSON.stringify(data),
});
},
async delete(url) {
return this.request(url, {
method: 'DELETE',
});
}
};
// 页面加载完成后执行
document.addEventListener('DOMContentLoaded', function() {
// 检查浏览器兼容性
const browserInfo = Utils.getBrowserInfo();
console.log(`浏览器: ${browserInfo.browser} ${browserInfo.version}`);
// 检查功能支持
if (!Utils.checkFileAPISupport()) {
Notification.warning('您的浏览器不完全支持文件API部分功能可能受限');
}
if (!Utils.checkWebRTCSupport()) {
console.warn('浏览器不支持WebRTC视频功能不可用');
}
// 添加全局错误处理
window.addEventListener('error', function(event) {
console.error('全局错误:', event.error);
Notification.error('页面发生错误,请刷新后重试');
});
// 添加网络状态监听
window.addEventListener('online', function() {
Notification.success('网络连接已恢复');
});
window.addEventListener('offline', function() {
Notification.warning('网络连接已断开,请检查网络设置');
});
// 添加页面可见性变化监听
document.addEventListener('visibilitychange', function() {
if (document.hidden) {
console.log('页面已隐藏');
} else {
console.log('页面已显示');
}
});
});
// 导出全局对象
window.Utils = Utils;
window.Notification = Notification;
window.Loading = Loading;
window.API = API;