/* ossUpload.js */
import OSS from 'ali-oss';
import Compressor from 'compressorjs';
import { randomString } from '@/utils/index.js';
const { accessKeyId, accessKeySecret, region, endpoint } = {
region: 'oss-cn-hangzhou',
accessKeyId: '',
accessKeySecret: '',
endpoint: 'oss-cn-hangzhou.aliyuncs.com'
};
const client = new OSS({
// yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
region: region,
// 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
accessKeyId: accessKeyId,
accessKeySecret: accessKeySecret,
endpoint: endpoint,
// 填写Bucket名称。
bucket: 'xxx'
});
/**
* 图片压缩
*/
function compressImage(fileList, backType, limitSize, quality) {
const promiseAry = [];
const maxSize = limitSize * 1024 * 1024;
fileList.forEach(image => {
promiseAry.push(new Promise((resolve, reject) => {
if (image.size <= maxSize) { // 没操过限制,不用压缩
resolve(image)
}
else {
new Compressor(image, {
// maxWidth: 750,
// maxHeight: 750,
quality: quality || 0.8,
success(result) {
let file = new File([result], image.name, { type: image.type })
if (!backType || backType == 'blob') {
resolve(result)
} else if (backType == 'file') {
resolve(file)
} else {
resolve(file)
}
},
error(err) {
console.log('图片压缩失败---->>>>>', err)
resolve(image)
}
})
}
}))
})
return Promise.all(promiseAry)
}
const defaultLimit = 1;
/**
*
* @param fileList 上传图片的资源路径
* @param dir oss要保存的文件夹
* @param limitSize oss图片限制 默认1m 0为不限制
* @returns {OSS文件路径}
*/
async function uploadOSS(fileList, dir = 'file', {
limitSize = defaultLimit, compress = false
}) {
return new Promise((resolve, reject) => {
const promiseAry = [];
let randomVal, randomStr, imgtype, fileName, tmpAry, maxSize = limitSize * 1024 * 1024;
let _Promise = compress ? compressImage(fileList, 'file', limitSize) : Promise.resolve(fileList)
if (compress) {
console.log('压缩前的图片列表', fileList)
}
_Promise.then(fileList => {
if (compress) {
console.log('压缩后的图片列表', fileList)
}
const canUploadList = limitSize == 0 ? fileList : fileList.filter(file => file.size <= maxSize);
canUploadList.forEach(file => {
tmpAry = file.name.split('.');
imgtype = tmpAry[tmpAry.length - 1]
randomVal = +new Date();
randomStr = randomString()
fileName = `${randomVal}_${randomStr}.${imgtype}`
promiseAry.push(client.put(`${dir}/${fileName}`, file, {
headers: {
'aa': 'aa'
}
}))
})
Promise.all(promiseAry).then(result => {
let code = canUploadList.length == fileList.length ? 1 : 0
resolve({
result,
code,
msg: code == 1 ? '上传成功' : `${fileList.length == 1 ? '' : '部分'}图片大小超过${limitSize}M`
});
}).catch(e => {
reject(e)
})
})
});
}
export { uploadOSS, defaultLimit }
<template>
<div>
<div class="flex-wrap">
<div class="oss-upload">
<slot></slot>
<label v-if="!disabled" class="hand">
<input
:multiple="multiple"
type="file"
class="hidden"
@change="change"
/>
</label>
</div>
<el-button
v-if="!disabled && onDelete && value"
@click="handleDelete"
type="text"
size="small"
>删除</el-button
>
</div>
<draggable
class="drag-list"
v-if="!disabled && showFileList && filelist.length > 0"
v-model="filelist"
@change="drag"
>
<div class="drag-item" v-for="(item, idx) in filelist" :key="idx">
<img class="drag-item-img" :src="item" />
<i class="el-icon-error" @click="remove(idx)"></i>
</div>
</draggable>
<template v-else-if="showFileList && filelist.length > 0">
<div class="drag-list">
<div class="drag-item" v-for="(item, idx) in filelist" :key="idx">
<img class="drag-item-img" :src="item" />
</div>
</div>
</template>
</div>
</template>
<script>
import draggable from "vuedraggable";
import { uploadOSS, defaultLimit } from "@/utils/ossUpload";
export default {
components: {
draggable,
},
props: {
value: String,
limit: [String, Number],
disabled: {
type: Boolean,
default: false,
},
compress: {
type: Boolean,
default: false,
},
showUploadResult: {
type: Boolean,
default: true,
},
multiple: {
type: Boolean,
default: false,
},
showFileList: {
type: Boolean,
default: false,
},
fileList: {
type: Array,
default: () => [],
},
onBeforeUpload: {
type: Function,
default: () => {},
},
onSuccess: {
type: Function,
default: () => {},
},
onError: {
type: Function,
default: () => {},
},
onChange: {
type: Function,
default: () => {},
},
onDelete: {
type: Function,
default: null,
},
dir: {
type: String,
default: "file",
},
},
watch: {
fileList: {
handler(val) {
this.filelist = val || [];
},
immediate: true,
},
},
data() {
return {
filelist: [],
};
},
methods: {
clearFileList() {
this.filelist = [];
},
handleDelete() {
this.onDelete && this.onDelete();
},
remove(index) {
this.filelist = this.filelist.filter((item, idx) => idx !== index);
this.onChange(this.filelist);
},
drag() {
this.onChange(this.filelist);
},
change(e) {
const files = Array.from(e.target.files);
const limit = Number(this.limit);
// 限制图片类型
const _files = files.filter((d) => {
if (d.type == "image/png" || d.type == "image/jpeg") {
return true;
} else {
return false;
}
});
e.target.value = null;
// 存在不符合的图片类型
if (_files.length !== files.length) {
this.$message.warning("图片类型不是png或者jpeg");
}
// 没有有效的图片直接返回
if (_files.length === 0) {
return;
}
this.onBeforeUpload(); // 上传前钩子
uploadOSS(_files, this.dir, {
limitSize: isNaN(limit) ? defaultLimit : limit,
compress: this.compress,
})
.then(({ result, code, msg }) => {
this.showUploadResult &&
this.$message({
type: code == 1 ? "success" : "warning",
message: msg,
});
result.forEach((res) => {
this.filelist.push(res.url);
});
if (this.multiple || this.filelist[this.filelist.length - 1]) {
this.onSuccess(
result,
this.multiple
? this.filelist
: this.filelist[this.filelist.length - 1]
);
}
})
.catch((err) => {
console.error(err);
this.onError(err);
});
},
},
};
</script>
<style scoped>
.oss-upload img {
display: block;
}
.flex-wrap {
display: inline-flex;
align-items: center;
}
.oss-upload {
display: inline-block;
position: relative;
margin-right: 10px;
}
.hand {
z-index: 99;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.hidden {
display: none;
}
.el-icon-error {
position: absolute;
right: -7px;
top: -7px;
font-size: 18px;
cursor: pointer;
color: #f56c6c;
}
.drag-list {
display: flex;
flex-wrap: wrap;
padding: 20px 0;
}
.drag-item {
position: relative;
margin-right: 10px;
}
.drag-item-img {
object-fit: contain;
width: 100px;
height: 100px;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>