|
|
@@ -1,298 +1,99 @@
|
|
|
<template>
|
|
|
- <div class="component-upload-image">
|
|
|
- <el-upload
|
|
|
- :action="uploadImgUrl"
|
|
|
- list-type="picture-card"
|
|
|
- :on-success="handleUploadSuccess"
|
|
|
- :before-upload="handleBeforeUpload"
|
|
|
- :limit="limit"
|
|
|
- :on-error="handleUploadError"
|
|
|
- :on-exceed="handleExceed"
|
|
|
- name="file"
|
|
|
- :on-remove="handleRemove"
|
|
|
- :show-file-list="true"
|
|
|
- :file-list="fileList"
|
|
|
- :on-preview="handlePictureCardPreview"
|
|
|
- :class="{hide: this.fileList.length >= this.limit}"
|
|
|
- >
|
|
|
- <i class="el-icon-plus"></i>
|
|
|
- </el-upload>
|
|
|
-
|
|
|
- <!-- 上传提示 -->
|
|
|
-<!-- <div class="el-upload__tip" slot="tip" v-if="showTip">
|
|
|
- 请上传
|
|
|
- <template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
|
|
|
- <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
|
|
|
- 的文件
|
|
|
- </div> -->
|
|
|
-
|
|
|
- <el-dialog
|
|
|
- :visible.sync="dialogVisible"
|
|
|
- title="预览"
|
|
|
- width="800"
|
|
|
- append-to-body
|
|
|
- >
|
|
|
- <img
|
|
|
- :src="dialogImageUrl"
|
|
|
- style="display: block; max-width: 100%; margin: 0 auto"
|
|
|
- />
|
|
|
- </el-dialog>
|
|
|
+ <div class="component-upload-image" :class="{ 'is-disabled': disabled }">
|
|
|
+ <MaterialSingle
|
|
|
+ v-if="imageLimit <= 1"
|
|
|
+ :value="singleUrl"
|
|
|
+ type="image"
|
|
|
+ :num="1"
|
|
|
+ :width="width"
|
|
|
+ :height="height"
|
|
|
+ :allow-upload="allowUpload"
|
|
|
+ @input="handleSingleInput"
|
|
|
+ />
|
|
|
+ <MaterialMulti
|
|
|
+ v-else
|
|
|
+ :value="urlArray"
|
|
|
+ type="image"
|
|
|
+ :num="imageLimit"
|
|
|
+ :width="width"
|
|
|
+ :height="height"
|
|
|
+ :allow-upload="allowUpload"
|
|
|
+ @input="handleMultiInput"
|
|
|
+ />
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import { getToken } from "@/utils/auth";
|
|
|
-
|
|
|
-import { Loading } from 'element-ui';
|
|
|
+import MaterialSingle from '@/components/Material/single'
|
|
|
+import MaterialMulti from '@/components/Material/index'
|
|
|
|
|
|
export default {
|
|
|
+ name: 'ImageUpload',
|
|
|
+ components: { MaterialSingle, MaterialMulti },
|
|
|
props: {
|
|
|
value: [String, Object, Array],
|
|
|
- // 图片数量限制
|
|
|
+ /** 最多选取张数;兼容旧 prop num */
|
|
|
limit: {
|
|
|
type: Number,
|
|
|
- default: 10,
|
|
|
+ default: 10
|
|
|
+ },
|
|
|
+ num: {
|
|
|
+ type: Number,
|
|
|
+ default: undefined
|
|
|
+ },
|
|
|
+ width: {
|
|
|
+ type: Number,
|
|
|
+ default: 148
|
|
|
},
|
|
|
- // 大小限制(MB)
|
|
|
- fileSize: {
|
|
|
- type: Number,
|
|
|
- default: 500,
|
|
|
+ height: {
|
|
|
+ type: Number,
|
|
|
+ default: 148
|
|
|
},
|
|
|
- // 文件类型, 例如['png', 'jpg', 'jpeg']
|
|
|
- fileType: {
|
|
|
- type: Array,
|
|
|
- default: () => ["png", "jpg", "jpeg"],
|
|
|
+ disabled: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
},
|
|
|
- // 是否显示提示
|
|
|
- isShowTip: {
|
|
|
+ /** 素材库弹窗内是否允许上传新素材 */
|
|
|
+ allowUpload: {
|
|
|
type: Boolean,
|
|
|
default: true
|
|
|
- }
|
|
|
- },
|
|
|
- data() {
|
|
|
- return {
|
|
|
- finalQuality:1,
|
|
|
- dialogImageUrl: "",
|
|
|
- dialogVisible: false,
|
|
|
- hideUpload: false,
|
|
|
- baseUrl: process.env.VUE_APP_BASE_API,
|
|
|
- uploadImgUrl: process.env.VUE_APP_BASE_API+"/common/uploadOSS", // 上传的图片服务器地址
|
|
|
- headers: {
|
|
|
- Authorization: "Bearer " + getToken(),
|
|
|
- },
|
|
|
- fileList: []
|
|
|
- };
|
|
|
- },
|
|
|
- watch: {
|
|
|
- value: {
|
|
|
- handler(val) {
|
|
|
- if (val) {
|
|
|
- // 首先将值转为数组
|
|
|
- const list = Array.isArray(val) ? val : this.value.split(',');
|
|
|
- // 然后将数组转为对象数组
|
|
|
- this.fileList = list.map(item => {
|
|
|
- if (typeof item === "string") {
|
|
|
- if (item.indexOf(this.baseUrl) === -1) {
|
|
|
- item = { name: item, url: item };
|
|
|
- } else {
|
|
|
- item = { name: item, url: item };
|
|
|
- }
|
|
|
- }
|
|
|
- return item;
|
|
|
- });
|
|
|
- } else {
|
|
|
- this.fileList = [];
|
|
|
- return [];
|
|
|
- }
|
|
|
- },
|
|
|
- deep: true,
|
|
|
- immediate: true
|
|
|
- }
|
|
|
+ },
|
|
|
+ // 以下保留兼容,不再使用
|
|
|
+ fileSize: Number,
|
|
|
+ fileType: Array,
|
|
|
+ isShowTip: Boolean,
|
|
|
+ type: String
|
|
|
},
|
|
|
computed: {
|
|
|
- // 是否显示提示
|
|
|
- showTip() {
|
|
|
- return this.isShowTip && (this.fileType || this.fileSize);
|
|
|
+ imageLimit() {
|
|
|
+ return this.num != null ? this.num : this.limit
|
|
|
},
|
|
|
+ singleUrl() {
|
|
|
+ if (!this.value) return ''
|
|
|
+ if (Array.isArray(this.value)) return this.value[0] || ''
|
|
|
+ return String(this.value).split(',').filter(Boolean)[0] || ''
|
|
|
+ },
|
|
|
+ urlArray() {
|
|
|
+ if (!this.value) return []
|
|
|
+ if (Array.isArray(this.value)) return this.value.filter(Boolean)
|
|
|
+ return String(this.value).split(',').filter(Boolean)
|
|
|
+ }
|
|
|
},
|
|
|
methods: {
|
|
|
- // 删除图片
|
|
|
- handleRemove(file, fileList) {
|
|
|
- const findex = this.fileList.map(f => f.name).indexOf(file.name);
|
|
|
- if(findex > -1) {
|
|
|
- this.fileList.splice(findex, 1);
|
|
|
- this.$emit("input", this.listToString(this.fileList));
|
|
|
- }
|
|
|
+ handleSingleInput(url) {
|
|
|
+ this.$emit('input', url || '')
|
|
|
},
|
|
|
- // 上传成功回调
|
|
|
- handleUploadSuccess(res) {
|
|
|
- console.log(res)
|
|
|
- this.fileList.push({ name: res.url, url: res.url });
|
|
|
- this.$emit("input", this.listToString(this.fileList));
|
|
|
- this.loading.close();
|
|
|
- },
|
|
|
- // 上传前loading加载
|
|
|
- handleBeforeUpload(file) {
|
|
|
- let isImg = false;
|
|
|
- if (this.fileType.length) {
|
|
|
- let fileExtension = "";
|
|
|
- if (file.name.lastIndexOf(".") > -1) {
|
|
|
- fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
|
|
|
- }
|
|
|
- isImg = this.fileType.some(type => {
|
|
|
- if (file.type.indexOf(type) > -1) return true;
|
|
|
- if (fileExtension && fileExtension.indexOf(type) > -1) return true;
|
|
|
- return false;
|
|
|
- });
|
|
|
- } else {
|
|
|
- isImg = file.type.indexOf("image") > -1;
|
|
|
- }
|
|
|
-
|
|
|
- if (!isImg) {
|
|
|
- this.$message.error(
|
|
|
- `文件格式不正确, 请上传${this.fileType.join("/")}图片格式文件!`
|
|
|
- );
|
|
|
- return false;
|
|
|
- }
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- if (file.size / 1024 / 1024 > 3) {
|
|
|
- this.$message.error('上传的图片不能超过3MB');
|
|
|
- reject();
|
|
|
- return;
|
|
|
- }
|
|
|
- if (file.size / 1024 / 1024 > 1) {
|
|
|
- const loadingInstance = Loading.service({ text: '图片内存过大正在压缩图片...' });
|
|
|
- // 文件大于1MB时进行压缩
|
|
|
- this.compressImage(file).then((compressedFile) => {
|
|
|
- loadingInstance.close();
|
|
|
- if (compressedFile.size / 1024 > 500) {
|
|
|
- this.$message.error('图片压缩后仍大于500KB');
|
|
|
- reject();
|
|
|
- } else {
|
|
|
- // this.$message.success(`图片压缩成功,最终质量为: ${this.finalQuality.toFixed(2)}`);
|
|
|
- console.log(`图片压缩成功,最终质量为: ${this.finalQuality.toFixed(2)}`);
|
|
|
- console.log(`最终内存大小为: ${(compressedFile.size/1024).toFixed(2)}KB`);
|
|
|
- resolve(compressedFile);
|
|
|
- }
|
|
|
- }).catch((err) => {
|
|
|
- loadingInstance.close();
|
|
|
- console.error(err);
|
|
|
- reject();
|
|
|
- });
|
|
|
- } else {
|
|
|
- resolve(file);
|
|
|
- }
|
|
|
- this.loading = this.$loading({
|
|
|
- lock: true,
|
|
|
- text: "上传中",
|
|
|
- background: "rgba(0, 0, 0, 0.7)",
|
|
|
- });
|
|
|
- });
|
|
|
- // if (this.fileSize) {
|
|
|
- // const isLt = file.size / 1024 < this.fileSize;
|
|
|
- // if (!isLt) {
|
|
|
- // this.$message.error(`上传头像图片大小不能超过 ${this.fileSize} KB!`);
|
|
|
- // return false;
|
|
|
- // }
|
|
|
- // }
|
|
|
-
|
|
|
- },
|
|
|
- compressImage(file) {
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- const reader = new FileReader();
|
|
|
- reader.readAsDataURL(file);
|
|
|
- reader.onload = (event) => {
|
|
|
- const img = new Image();
|
|
|
- img.src = event.target.result;
|
|
|
- img.onload = () => {
|
|
|
- const canvas = document.createElement('canvas');
|
|
|
- const ctx = canvas.getContext('2d');
|
|
|
- const width = img.width;
|
|
|
- const height = img.height;
|
|
|
- canvas.width = width;
|
|
|
- canvas.height = height;
|
|
|
- ctx.drawImage(img, 0, 0, width, height);
|
|
|
-
|
|
|
- let quality = 1; // 初始压缩质量
|
|
|
- let dataURL = canvas.toDataURL('image/jpeg', quality);
|
|
|
-
|
|
|
- // 逐步压缩,直到图片大小小于500KB并且压缩质量不再降低
|
|
|
- while (dataURL.length / 1024 > 500 && quality > 0.1) {
|
|
|
- quality -= 0.01;
|
|
|
- dataURL = canvas.toDataURL('image/jpeg', quality);
|
|
|
- }
|
|
|
- this.finalQuality = quality; // 存储最终的压缩质量
|
|
|
-
|
|
|
- if (dataURL.length / 1024 > 500) {
|
|
|
- reject(new Error('压缩后图片仍然大于500KB'));
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- const arr = dataURL.split(',');
|
|
|
- const mime = arr[0].match(/:(.*?);/)[1];
|
|
|
- const bstr = atob(arr[1]);
|
|
|
- let n = bstr.length;
|
|
|
- const u8arr = new Uint8Array(n);
|
|
|
- while (n--) {
|
|
|
- u8arr[n] = bstr.charCodeAt(n);
|
|
|
- }
|
|
|
- const compressedFile = new Blob([u8arr], { type: mime });
|
|
|
- compressedFile.name = file.name;
|
|
|
- resolve(compressedFile);
|
|
|
- };
|
|
|
- img.onerror = (error) => {
|
|
|
- reject(error);
|
|
|
- };
|
|
|
- };
|
|
|
- reader.onerror = (error) => {
|
|
|
- reject(error);
|
|
|
- };
|
|
|
- });
|
|
|
- },
|
|
|
- // 文件个数超出
|
|
|
- handleExceed() {
|
|
|
- this.$message.error(`上传文件数量不能超过 ${this.limit} 个!`);
|
|
|
- },
|
|
|
- // 上传失败
|
|
|
- handleUploadError() {
|
|
|
- this.$message({
|
|
|
- type: "error",
|
|
|
- message: "上传失败",
|
|
|
- });
|
|
|
- this.loading.close();
|
|
|
- },
|
|
|
- // 预览
|
|
|
- handlePictureCardPreview(file) {
|
|
|
- console.log(file)
|
|
|
- this.dialogImageUrl = file.url;
|
|
|
- this.dialogVisible = true;
|
|
|
- },
|
|
|
- // 对象转成指定字符串分隔
|
|
|
- listToString(list, separator) {
|
|
|
- let strs = "";
|
|
|
- separator = separator || ",";
|
|
|
- for (let i in list) {
|
|
|
- strs += list[i].url.replace(this.baseUrl, "") + separator;
|
|
|
- }
|
|
|
- return strs != '' ? strs.substr(0, strs.length - 1) : '';
|
|
|
+ handleMultiInput(arr) {
|
|
|
+ const list = Array.isArray(arr) ? arr.filter(Boolean) : []
|
|
|
+ this.$emit('input', list.join(','))
|
|
|
}
|
|
|
}
|
|
|
-};
|
|
|
-</script>
|
|
|
-<style scoped lang="scss">
|
|
|
-// .el-upload--picture-card 控制加号部分
|
|
|
-::v-deep.hide .el-upload--picture-card {
|
|
|
- display: none;
|
|
|
-}
|
|
|
-// 去掉动画效果
|
|
|
-::v-deep .el-list-enter-active,
|
|
|
-::v-deep .el-list-leave-active {
|
|
|
- transition: all 0s;
|
|
|
}
|
|
|
+</script>
|
|
|
|
|
|
-::v-deep .el-list-enter, .el-list-leave-active {
|
|
|
- opacity: 0;
|
|
|
- transform: translateY(0);
|
|
|
+<style scoped lang="scss">
|
|
|
+.is-disabled {
|
|
|
+ pointer-events: none;
|
|
|
+ opacity: 0.6;
|
|
|
}
|
|
|
</style>
|
|
|
-
|