|
|
<template>
|
|
|
<view class="upload">
|
|
|
<view style="width: 0px; height: 0px; overflow: hidden">
|
|
|
<canvas id="canone" :style="{ width: imageWidth + 'px', height: imageHeight + 'px' }" canvas-id="canone" />
|
|
|
</view>
|
|
|
<view class="upload__preview">
|
|
|
<view v-for="(item, index) in lists" :key="index" class="upload__preview--item"
|
|
|
:class="{ 'both-width': both, 'third-width': !both }">
|
|
|
<view class="upload__preview--imagebox" :class="{ both: both, third: !both }">
|
|
|
<image class="upload__preview--image" :src="item.fileUrl" @click="previewImage(index)"></image>
|
|
|
<u-icon v-if="!detail" class="upload__preview--close" name="close-circle-fill" color="#666666"
|
|
|
size="20" @click="deleteImageList(index)"></u-icon>
|
|
|
</view>
|
|
|
<view v-if="desc" :class="{ both: both, third: !both }" class="upload__up--desc u-line-1"
|
|
|
:style="{ color: descColor }">
|
|
|
{{ desc }}
|
|
|
</view>
|
|
|
</view>
|
|
|
<view v-if="!detail && lists.length < maxCount" class="upload__up"
|
|
|
:class="{ 'both-width': both, 'third-width': !both }">
|
|
|
<view class="upload__up--btn" :class="{ 'both-border both': both, third: !both }" @click="selectFile">
|
|
|
<u-icon name="plus" size="50"></u-icon>
|
|
|
</view>
|
|
|
<view v-if="desc" :class="{ both: both, third: !both }" class="upload__up--desc u-line-1"
|
|
|
:style="{ color: descColor }">
|
|
|
{{ desc }}
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
|
|
|
<script>
|
|
|
import Api from '@/api/api.js';
|
|
|
export default {
|
|
|
props: {
|
|
|
waterMark: {
|
|
|
type: Boolean,
|
|
|
default: false
|
|
|
},
|
|
|
// 上传数
|
|
|
maxCount: {
|
|
|
type: Number,
|
|
|
default: 9,
|
|
|
},
|
|
|
deleteable: {
|
|
|
type: Boolean,
|
|
|
default: true
|
|
|
},
|
|
|
detail: {
|
|
|
type: Boolean,
|
|
|
default: false
|
|
|
},
|
|
|
desc: {
|
|
|
|
|
|
default: ""
|
|
|
},
|
|
|
descColor: {
|
|
|
|
|
|
default: "#2593F2",
|
|
|
},
|
|
|
delColor: {
|
|
|
|
|
|
default: "#666666"
|
|
|
},
|
|
|
both: {
|
|
|
type: Boolean,
|
|
|
default: false
|
|
|
},
|
|
|
maxSize: {
|
|
|
type: Number,
|
|
|
default: 10
|
|
|
},
|
|
|
limitType: {
|
|
|
type: Array,
|
|
|
default: () => ['png', 'jpg', 'jpeg', 'gif', 'webp', 'image']
|
|
|
},
|
|
|
value: {
|
|
|
type: Array,
|
|
|
default: () => []
|
|
|
},
|
|
|
ossFileDTOList:{
|
|
|
type: Array,
|
|
|
default: () => []
|
|
|
},
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
lists: [],
|
|
|
imageWidth: 300,
|
|
|
imageHeight: 500
|
|
|
};
|
|
|
},
|
|
|
watch: {
|
|
|
value: {
|
|
|
handler(val, oval) {
|
|
|
this.lists = val
|
|
|
},
|
|
|
deep: true, //是否深度监听
|
|
|
immediate: true, //是否监听初始
|
|
|
},
|
|
|
|
|
|
},
|
|
|
methods: {
|
|
|
/**
|
|
|
* 图片预览
|
|
|
*/
|
|
|
|
|
|
previewImage(index) {
|
|
|
uni.previewImage({
|
|
|
current: index,
|
|
|
urls: this.lists[index].fileUrl,
|
|
|
indicator: 'default',
|
|
|
loop: true
|
|
|
})
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* 删除图片
|
|
|
*/
|
|
|
deleteImageList(index) {
|
|
|
let deleteList = this.lists.splice(index, 1)
|
|
|
this.$emit('update: ossFileDTOList', deleteList)
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* 选择图片,校验图片格式和图片大小
|
|
|
*/
|
|
|
selectFile() {
|
|
|
const {
|
|
|
maxSize,
|
|
|
maxCount,
|
|
|
waterMark
|
|
|
} = this
|
|
|
let chooseFile = null
|
|
|
chooseFile = new Promise((resolve, reject) => {
|
|
|
uni.chooseImage({
|
|
|
count: 10, // 为了避免麻烦,偷懒,限制了只能选择一张
|
|
|
success: resolve,
|
|
|
fail: reject
|
|
|
})
|
|
|
})
|
|
|
chooseFile
|
|
|
.then((res) => {
|
|
|
// 检查文件后缀是否允许,如果不在this.limitType内,就会返回false
|
|
|
let file = res.tempFiles[0]
|
|
|
if (!this.checkFileType(file)) {
|
|
|
return
|
|
|
}
|
|
|
if (file.size > maxSize * 1024 * 1024) {
|
|
|
this.$u.toast('最大允许上传' + maxSize + 'MB的图片')
|
|
|
return
|
|
|
}
|
|
|
if (this.lists.length >= maxCount) {
|
|
|
this.$u.toast('最多允许上传' + maxCount + '张图片')
|
|
|
return
|
|
|
}
|
|
|
let tempFilePath = res.tempFilePaths[0]
|
|
|
if (waterMark) {
|
|
|
this.uploadWaterMarkImage(tempFilePath)
|
|
|
} else {
|
|
|
this.uploadImage(tempFilePath)
|
|
|
}
|
|
|
})
|
|
|
.catch((error) => {
|
|
|
this.$emit('on-choose-fail', error)
|
|
|
})
|
|
|
},
|
|
|
|
|
|
// 图片上传
|
|
|
uploadImage(tempFilePath) {
|
|
|
|
|
|
uni.getImageInfo({
|
|
|
src: tempFilePath,
|
|
|
success: (res) => {
|
|
|
Api.storge.getPolicy({
|
|
|
bucket: "public-aaf-shenzhen-file"
|
|
|
}).then(({
|
|
|
data
|
|
|
}) => {
|
|
|
const fileName = res.path.substring(res.path.lastIndexOf("/") + 1)
|
|
|
res.name = fileName
|
|
|
const keyName = data.dir + fileName
|
|
|
const querData = {
|
|
|
key: keyName,
|
|
|
policy: data.policy,
|
|
|
OSSAccessKeyId: data.accessid,
|
|
|
success_action_status: "200",
|
|
|
signature: data.signature,
|
|
|
file: res
|
|
|
}
|
|
|
uni.uploadFile({
|
|
|
url: data.host,
|
|
|
filePath: res.path, // 随便填,不为空即可
|
|
|
name: 'file', // 随便填,不为空即可
|
|
|
formData: querData, // 接口参数,json格式,底层自动转为FormData的格式数据
|
|
|
complete: (res) => {
|
|
|
const fileUrl = `${data.host}/${data.dir}${fileName}`;
|
|
|
this.lists.push({fileUrl,fileName,})
|
|
|
this.$emit('update: ossFileDTOList', this.lists)
|
|
|
|
|
|
}
|
|
|
})
|
|
|
|
|
|
|
|
|
})
|
|
|
},
|
|
|
})
|
|
|
},
|
|
|
|
|
|
// 图片添加水印后上传
|
|
|
uploadWaterMarkImage(tempFilePath) {
|
|
|
uni.getImageInfo({
|
|
|
src: tempFilePath,
|
|
|
success: (res) => {
|
|
|
this.imageWidth = res.width
|
|
|
this.imageHeight = res.height
|
|
|
// 组件调用时读不到canvas,所以需要将this传入进去,同时,上传水印那里也需要把当前的this传入
|
|
|
let ctx = uni.createCanvasContext('canone', this) // 创建画布
|
|
|
let data = {
|
|
|
that: this,
|
|
|
filePath: tempFilePath,
|
|
|
extensionName: '.' + res.type,
|
|
|
ctx: ctx,
|
|
|
height: res.height,
|
|
|
width: res.width
|
|
|
}
|
|
|
// uploadWaterMarkImage(data)
|
|
|
// .then((image) => {
|
|
|
// this.lists.push(image.url)
|
|
|
// this.$emit('on-success', image, this.lists)
|
|
|
// this.$emit('on-change', this.lists)
|
|
|
// })
|
|
|
// .catch((err) => {
|
|
|
// this.uploadError(err)
|
|
|
// })
|
|
|
},
|
|
|
})
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* 上传失败
|
|
|
*/
|
|
|
uploadError(err) {
|
|
|
this.$emit('on-error', err, this.lists)
|
|
|
// this.$u.toast('上传失败,请重试')
|
|
|
},
|
|
|
|
|
|
// 判断文件后缀是否允许
|
|
|
checkFileType(file) {
|
|
|
// 检查是否在允许的后缀中
|
|
|
let flag = false
|
|
|
// 获取后缀名
|
|
|
let fileType = ''
|
|
|
const reg = /.+\./
|
|
|
fileType = file.path.replace(reg, '').toLowerCase()
|
|
|
// 只要符合limitType中的一个,就返回true
|
|
|
flag = this.limitType.some((ext) => {
|
|
|
// 转为小写
|
|
|
return ext?.toLowerCase() === fileType
|
|
|
})
|
|
|
if (!flag) {
|
|
|
// this.$u.toast(`不允许选择${fileType}格式的文件`)
|
|
|
}
|
|
|
return flag
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
<style lang="scss">
|
|
|
.upload {
|
|
|
&__preview {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
&--item {
|
|
|
margin-top: 20rpx;
|
|
|
}
|
|
|
|
|
|
&--imagebox {
|
|
|
position: relative;
|
|
|
}
|
|
|
|
|
|
&--image {
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
}
|
|
|
|
|
|
&--close {
|
|
|
position: absolute;
|
|
|
top: -12rpx;
|
|
|
right: -12rpx;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
&__up {
|
|
|
margin-top: 20rpx;
|
|
|
|
|
|
&--btn {
|
|
|
border-radius: 6rpx;
|
|
|
background: #f0f2f4;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
|
|
|
&--desc {
|
|
|
height: 60rpx !important;
|
|
|
line-height: 60rpx;
|
|
|
font-size: 28rpx;
|
|
|
text-align: center;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.both {
|
|
|
width: 310rpx;
|
|
|
height: 240rpx;
|
|
|
}
|
|
|
|
|
|
.both-width {
|
|
|
width: 50%;
|
|
|
|
|
|
}
|
|
|
|
|
|
.both-border {
|
|
|
border: 1rpx dashed #2593f2;
|
|
|
}
|
|
|
.upload__up{
|
|
|
|
|
|
}
|
|
|
.third {
|
|
|
margin-right: 130rpx;
|
|
|
width: 190rpx;
|
|
|
height: 190rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
.third-width {
|
|
|
width: 33.3%;
|
|
|
|
|
|
}
|
|
|
}
|
|
|
</style> |