Browse Source

Merge branch 'develop' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev

QM303176530 4 years ago
parent
commit
5b51b89439

+ 2 - 1
web/public/index.html

@@ -3,6 +3,7 @@
 
 <head>
     <meta charset="utf-8">
+    <meta name="renderer" content="webkit">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
     <link rel="icon" href="<%= BASE_URL %>favicon.ico">
@@ -17,4 +18,4 @@
     <!-- built files will be auto injected -->
 </body>
 
-</html>
+</html>

+ 100 - 0
web/src/components/upload/image.vue

@@ -0,0 +1,100 @@
+<!--
+  <div>
+    带压缩的上传
+    <upload-image v-model="imageUrl" :fileSize="512" />
+    已上传文件 {{ imageUrl }}
+  </div>
+
+
+-->
+
+<template>
+  <div>
+    <el-upload
+      class="image-uploader"
+      :action="`${path}/fileUploadAndDownload/upload`"
+      :show-file-list="false"
+      :on-success="handleImageSuccess"
+      :before-upload="beforeImageUpload"
+      :multiple="false"
+    >
+      <img v-if="imageUrl" :src="imageUrl" class="image" />
+      <i v-else class="el-icon-plus image-uploader-icon"></i>
+    </el-upload>
+  </div>
+</template>
+<script>
+const path = process.env.VUE_APP_BASE_API;
+import ImageCompress from "@/utils/image.js";
+export default {
+  name: "upload-image",
+  model: {
+    prop: "imageUrl",
+    event: "change",
+  },
+  props: {
+    imageUrl: {
+      type: String,
+      default: "",
+    },
+    fileSize: {
+      type: Number,
+      default: 2048, // 2M 超出后执行压缩
+    },
+    maxWH: {
+      type: Number,
+      default: 1920, // 图片长宽上限
+    },
+  },
+  data() {
+    return {
+      path: path,
+    };
+  },
+  methods: {
+    beforeImageUpload(file) {
+      let isRightSize = file.size / 1024 < this.fileSize;
+      if (!isRightSize) {
+        // 压缩
+        let compress = new ImageCompress(file, this.fileSize, this.maxWH);
+        return compress.compress();
+      }
+      return isRightSize;
+    },
+    handleImageSuccess(res, file) {
+      // this.imageUrl = URL.createObjectURL(file.raw);
+      const { code, msg, data } = res;
+      if (data.file) {
+        this.$emit("change", data.file.url);
+      }
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.image-uploader {
+  border: 1px dashed #d9d9d9;
+  width: 180px;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.image-uploader {
+  border-color: #409eff;
+}
+.image-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 178px;
+  height: 178px;
+  line-height: 178px;
+  text-align: center;
+}
+.image {
+  width: 178px;
+  height: 178px;
+  display: block;
+}
+</style>

+ 99 - 0
web/src/utils/image.js

@@ -0,0 +1,99 @@
+export default class ImageCompress {
+    constructor(file, fileSize, maxWH = 1920) {
+        this.file = file
+        this.fileSize = fileSize
+        this.maxWH = maxWH // 最大长宽
+    }
+
+    compress() {
+        // 压缩
+        const fileType = this.file.type
+        const fileSize = this.file.size / 1024
+        return new Promise(resolve => {
+            const reader = new FileReader();
+            reader.readAsDataURL(this.file);
+            reader.onload = () => {
+                const canvas = document.createElement('canvas');
+                const img = document.createElement('img');
+                img.src = reader.result;
+                img.onload = () => {
+                    const ctx = canvas.getContext('2d');
+                    let _dWH = this.dWH(img.width, img.height, this.maxWH)
+                    canvas.width = _dWH.width
+                    canvas.height = _dWH.height
+
+                    // 清空后, 重写画布
+                    ctx.clearRect(0, 0, canvas.width, canvas.height)
+                    ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
+
+                    let newImgData = canvas.toDataURL(fileType, 0.90)
+
+                    // 压缩宽高后的图像大小
+                    let newImgSize = this.fileSizeKB(newImgData)
+
+                    if (newImgSize > this.fileSize) {
+                        console.log('图片尺寸太大!' + fileSize + " >> " + newImgSize)
+                        reject(`图片尺寸太大!`)
+                    }
+
+                    let blob = this.dataURLtoBlob(newImgData, fileType)
+                    let nfile = new File([blob], this.file.name);
+                    resolve(nfile)
+                };
+            };
+        });
+    }
+
+    /*
+     * 长宽等比缩小
+     * 图像的一边(长或宽)为最大目标值
+     * */
+    dWH(srcW, srcH, dMax) {
+
+        let defaults = {
+            width: srcW,
+            height: srcH
+        }
+        if (Math.max(srcW, srcH) > dMax) {
+            if (srcW > srcH) {
+                defaults.width = dMax
+                defaults.height = Math.round(srcH * (dMax / srcW))
+                return defaults
+            } else {
+                defaults.height = dMax
+                defaults.width = Math.round(srcW * (dMax / srcH))
+                return defaults
+            }
+        } else {
+            return defaults
+        }
+    }
+
+    fileSizeKB(dataURL) {
+        let self = this
+
+        let sizeKB = 0
+        sizeKB = Math.round((dataURL.split(',')[1].length * 3 / 4) / 1024)
+        return sizeKB
+    }
+
+    /*
+     * 转为Blob
+     * */
+    dataURLtoBlob(dataURL, fileType) {
+        let self = this
+
+        let byteString = atob(dataURL.split(',')[1])
+        let mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0]
+        let ab = new ArrayBuffer(byteString.length)
+        let ia = new Uint8Array(ab)
+        for (let i = 0; i < byteString.length; i++) {
+            ia[i] = byteString.charCodeAt(i)
+        }
+        if (fileType) {
+            mimeString = fileType
+        }
+        return new Blob([ab], { type: mimeString, lastModifiedDate: new Date() })
+    }
+
+}

+ 36 - 19
web/src/view/example/upload/upload.vue

@@ -1,23 +1,33 @@
 <template>
   <div v-loading.fullscreen.lock="fullscreenLoading">
     <div class="upload">
-      <el-upload
-        :action="`${path}/fileUploadAndDownload/upload`"
-        :before-upload="checkFile"
-        :headers="{ 'x-token': token }"
-        :on-error="uploadError"
-        :on-success="uploadSuccess"
-        :show-file-list="false"
-      >
-        <el-button size="small" type="primary">点击上传</el-button>
-        <div class="el-upload__tip" slot="tip">
-          只能上传jpg/png文件,且不超过500kb
-        </div>
-      </el-upload>
+      <el-row>
+        <el-col :span="12">
+          <el-upload
+            :action="`${path}/fileUploadAndDownload/upload`"
+            :before-upload="checkFile"
+            :headers="{ 'x-token': token }"
+            :on-error="uploadError"
+            :on-success="uploadSuccess"
+            :show-file-list="false"
+          >
+            <el-button size="small" type="primary">点击上传</el-button>
+            <div class="el-upload__tip" slot="tip">
+              只能上传jpg/png文件,且不超过500kb
+            </div>
+          </el-upload>
+        </el-col>
+        <el-col :span="12">
+          带压缩的上传, (512(k)为压缩限制)
+          <upload-image v-model="imageUrl" :fileSize="512" :maxWH="1080" />
+          已上传文件 {{ imageUrl }}
+        </el-col>
+      </el-row>
+
       <el-table :data="tableData" border stripe>
         <el-table-column label="预览" width="100">
           <template slot-scope="scope">
-            <CustomPic picType="file" :picSrc="scope.row.url"/>
+            <CustomPic picType="file" :picSrc="scope.row.url" />
           </template>
         </el-table-column>
         <el-table-column label="日期" prop="UpdatedAt" width="180">
@@ -30,7 +40,11 @@
           prop="name"
           width="180"
         ></el-table-column>
-        <el-table-column label="链接" prop="url" min-width="300"></el-table-column>
+        <el-table-column
+          label="链接"
+          prop="url"
+          min-width="300"
+        ></el-table-column>
         <el-table-column label="标签" prop="tag" width="100">
           <template slot-scope="scope">
             <el-tag
@@ -72,26 +86,29 @@ import infoList from "@/components/mixins/infoList";
 import { getFileList, deleteFile } from "@/api/fileUploadAndDownload";
 import { downloadImage } from "@/utils/downloadImg";
 import { formatTimeToStr } from "@/utils/data";
-import CustomPic from '@/components/customPic'
+import CustomPic from "@/components/customPic";
+import UploadImage from "@/components/upload/image.vue";
 export default {
   name: "Upload",
   mixins: [infoList],
   components: {
-		CustomPic
-	},
+    CustomPic,
+    UploadImage,
+  },
   data() {
     return {
       fullscreenLoading: false,
       listApi: getFileList,
       path: path,
       tableData: [],
+      imageUrl: "",
     };
   },
   computed: {
     ...mapGetters("user", ["userInfo", "token"]),
   },
   filters: {
-    formatDate: function(time) {
+    formatDate: function (time) {
       if (time != null && time != "") {
         var date = new Date(time);
         return formatTimeToStr(date, "yyyy-MM-dd hh:mm:ss");