Files
2026-09-11 20:02:47 +08:00

76 lines
3.0 KiB
JavaScript

'use strict';
// ---------------------------------------------------------------------------
// 大文件分片上传常量 (见 app.js uploadChunked/uploadOneChunk)
// ---------------------------------------------------------------------------
const CHUNK_THRESHOLD = 5 * 1024 * 1024 * 1024; // >5GB 走分片
const CHUNK_SIZE = 1 * 1024 * 1024 * 1024; // 每片 1GB
function uuid() {
// crypto.randomUUID 仅在 secure context (HTTPS / localhost) 可用, HTTP 非 localhost 会抛.
// 用 crypto.getRandomValues (所有现代浏览器均支持, 不要求 secure context) 手动拼一个 v4.
const b = new Uint8Array(16);
crypto.getRandomValues(b);
b[6] = (b[6] & 0x0f) | 0x40; // version 4
b[8] = (b[8] & 0x3f) | 0x80; // variant RFC 4122
const h = [...b].map(x => x.toString(16).padStart(2, '0')).join('');
return `${h.slice(0,8)}-${h.slice(8,12)}-${h.slice(12,16)}-${h.slice(16,20)}-${h.slice(20)}`;
}
// ---------------------------------------------------------------------------
// 纯函数 + 倒计时 interval
// 跨文件共享 (classic <script> 加载顺序: app.js → helpers.js → batch.js).
// ---------------------------------------------------------------------------
function formatRemain(iso) {
const ms = new Date(iso).getTime() - Date.now();
if (ms <= 0) return '已过期';
const s = Math.floor(ms / 1000);
if (s < 60) return `剩 ${s} 秒`;
const m = Math.floor(s / 60);
if (m < 60) return `剩 ${m} 分钟`;
const h = Math.floor(m / 60);
if (h < 24) return `剩 ${h} 小时${m % 60 ? ' ' + (m % 60) + ' 分' : ''}`;
const d = Math.floor(h / 24);
return `剩 ${d}${h % 24 ? ' ' + (h % 24) + ' 小时' : ''}`;
}
function isAlmostExpired(iso) {
const ms = new Date(iso).getTime() - Date.now();
return ms > 0 && ms < 60 * 60 * 1000; // < 1h
}
setInterval(() => {
document.querySelectorAll('[data-expires]').forEach(el => {
el.textContent = formatRemain(el.dataset.expires);
el.classList.toggle('danger', isAlmostExpired(el.dataset.expires));
});
}, 1000);
function iconFor(ext) {
const map = { pdf:'📄', zip:'📦', rar:'📦', '7z':'📦', txt:'📄', md:'📄',
png:'🖼', jpg:'🖼', jpeg:'🖼', gif:'🖼', webp:'🖼', svg:'🖼',
mp4:'🎬', mov:'🎬', avi:'🎬', mkv:'🎬',
mp3:'🎵', wav:'🎵', flac:'🎵',
xls:'📊', xlsx:'📊', csv:'📊',
doc:'📃', docx:'📃', ppt:'📽', pptx:'📽' };
return map[ext] || '📁';
}
function formatSize(b) {
if (b == null || isNaN(b)) return '-';
if (b < 1024) return b + ' B';
if (b < 1024 * 1024) return (b / 1024).toFixed(1) + ' KB';
if (b < 1024 * 1024 * 1024) return (b / 1024 / 1024).toFixed(2) + ' MB';
return (b / 1024 / 1024 / 1024).toFixed(2) + ' GB';
}
function formatTime(iso) {
const d = new Date(iso);
const pad = n => String(n).padStart(2, '0');
return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
}
function escapeHtml(s) {
return String(s).replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
}