2 Commits a291a926b5 ... 11c7f692c7

Autore SHA1 Messaggio Data
  zengjun 11c7f692c7 Merge branch 'zengjun/退货/20260123退货拍照优化' into testing 1 mese fa
  zengjun ddac312004 拍照优化 1 mese fa
4 ha cambiato i file con 92 aggiunte e 12 eliminazioni
  1. 1 0
      package.json
  2. 11 0
      src/types/heic2any.d.ts
  3. 42 0
      src/utils/imageFormat.ts
  4. 38 12
      src/views/returned/register/index.vue

+ 1 - 0
package.json

@@ -17,6 +17,7 @@
     "@types/fabric": "^5.3.11",
     "axios": "^1.7.9",
     "fabric": "^7.1.0",
+    "heic2any": "^0.0.4",
     "lib-flexible": "^0.3.2",
     "pinia": "^2.3.0",
     "pinia-plugin-persistedstate": "^3.2.1",

+ 11 - 0
src/types/heic2any.d.ts

@@ -0,0 +1,11 @@
+declare module 'heic2any' {
+  interface Heic2AnyOptions {
+    blob: Blob
+    toType?: string
+    quality?: number
+  }
+
+  type Heic2AnyResult = Blob | Blob[]
+
+  export default function heic2any(options: Heic2AnyOptions): Promise<Heic2AnyResult>
+}

+ 42 - 0
src/utils/imageFormat.ts

@@ -0,0 +1,42 @@
+const HEIC_MIME_TYPES = [
+  'image/heic',
+  'image/heif',
+  'image/heic-sequence',
+  'image/heif-sequence',
+]
+
+export function isHeicOrHeif(file: File): boolean {
+  const name = file.name.toLowerCase()
+  const type = (file.type || '').toLowerCase()
+  return (
+    name.endsWith('.heic') ||
+    name.endsWith('.heif') ||
+    HEIC_MIME_TYPES.includes(type)
+  )
+}
+
+function replaceExtension(fileName: string, extension: string): string {
+  const lastDot = fileName.lastIndexOf('.')
+  if (lastDot <= 0) return `${fileName}.${extension}`
+  return `${fileName.slice(0, lastDot)}.${extension}`
+}
+
+export async function convertHeicHeifToWebp(file: File): Promise<File> {
+  const { default: heic2any } = await import('heic2any')
+  const result = await heic2any({
+    blob: file,
+    toType: 'image/webp',
+    quality: 0.92,
+  })
+
+  const blob = Array.isArray(result) ? result[0] : result
+  if (!(blob instanceof Blob)) {
+    throw new Error('HEIC/HEIF 转换失败')
+  }
+
+  const targetFileName = replaceExtension(file.name, 'webp')
+  return new File([blob], targetFileName, {
+    type: 'image/webp',
+    lastModified: Date.now(),
+  })
+}

+ 38 - 12
src/views/returned/register/index.vue

@@ -23,7 +23,7 @@
         <p class="info-line">
           工作台:<span class="info-value">{{ workbench.workStation }}</span>
         </p>
-        <p class="info-line hint-text">支持png/jpeg/jpg/webp</p>
+        <p class="info-line hint-text">支持png/jpeg/jpg/webp/heic/heif(heic/heif自动转webp)</p>
         <van-button
           size="mini"
           type="primary"
@@ -206,6 +206,7 @@ import {
 import { getHeader, goBack } from '@/utils/android'
 import { detailImageUpload, returnedWorkbench } from '@/api/returned/index.ts'
 import { compressImage } from '@/utils/imageCompression'
+import { convertHeicHeifToWebp, isHeicOrHeif } from '@/utils/imageFormat'
 import EditImage from '@/components/EditImage.vue'
 
 const workbench = ref<Workbench>({ warehouseCode: '', workStation: '' })
@@ -261,17 +262,13 @@ function getWorkbench(): void {
     })
 }
 
-const beforeReadImage = (file: File | File[]): any => {
+const beforeReadImage = async (file: File | File[]): Promise<UploadImage[] | false> => {
   const files = Array.isArray(file) ? file : [file]
+  const normalizedFiles: File[] = []
+
   for (const f of files) {
-    if (
-      f.name.toLowerCase().endsWith('.heic') ||
-      f.name.toLowerCase().endsWith('.heif')
-    ) {
-      showFailToast('不支持的图片格式')
-      return false
-    }
-    const isImage = /^image\//.test(f.type)
+    const isHeicFile = isHeicOrHeif(f)
+    const isImage = /^image\//.test(f.type) || isHeicFile
     if (!isImage) {
       showFailToast('仅支持图片文件')
       return false
@@ -280,10 +277,24 @@ const beforeReadImage = (file: File | File[]): any => {
       showFailToast('图片大小不能超过15MB')
       return false
     }
+
+    if (isHeicFile) {
+      try {
+        const convertedFile = await convertHeicHeifToWebp(f)
+        normalizedFiles.push(convertedFile)
+      } catch (error) {
+        console.error('HEIC/HEIF 转换失败:', error)
+        showFailToast('HEIC/HEIF 转换失败,请使用 JPG/PNG/WEBP 格式')
+        return false
+      }
+      continue
+    }
+
+    normalizedFiles.push(f)
   }
 
   // 返回增强的图片对象数组,包含状态信息
-  return files.map((f) => ({
+  return normalizedFiles.map((f) => ({
     file: f, // 原始File对象
     status: UPLOAD_STATUS.PENDING,
     url: null,
@@ -623,7 +634,10 @@ const changeFile = async (
     const imageObj = imageList[index]
 
     // 将base64转换为File对象
-    const editedFile = dataURLtoFile(editedDataURL, imageObj.file.name)
+    const editedFile = dataURLtoFile(
+      editedDataURL,
+      getFileNameByMime(imageObj.file.name, editedDataURL),
+    )
 
     // 压缩图片(EditImage保存的是PNG,可能很大)
     const compressedFile = await compressImage(editedFile)
@@ -669,6 +683,18 @@ function dataURLtoFile(dataurl: string, filename: string): File {
   }
   return new File([u8arr], filename, { type: mime })
 }
+
+function getFileNameByMime(fileName: string, dataUrl: string): string {
+  const mimeMatch = dataUrl.match(/^data:(.*?);/)
+  const mime = mimeMatch?.[1] || ''
+  const ext = mime.split('/')[1]
+  if (!ext) return fileName
+
+  const normalizedExt = ext.split('+')[0].toLowerCase()
+  const dotIndex = fileName.lastIndexOf('.')
+  if (dotIndex <= 0) return `${fileName}.${normalizedExt}`
+  return `${fileName.slice(0, dotIndex)}.${normalizedExt}`
+}
 </script>
 
 <style scoped lang="sass">