From 0e05568c7aceaa5ff9c6cd33bf889e995a8e9cb0 Mon Sep 17 00:00:00 2001 From: Frudrax Cheng Date: Tue, 2 Jun 2026 11:18:10 +0800 Subject: [PATCH] Compress site images before upload --- src/pages/AftersalesConfirm.tsx | 61 +++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/src/pages/AftersalesConfirm.tsx b/src/pages/AftersalesConfirm.tsx index b9fe583..9146317 100644 --- a/src/pages/AftersalesConfirm.tsx +++ b/src/pages/AftersalesConfirm.tsx @@ -22,6 +22,62 @@ const SERVICE_TYPE_LABEL: Record = { maintenance: '售后维保', }; +const SITE_IMAGE_MAX_EDGE = 1600; +const SITE_IMAGE_QUALITY = 0.78; + +async function compressSiteImage(file: File): Promise { + if (!file.type.startsWith('image/') || file.type === 'image/gif') { + return file; + } + + const imageUrl = URL.createObjectURL(file); + try { + const img = await loadImage(imageUrl); + const scale = Math.min(1, SITE_IMAGE_MAX_EDGE / Math.max(img.width, img.height)); + const width = Math.max(1, Math.round(img.width * scale)); + const height = Math.max(1, Math.round(img.height * scale)); + + const canvas = document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + const ctx = canvas.getContext('2d'); + if (!ctx) return file; + + ctx.drawImage(img, 0, 0, width, height); + const blob = await canvasToBlob(canvas, 'image/jpeg', SITE_IMAGE_QUALITY); + if (!blob || blob.size >= file.size) { + return file; + } + + const name = file.name.replace(/\.[^.]+$/, '') || 'site-image'; + return new File([blob], `${name}.jpg`, { + type: 'image/jpeg', + lastModified: Date.now(), + }); + } catch { + return file; + } finally { + URL.revokeObjectURL(imageUrl); + } +} + +function loadImage(src: string): Promise { + return new Promise((resolve, reject) => { + const img = new Image(); + img.onload = () => resolve(img); + img.onerror = reject; + img.src = src; + }); +} + +function canvasToBlob( + canvas: HTMLCanvasElement, + type: string, + quality: number, +): Promise { + return new Promise((resolve) => canvas.toBlob(resolve, type, quality)); +} + function AftersalesConfirmPage() { const { serialNumber = '' } = useParams<{ serialNumber: string }>(); const [order, setOrder] = useState(null); @@ -125,7 +181,8 @@ function AftersalesConfirmPage() { if (!files || files.length === 0) return; setUploadingImages(true); try { - const images = await aftersalesApi.uploadSiteImages(serialNumber, Array.from(files)); + const compressedFiles = await Promise.all(Array.from(files).map(compressSiteImage)); + const images = await aftersalesApi.uploadSiteImages(serialNumber, compressedFiles); setOrder((prev) => (prev ? { ...prev, siteImages: images } : prev)); message.success('现场图片上传成功'); } catch (err: any) { @@ -298,7 +355,7 @@ function AftersalesConfirmPage() {