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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<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>