feat(admin+api): 列表页子路由重构、结算历史与充值截图清理

赛事/代理管理从表格展开改为子路由详情页;结算页增加预览弹窗与历史记录;媒体库支持截图存储统计与自动/手动清理;Player 端充值截图压缩为 WebP 300KB。
This commit is contained in:
2026-06-22 12:28:25 +08:00
parent 499522f3fb
commit 648c314e23
38 changed files with 3298 additions and 1147 deletions

View File

@@ -95,30 +95,44 @@ function selectMethod(m: PaymentMethod) {
}
const MAX_ORIGINAL_BYTES = 10 * 1024 * 1024;
const MAX_SCREENSHOT_BYTES = 1024 * 1024;
const MAX_SCREENSHOT_BYTES = 300 * 1024;
async function compressScreenshot(file: File): Promise<File> {
const baseOptions = {
maxSizeMB: 1,
maxWidthOrHeight: 1920,
maxSizeMB: 0.3,
maxWidthOrHeight: 1200,
useWebWorker: true,
maxIteration: 15,
maxIteration: 10,
fileType: 'image/webp',
} as const;
const attempts = [
{ ...baseOptions, initialQuality: 0.85 },
{ ...baseOptions, initialQuality: 0.65, maxWidthOrHeight: 1600 },
{ ...baseOptions, initialQuality: 0.5, maxWidthOrHeight: 1280 },
{ ...baseOptions, initialQuality: 0.8 },
{ ...baseOptions, initialQuality: 0.6, maxWidthOrHeight: 1000 },
];
let compressed: File | null = null;
for (const options of attempts) {
const compressed = (await imageCompression(file, options)) as File;
if (compressed.size <= MAX_SCREENSHOT_BYTES) {
return compressed;
try {
compressed = (await imageCompression(file, options)) as File;
if (compressed.size <= MAX_SCREENSHOT_BYTES) {
break;
}
} catch (err) {
console.error('Compression attempt failed:', err);
}
}
throw new Error('COMPRESS_TOO_LARGE');
if (!compressed) {
throw new Error('COMPRESS_FAILED');
}
// 重命名文件后缀为 .webp
const name = file.name.replace(/\.[^/.]+$/, "") + '.webp';
return new File([compressed], name, {
type: 'image/webp',
lastModified: Date.now(),
});
}
async function handleFileChange(event: Event) {