457 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="l-upload">
<view class="upload-box">
<view class="image-item"
:style="{width:width+'rpx',height:height+'rpx','--margin-right':marginRight + 'px',marginRight:(index + 1) % lineNum == 0 ? 0 : marginRight + 'px'}"
v-for="(item, index) in fileList" :key="index">
<view>
<image :src="`${serverUrl}/image/${item.id}`" class="img"
:style="{width:width+'rpx',height:height+'rpx'}" @tap.stop="previewImage(index)"
mode="aspectFill"></image>
<view v-if="!disable" class="img-del" @tap.stop="delImage(index)"></view>
</view>
</view>
<view v-if="isShowAdd" class="upload-add" :style="{'width':width+'rpx',height:height+'rpx'}"
@tap="chooseFile">
<view class="upload-icon icon-tianjia"></view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'lUpload',
props: {
//图片宽度
width: {
type: [Number, String],
default: 220
},
//图片高度
height: {
type: [Number, String],
default: 220
},
// 上传类型 图片img/视频video 默认都可以
uploadType: {
type: String,
default: 'all'
},
//禁用添加
disableAdd: {
type: Boolean,
default: false
},
disable: {
type: Boolean,
default: false
},
//限制数
limit: {
type: Number,
default: 9
},
//original 原图compressed 压缩图,默认二者都有
sizeType: {
type: Array,
default () {
return ['original', 'compressed']
}
},
//album 从相册选图camera 使用相机,默认二者都有。如需直接开相机或直接选相册,请只使用一个选项
sourceType: {
type: Array,
default () {
return ['album', 'camera']
}
},
//可上传图片类型,默认为空,不限制 Array<String> ['jpg','png','gif']
imageFormat: {
type: Array,
default () {
return ['jpg', 'jpeg', 'png', 'gif', 'webp']
}
},
//图片路径
images: {
type: Array,
default () {
return []
}
},
//视频路径
videos: {
type: Array,
default () {
return []
}
},
//服务器接口地址。当接口地址为空时,直接返回本地图片地址
serverUrl: {
type: String,
default: ""
},
//文件对应的key默认为 file
fileKeyName: {
type: String,
default: "file"
},
//HTTP 请求 Header, header 中不能设置 Referer。
header: {
type: Object,
default () {
return {}
}
},
//HTTP 请求中其他额外的 form data
formData: {
type: Object,
default () {
return {}
}
},
//wflow的最大尺寸
maxSize: {
type: Number,
default () {
return 0
}
}
},
data() {
return {
//图片地址
imageList: [...this.images],
//图片地址
videoList: [...this.videos],
fileList: [...this.videos, ...this.images],
marginRight: 0,
lineNum: 0,
videoContext: null,
}
},
computed: {
isShowAdd() {
let isShow = true;
if (this.disableAdd || (this.limit && (this.imageList.length + this.videoList) >= this.limit)) {
isShow = false;
}
return isShow
}
},
mounted() {
this.initBoxData()
},
watch: {
images: {
handler(newVal) {
this.fileList = [...this.videoList, ...this.images]
},
deep: true,
immediate: true
}
},
methods: {
change() {
this.fileList = [...this.videoList, ...this.imageList]
this.$emit('complete', {
imageArr: [...this.imageList],
videoArr: [...this.videoList],
})
},
initBoxData() {
const query = uni.createSelectorQuery().in(this);
query.select('.upload-box').fields({
rect: true, //返回节点布局位置
size: true //返回节点尺寸
}, res => {
let imgwidth = Math.floor(this.width / 2)
this.lineNum = Math.floor(res.width / imgwidth)
this.marginRight = (res.width - this.lineNum * imgwidth) / (this.lineNum - 1)
});
query.exec(); //执行
},
toast(text) {
text && uni.showToast({
title: text,
icon: "none"
});
},
chooseFile() {
if (this.uploadType == 'img') {
this.chooseImage()
} else if (this.uploadType == 'video') {
this.chooseVideo()
} else {
uni.showActionSheet({
itemList: ['图片', '视频'],
success: (res) => {
if (res.tapIndex + 1 == 1) {
this.chooseImage()
} else {
this.chooseVideo()
}
},
fail: function(res) {
console.log(res.errMsg);
}
});
}
},
chooseVideo() {
uni.chooseVideo({
sizeType: this.sizeType,
camera: 'back', //默认摄像头是后置摄像头
success: (e) => {
this.videoList.push(e.tempFilePath)
//服务器地址
if (this.serverUrl) {
this.uploadImage(null, e.tempFilePath, 'video').then(() => {
this.change()
}).catch(() => {
this.change()
})
} else {
//无服务器地址则直接返回成功
this.change()
}
}
})
},
chooseImage() {
uni.chooseImage({
count: this.limit - this.imageList.length - this.videoList.length,
sizeType: this.sizeType,
sourceType: this.sourceType,
success: (e) => {
console.log(e)
let imageArr = [];
for (let i = 0; i < e.tempFiles.length; i++) {
let len = this.imageList.length + this.videoList.length;
if (len >= this.limit) {
this.toast(`最多可上传${this.limit}张图片`);
break;
}
if (this.maxSize > 0 && e.tempFiles[i].size / 1024 / 1024 > this.maxSize) {
this.toast(`单张图片最大${this.maxSize}MB`);
break;
}
//过滤图片类型
let path = e.tempFiles[i].path;
if (this.imageFormat.length > 0) {
let format = ""
// #ifdef H5
let type = e.tempFiles[i].type;
format = type.split('/')[1]
// #endif
// #ifndef H5
format = path.split(".")[(path.split(".")).length - 1];
// #endif
if (this.imageFormat.indexOf(format) == -1) {
let text = `只能上传 ${this.imageFormat.join(',')} 格式图片!`
this.toast(text);
continue;
}
}
imageArr.push(path)
//this.imageList.push(path)
}
let start = this.imageList.length - imageArr.length
for (let j = 0; j < imageArr.length; j++) {
let index = start + j
//服务器地址
if (this.serverUrl) {
this.uploadImage(index, imageArr[j], 'image').then(() => {
this.change()
}).catch(() => {
this.change()
})
} else {
//无服务器地址则直接返回成功
this.change()
}
}
}
})
},
uploadImage(index, url, type) {
return new Promise((resolve, reject) => {
uni.uploadFile({
url: this.serverUrl + '/wflow/res',
header: {
//大家在这里传自定义的token这里默认wflow的
Authorization: "Bearer " + uni.getStorageSync('wflow-token'),
TenantId: JSON.parse(uni.getStorageSync("loginUser")).sn
},
name: this.fileKeyName,
header: this.header,
formData: this.formData,
filePath: url,
success: (res) => {
if (res.statusCode == 200) {
//返回结果 此处需要按接口实际返回进行修改
let data = JSON.parse(res.data.replace(/\ufeff/g, "") || "{}")
//这里注意使用wflow的接口如自行修改的话要修改为自己的系统接口把图片url传入
this.imageList.push(data)
// if (data.code === '根据实际情况修改') {
// if(type === 'image'){//图片 -此处无需修改
// console.log(data)
// this.imageList.push(...data.data)//根据实际情况修改-this.imageList不能改
// }else if(type === 'video'){//视频 -此处无需修改
// this.videoList.push(...data.data)//根据实际情况修改-this.videoList不能改
// }
// } else {
// // 上传失败
// }
resolve(data)
} else {
reject(res.msg)
}
},
fail: function(res) {
reject(res)
}
})
})
},
delVideo(index) {
uni.showModal({
title: '提示',
content: '确认删除该视频吗?',
success: (res) => {
if (res.confirm) {
this.videoList.splice(index, 1)
this.$emit("remove", {
index: index,
type: 'video'
})
this.change()
}
}
})
},
delImage(index) {
uni.showModal({
title: '提示',
content: '确认删除该图片吗?',
success: (res) => {
if (res.confirm) {
this.imageList.splice(index, 1)
this.$emit("remove", {
index: index,
type: 'image'
})
this.change()
}
}
})
},
previewImage(index) {
//根据wflow改造
if (!this.imageList.length) return;
uni.previewImage({
current: this.serverUrl + '/image/' + this.imageList[index].id,
loop: false,
urls: this.imageList.map(v => this.serverUrl + '/image/' + v.id)
})
},
}
}
</script>
<style lang="scss" scoped>
@font-face {
font-family: 'l-icon';
src: url('data:font/ttf;charset=utf-8;base64,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') format('truetype');
font-weight: normal;
font-style: normal;
font-display: swap;
}
.upload-icon {
font-family: "l-icon" !important;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
padding: 10rpx;
}
.icon-tianjia:before {
content: "\e63b";
}
.l-upload {
width: 100%;
.upload-box {
width: 100%;
display: flex;
flex-wrap: wrap;
.image-item,
.upload-add {
margin: 10px;
}
.image-item {
position: relative;
margin-bottom: var(--margin-right);
.img {
display: block;
}
.img-del {
width: 36rpx;
height: 36rpx;
position: absolute;
right: -12rpx;
top: -12rpx;
background-color: #EB0909;
border-radius: 50%;
color: white;
font-size: 34rpx;
//z-index: 200;
&::before {
content: '';
width: 16rpx;
height: 1px;
position: absolute;
left: 10rpx;
top: 18rpx;
background-color: #fff;
}
}
}
.upload-add {
font-size: 68rpx;
font-weight: 100;
color: #888;
background-color: #F7F7F7;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
}
}
}
</style>