diff --git a/src/pages/idcard/index.vue b/src/pages/idcard/index.vue index 38eef9f..881c10f 100644 --- a/src/pages/idcard/index.vue +++ b/src/pages/idcard/index.vue @@ -147,6 +147,7 @@ type MarriageInfo = { const STORAGE_KEY_USER = 'userAs' const STORAGE_KEY_MARRIAGE = 'marriageOcr' +const MAX_UPLOAD_KB = 500 const router = useRouter() @@ -264,6 +265,56 @@ const triggerUpload = (role: Role) => { } } +const compressImage = (file: File, maxSizeKB = MAX_UPLOAD_KB): Promise => { + const limit = maxSizeKB * 1024 + if (file.size <= limit) return Promise.resolve(file) + + return new Promise((resolve, reject) => { + const reader = new FileReader() + reader.onload = () => { + const img = new Image() + img.onload = async () => { + const tryCompress = async (scale: number) => { + const canvas = document.createElement('canvas') + canvas.width = Math.max(1, Math.round(img.width * scale)) + canvas.height = Math.max(1, Math.round(img.height * scale)) + const ctx = canvas.getContext('2d') + if (!ctx) throw new Error('无法获取画布上下文') + ctx.drawImage(img, 0, 0, canvas.width, canvas.height) + + let quality = 0.9 + let dataUrl = canvas.toDataURL(file.type || 'image/jpeg', quality) + while (dataUrl.length / 1024 > maxSizeKB && quality > 0.4) { + quality -= 0.1 + dataUrl = canvas.toDataURL(file.type || 'image/jpeg', quality) + } + const blob = await fetch(dataUrl).then(res => res.blob()) + return blob + } + + try { + let scale = Math.min(1, Math.sqrt(limit / file.size)) + for (let attempt = 0; attempt < 3; attempt++) { + const blob = await tryCompress(scale) + if (blob.size <= limit) { + resolve(new File([blob], file.name, { type: blob.type })) + return + } + scale *= 0.7 + } + reject(new Error('图片压缩失败,请重试')) + } catch (err) { + reject(err) + } + } + img.onerror = () => reject(new Error('图片加载失败,请重试')) + img.src = reader.result as string + } + reader.onerror = () => reject(new Error('读取图片失败,请重试')) + reader.readAsDataURL(file) + }) +} + const handleIdChange = async (role: Role) => { const input = role === 'husband' ? husbandUpload.value : wifeUpload.value const file = input?.files?.[0] @@ -280,11 +331,11 @@ const handleIdChange = async (role: Role) => { return } - const formFormData = new FormData() - formFormData.append('file', file) - showLoading() try { + const compressedFile = await compressImage(file) + const formFormData = new FormData() + formFormData.append('file', compressedFile) const response: any = await apiService.uploadOcrImage(formFormData) const res: any = await apiService.idCardParseOcrInfo({ mobile: userInfo.value.phone,