You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

345 lines
7.5 KiB
Vue

4 weeks ago
<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>