OA/components/UploadDemo.vue

290 lines
7.7 KiB
Vue
Raw Permalink Normal View History

2023-11-05 00:08:34 +08:00
<template>
<view>
<view class="upload-wrap">
<view class="btn-click mgb-16 upload-btn" @click="handleUploadClick" v-show="!disabled">
<image :src="icons.upload" mode="aspectFill" class="upload-icon" />
<text class="upload-text">上传{{ title[type] }}</text>
</view>
<view class="mgb-16 file-wrap" v-for="(item, index) in fileList" :key="index">
<view class="btn-click file-line" @click="handlePreview(item)">
<!-- <view class="btn-click file-line" @click="handleUploadFile(item)"> -->
<view class="file-info">
<image :src="icons[item.fileType || 'file']" mode="aspectFill" class="file-icon" />
<text class="file-name">{{ item.name || title[type] }}</text>
</view>
<image :src="icons.close" mode="aspectFill" class="file-icon" v-if="!disabled"
@click.stop="handleDeleteFile(index)" />
</view>
</view>
<view class="mgb-16 file-wrap" v-if="fileList.length === 0 && disabled">
<view class="file-line">
<text class="file-empty">暂无数据</text>
</view>
</view>
</view>
<xe-upload ref="XeUpload" :options="uploadOptions" @callback="handleUploadCallback"></xe-upload>
</view>
</template>
<script>
export default {
name: 'UploadDemo',
components: {},
props: {
type: {
default: 'image', // image, video, file
type: String,
},
list: {
default: () => ([]),
type: Array,
},
disabled: {
default: false,
type: Boolean,
},
},
data() {
return {
// uploadOptions 参数跟uni.uploadFile的参数是一样的除了类型为Function的属性
uploadOptions: {
// url: 'http://192.168.31.185:3000/api/upload', // 不传入上传地址则返回本地链接
},
fileList: [],
title: {
image: '图片',
video: '视频',
file: '文件',
},
icons: {
upload: '/static/icon_upload.png',
close: '/static/icon_close.png',
image: '/static/icon_image.png',
video: '/static/icon_video.png',
file: '/static/icon_file.png',
},
};
},
watch: {
list: {
handler(val) {
this.fileList = val || [];
},
immediate: true,
deep: true,
},
},
methods: {
handleUploadClick() {
// 使用默认配置则不需要传入第二个参数
// App、H5 文件拓展名过滤 { extension: ['.doc', '.docx'] } 或者 { extension: '.doc, .docx' }
this.$refs.XeUpload.upload(this.type);
// 可以根据当前的平台,传入选择文件的参数,例如
// 注意 当chooseMedia可用时会优先使用chooseMedia
// // uni.chooseImage
// this.$refs.XeUpload.upload(type, {
// count: 6,
// sizeType: ['original', 'compressed'],
// sourceType: ['album'],
// });
// // uni.chooseVideo
// this.$refs.XeUpload.upload(type, {
// sourceType: ['camera', 'album'],
// });
// // uni.chooseMedia (微信小程序2.10.0+;抖音小程序、飞书小程序;京东小程序支持)
// this.$refs.XeUpload.upload(type, {
// count: 9,
// sourceType: ['album', 'camera'],
// });
},
handleUploadCallback(e) {
2023-11-20 18:23:46 +08:00
//console.log('UploadCallback', e);
2023-11-05 00:08:34 +08:00
if (['choose', 'success'].includes(e.type)) {
// 根据接口返回修改对应的response相关的逻辑
const tmpFiles = (e.data || []).map(({ response, tempFilePath, name, fileType }) => {
// 当前测试服务返回的数据结构如下
// {
// "result": {
// "fileName": "fileName",
// "filePath": `http://192.168.1.121:3000/static/xxxxx.png`,
// },
// "success": true,
// }
const res = response?.result || {};
const tmpUrl = res.filePath ?? tempFilePath;
const tmpName = res.fileName ?? name;
return {
...res,
url: tmpUrl,
name: tmpName,
fileType,
};
});
this.fileList.push(...tmpFiles);
}
},
// 自定义上传
handleUploadFile({ url }) {
2023-11-20 18:23:46 +08:00
//console.log('UploadFile', url);
2023-11-05 00:08:34 +08:00
uni.uploadFile({
url: 'http://192.168.31.185:3000/api/upload',
filePath: url,
name: 'file',
success: (res) => {
2023-11-20 18:23:46 +08:00
//console.log('handleUpload success', res);
2023-11-05 00:08:34 +08:00
const tmpData = JSON.parse(res.data);
uni.showToast({ title: tmpData.success ? '上传成功' : '上传失败', icon: 'none' });
},
fail: (err) => {
2023-11-20 18:23:46 +08:00
//console.log('handleUpload fail', err);
2023-11-05 00:08:34 +08:00
uni.showToast({ title: '出错啦', icon: 'none' });
},
});
},
// 预览
handlePreview({ url }) {
2023-11-20 18:23:46 +08:00
//console.log('PreviewFile', url);
2023-11-05 00:08:34 +08:00
const fileType = this.getFileType(url);
if (fileType === 'image') {
return uni.previewImage({
current: url,
urls: [url],
});
}
// #ifndef H5
if (fileType === 'office') {
return uni.openDocument({
filePath: url,
fail: (err) => {
2023-11-20 18:23:46 +08:00
//console.log(err);
2023-11-05 00:08:34 +08:00
uni.showToast({ icon: 'none', title: '文件预览失败' });
},
});
}
// #endif
uni.showModal({
title: '提示',
content: url,
showCancel: false,
});
},
handleDeleteFile(index) {
this.fileList.splice(index, 1);
},
/**
* 获取文件类型
* @param {String} fileName 文件链接
* @returns {String} fileType => '', image, video, audio, office, unknown
*/
getFileType(fileName = '') {
const flieArr = fileName.split('.');
let suffix = flieArr[flieArr.length - 1];
if (!suffix) return '';
suffix = suffix.toLocaleLowerCase();
const image = ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp'];
if (image.includes(suffix)) return 'image';
const video = ['mp4', 'm4v'];
if (video.includes(suffix)) return 'video';
const audio = ['mp3', 'm4a', 'wav', 'aac'];
if (audio.includes(suffix)) return 'audio';
const office = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'plain'];
if (office.includes(suffix)) return 'office';
return 'unknown';
},
},
};
</script>
<style lang="scss" scoped>
view {
box-sizing: border-box;
}
.btn-click {
transition: all 0.3s;
opacity: 1;
}
.btn-click:active {
opacity: 0.5;
}
.mgb-16 {
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
}
.upload-wrap {
width: 100%;
border-radius: 16rpx;
background: white;
padding: 32rpx;
.upload-btn {
width: 100%;
height: 176rpx;
border: 2rpx dashed #AAAAAA;
background: #FAFAFA;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
.upload-icon {
width: 48rpx;
height: 48rpx;
margin-bottom: 8rpx;
}
.upload-text {
font-size: 26rpx;
color: #9E9E9E;
line-height: 40rpx;
}
}
.file-wrap {
.file-line {
width: 100%;
background: #F5F5F5;
border-radius: 8rpx;
padding: 16rpx;
font-size: 26rpx;
color: #1A1A1A;
line-height: 40rpx;
display: flex;
align-items: center;
justify-content: space-between;
.file-info {
width: 90%;
display: flex;
align-items: center;
.file-name {
max-width: 80%;
padding-left: 16rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.file-icon {
width: 40rpx;
height: 40rpx;
flex-shrink: 0;
}
.file-empty {
color: #999999;
}
}
}
}
</style>