فهرست منبع

修改heic图片展示问题

ymz 4 ماه پیش
والد
کامیت
31353cb757

+ 2 - 2
.env.development

@@ -2,7 +2,7 @@ NODE_ENV = 'development'
 VUE_APP_TYPE= 'dev'
 # VUE_APP_URL = 'http://10.144.62.235:9999'
 # VUE_APP_URL = 'https://mic.freerr.cn'
-# VUE_APP_URL = 'https://mic.cnbg.com.cn'
+VUE_APP_URL = 'https://mic.cnbg.com.cn'
 # VUE_APP_URL = 'https://cnbg.yaoyi.net'
 # VUE_APP_URL = 'http://192.168.110.25:9999'
-VUE_APP_URL = 'https://mic-t.cnbg.com.cn'
+# VUE_APP_URL = 'https://mic-t.cnbg.com.cn'

+ 1 - 0
package.json

@@ -28,6 +28,7 @@
     "echarts": "^5.6.0",
     "element-ui": "^2.15.14",
     "file-saver": "^2.0.5",
+    "heic2any": "^0.0.4",
     "js-cookie": "^3.0.5",
     "js-file-download": "^0.4.12",
     "nprogress": "^0.2.0",

+ 8 - 0
pnpm-lock.yaml

@@ -59,6 +59,9 @@ importers:
       file-saver:
         specifier: ^2.0.5
         version: 2.0.5
+      heic2any:
+        specifier: ^0.0.4
+        version: 0.0.4
       js-cookie:
         specifier: ^3.0.5
         version: 3.0.5
@@ -2643,6 +2646,9 @@ packages:
     resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
     hasBin: true
 
+  heic2any@0.0.4:
+    resolution: {integrity: sha512-3lLnZiDELfabVH87htnRolZ2iehX9zwpRyGNz22GKXIu0fznlblf0/ftppXKNqS26dqFSeqfIBhAmAj/uSp0cA==}
+
   highlight.js@10.7.3:
     resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==}
 
@@ -7709,6 +7715,8 @@ snapshots:
 
   he@1.2.0: {}
 
+  heic2any@0.0.4: {}
+
   highlight.js@10.7.3: {}
 
   hosted-git-info@2.8.9: {}

+ 56 - 2
src/views/serviceManagement/quickReview/index.vue

@@ -112,7 +112,7 @@
         </div>
       </template>
       <div class="cards" v-masonry :cols="2" :gutter="20" style="width: 100%" v-else>
-        <template v-for="curr in list">
+        <template v-for="(curr, currIndex) in list">
           <div class="card" v-masonry-tile :key="curr.info.taskId" v-if="curr.reviewInfo.show">
             <div class="task-info">
               <div class="task-type-info">
@@ -171,7 +171,17 @@
                     <div class="img-box" v-if="item.imgList">
                       <div v-for="(iItem, index) in item.imgList" :key="index" class="img-box-content">
                         <span class="type">{{ iItem.type }}</span>
-                        <el-image class="img-item" :src="iItem.url" :preview-src-list="getPreviewList(item.previewList, index)" />
+
+                        <el-image
+                          class="img-item"
+                          :src="iItem.url"
+                          :preview-src-list="getPreviewList(item.previewList, index)"
+                          @error="(err) => imgeError(err, item, index, iItem.url)"
+                        >
+                          <div slot="error" class="image-slot">
+                            <i class="el-icon-loading"></i>
+                          </div>
+                        </el-image>
                       </div>
                     </div>
                   </div>
@@ -289,6 +299,7 @@ import { getDictType } from '@/api/common';
 import abbreviationsProvinces from '@/const/abbreviationsProvinces.js';
 import dayjs from 'dayjs';
 import { mapGetters } from 'vuex';
+import heic2any from 'heic2any';
 
 export default {
   components: { refuseReason },
@@ -432,6 +443,41 @@ export default {
     window.removeEventListener('scroll', this.handleScroll);
   },
   methods: {
+    imgeError(err, item, index, url) {
+      this.handleImage(url, item, index);
+    },
+    isHeicFile(file) {
+      return new Promise((resolve, reject) => {
+        const reader = new FileReader();
+        reader.onloadend = () => {
+          const buffer = reader.result;
+          // HEIC 文件的前几个字节为 "00 00 00 18 66 74 79 70 68 65 69 63" 或 "00 00 00 20 66 74 79 70 68 65 69 63" (小端字节序)
+          const signature = new Uint8Array(buffer).subarray(0, 12);
+          const heicSignature = [0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70, 0x68, 0x65, 0x69, 0x63];
+
+          const isHeic = signature.every((byte, index) => byte === heicSignature[index]);
+          resolve(isHeic);
+        };
+        reader.onerror = reject;
+        reader.readAsArrayBuffer(file);
+      });
+    },
+    async handleImage(url, item, index) {
+      const response = await fetch(url);
+      const blob = await response.blob();
+
+      if (await this.isHeicFile(blob)) {
+        const heicImageBlob = await fetch(url).then((res) => res.blob());
+
+        // 使用 heic2any 库将 HEIC 转换为 JPG
+        heic2any({ blob: heicImageBlob, toType: 'image/jpeg' }).then((convertedBlob) => {
+          const imgURL = URL.createObjectURL(convertedBlob);
+          item.imgList[index].url = imgURL;
+          item.previewList[index] = imgURL;
+          this.$forceUpdate();
+        });
+      }
+    },
     handleScroll(event) {
       const scrollHeight = event.target.scrollHeight; // 获取滚动元素的总高度
       const scrollTop = event.target.scrollTop; // 获取滚动元素的当前滚动高度
@@ -1086,4 +1132,12 @@ export default {
   text-align: center;
   font-weight: 600;
 }
+::v-deep .image-slot {
+  width: 100px;
+  height: 100px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 28px;
+}
 </style>

+ 53 - 6
src/views/serviceManagement/servicesToBeReviewed/components/TaskDetail.vue

@@ -49,9 +49,14 @@
               <div class="img-box" v-if="item.imgList">
                 <div v-for="(iItem, index) in item.imgList" :key="index" class="img-box-content">
                   <span class="type">{{ iItem.type }}</span>
-
-                  <img :src="iItem.url" alt="" style="height: 50px; width: 50px" />
-                  <el-image class="img-item" lazy :src="iItem.url" :preview-src-list="getPreviewList(item.previewList, index)" />
+                  <el-image
+                    v-loading="imgErrorLoading"
+                    class="img-item"
+                    @error="(err) => imgeError(err, item, index, iItem.url)"
+                    lazy
+                    :src="iItem.url"
+                    :preview-src-list="getPreviewList(item.previewList, index)"
+                  />
                 </div>
               </div>
             </div>
@@ -90,6 +95,7 @@ import provinces from '@/util/lib/province';
 import citys from '@/util/lib/city';
 import areas from '@/util/lib/area';
 import request from '@/router/axios';
+import heic2any from 'heic2any';
 
 export default {
   name: 'index',
@@ -102,6 +108,7 @@ export default {
       taskTypeId: 0, // 任务类型id
       configList: [], // 配置列表
       dictList: [], //字典
+      imgErrorLoading: false,
       imgTypeList: ['jpeg', 'jpg', 'png', 'git', 'bmp'] // 能查看的文件类型
     };
   },
@@ -135,6 +142,49 @@ export default {
     },
 
     // 得出图片
+    imgeError(err, item, index, url) {
+      this.imgErrorLoading = true;
+      this.handleImage(url, item, index);
+    },
+
+    // 检查文件是否为 HEIC 格式
+    isHeicFile(file) {
+      return new Promise((resolve, reject) => {
+        const reader = new FileReader();
+        reader.onloadend = () => {
+          const buffer = reader.result;
+          // HEIC 文件的前几个字节为 "00 00 00 18 66 74 79 70 68 65 69 63" 或 "00 00 00 20 66 74 79 70 68 65 69 63" (小端字节序)
+          const signature = new Uint8Array(buffer).subarray(0, 12);
+          const heicSignature = [0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70, 0x68, 0x65, 0x69, 0x63];
+
+          const isHeic = signature.every((byte, index) => byte === heicSignature[index]);
+          resolve(isHeic);
+        };
+        reader.onerror = reject;
+        reader.readAsArrayBuffer(file);
+      });
+    },
+
+    async handleImage(url, item, index) {
+      const response = await fetch(url);
+      const blob = await response.blob();
+
+      if (await this.isHeicFile(blob)) {
+        const heicImageBlob = await fetch(url).then((res) => res.blob());
+
+        // 使用 heic2any 库将 HEIC 转换为 JPG
+        heic2any({ blob: heicImageBlob, toType: 'image/jpeg' }).then((convertedBlob) => {
+          const imgURL = URL.createObjectURL(convertedBlob);
+          item.imgList[index].url = imgURL;
+          item.previewList[index] = imgURL;
+          this.$forceUpdate();
+          this.imgErrorLoading = false;
+        });
+      } else {
+        this.imgErrorLoading = false;
+      }
+    },
+
     // 得出图片
     getImgList(urlStr, item) {
       // 如果字段类型不是图片或没有 urlStr,则直接返回空数组
@@ -145,7 +195,6 @@ export default {
       // 如果拆分后为空,也返回空数组
       if (!urlArr.length) return [[], []];
 
-      console.log('urlArr', urlArr);
       // 使用 reduce 一次性构建 imgList 和 previewList
       const [imgList, previewList] = urlArr.reduce(
         (acc, curUrl) => {
@@ -170,8 +219,6 @@ export default {
         [[], []]
       );
 
-      console.log('imgList', [imgList, previewList]);
-
       return [imgList, previewList];
     },