371 lines
8.9 KiB
Vue
Raw Normal View History

<template>
<view>
<lsj-upload v-if="!$props.readonly" ref="fileUpload" childId="upload1" width="100%" height="100%" :option="options"
:formats="''" :debug="false" :instantly="false" :count="$props.formProps.maxNumber" :size="$props.formProps.maxSize"
:multiple="$props.formProps.multiple" @change="fileChange" instantly @uploadEnd="uploadEnd" @progress="onprogre">
<slot>
<view class="w-upload-btn">
<uni-icons2 type="cloud-upload" :size="40" color="#b3b3b3"></uni-icons2>
<text>{{$props.formProps.placeholder || '请选择附件'}} | 单个附件不得超过{{$props.formProps.maxSize}}MB</text>
</view>
</slot>
</lsj-upload>
<view class="w-file-list" :key="fileList.length">
<view v-for="(file, i) in fileList" class="w-file" :key="`file_${i}_${file.type}`" @click="downFile(i)">
<image :src="getFileImgByType(file.name)" mode="aspectFit"></image>
<text class="w-file-name">{{file.name}}</text>
<uni-tag :text="getSize(file.size)" size="mini" inverted></uni-tag>
<text style="margin-right: 20rpx;" v-if="file.progress < 100">{{ file.progress }}%</text>
<view v-else-if="!$props.readonly" @click.stop="deleteFile(i, file)">
<uni-icons2 type="trash" size="20" color="#ce8d8e"></uni-icons2>
</view>
</view>
</view>
<view class="fixed" :class="{show:showIframe}" v-if="showDisplay" @click="showDisplay=false">
<view class="iframeMain" @click.stop="showDisplay=true">
<video v-if="getType(iframeUrl) == 'video'" class="iframe" :src="iframeUrl"></video>
<image v-else-if="getType(iframeUrl) == 'image'" class="iframe" :src="iframeUrl">
</image>
</view>
</view>
</view>
</template>
<script>
import {
delFile
} from '@/api/resource.js'
import {
saveFileTemp,
removeFileTemp,
openLocalFile,
isVideoLink,
isImageLink
} from '@/utils/tool.js';
//常用文件格式
const fileTypes = {
pdf: ['pdf'],
img: ['bmp', 'jpg', 'png', 'tif', 'gif', 'svg', 'psd', 'webp', 'apng'],
video: ['mp4', 'avi', 'mpeg', 'mkv', 'mov', 'rmvb', 'flv', '3gp', 'wav'],
word: ['doc', 'docx'],
excel: ['xls', 'xlsx'],
ppt: ['ppt', 'pptx'],
txt: ['txt'],
zip: ['zip', 'rar', '7z', 'iso'],
}
const fileTypeMap = new Map()
for (const key of Object.keys(fileTypes)) {
fileTypes[key].forEach(v => fileTypeMap.set(v, key))
}
export default {
props: {
formProps: {
type: Object,
default: () => {
return {}
}
},
modelValue: {
type: Array,
default: () => {
return []
}
},
readonly: Boolean
},
components: {},
data() {
return {
showDisplay: false,
showIframe: false,
iframeUrl: "",
isHide: false,
fileList: [],
fileMap: null,
}
},
computed: {
options() {
return {
url: this.url_config + 'wflow/res',
header: {
Authorization: "Bearer " + uni.getStorageSync('wflow-token'),
},
name: 'file',
formData: {
isImg: 'false'
}
}
},
_value: {
get() {
return this.$props.modelValue || []
},
set(val) {
this.$emit('update:modelValue', val)
}
}
},
created() {
this.fileMap = new Map();
},
onLoad() {
// this.fileMap = new Map();
},
mounted() {
this.$nextTick(() => {
if (!this.isHide && this.$refs.fileUpload) {
this.$refs.fileUpload.show()
}
})
console.log(this._value)
this.fileList = this._value.map(f => {
return {
name: f.name,
progress: 100,
size: f.size,
url: f.url,
type: 'success'
}
})
if (!this.$props.readonly) {
//可编辑状态下设置文件的列表
this.$refs.fileUpload.setFiles(this.fileList)
}
//由于webview层级最高这个用来防止点击穿透,事件从uni-popup组件里面发射来
uni.$on('hideFp', () => {
//开发期间可能会偶发找不到ref组件实例的问题
if (this.$refs.fileUpload) {
this.isHide = true
this.$refs.fileUpload.hide()
}
})
uni.$on('showFp', () => {
try {
this.isHide = false
setTimeout(() => {
if (this.$refs.fileUpload) {
this.$refs.fileUpload.show()
}
}, 800)
} catch (e) {}
})
},
onShow() {
},
onUnload() {
uni.$off('hideFp')
uni.$off('showFp')
},
methods: {
getFileImgByType(fileName) {
console.log(fileTypeMap, fileName)
const type = fileTypeMap.get(fileName.split('.').pop())
return `/static/image/filetype/${(type || '') === '' ? 'file': type}.png`
},
resizeCollapse() {
setTimeout(() => this.$emit('resize'), 800)
},
fileChange(file) {
if (file instanceof Map) {
this.fileList = []
this.fileMap.clear()
file.forEach((f) => {
const fileM = {
name: f.name,
progress: f.progress,
size: f.size,
type: f.type
}
this.fileList.push(fileM)
this.fileMap.set(f.name, fileM)
})
this.$refs.fileUpload.upload()
}
this.resizeCollapse();
},
onprogre(item) {
this.fileMap.get(item.name).progress = item.progress
},
uploadEnd(file) {
const fileM = this.fileMap.get(file.name)
if (fileM) {
fileM.type = file.type
fileM.progress = file.progress
if (file.type === 'success') {
uni.showToast({
icon: 'none',
title: '上传成功'
})
if (!Array.isArray(this._value)) {
this._value = []
}
const _file = JSON.parse(file.responseText)
//将文件
saveFileTemp({
id: _file.id,
name: _file.name,
path: file.path,
size: this.getSize(file.size)
})
this._value.push(_file)
//强制更新下数据
this.$emit('update:modelValue', this._value)
} else {
//不保存
this.removeFileTemp(file.name)
}
}
},
getType(url) {
if (isImageLink(url)) {
return "image"
} else if (isVideoLink(url)) {
return "video"
} else {
return ''
}
},
downFile(i) {
// if (!this.$props.readonly) {
// //可编辑状态下不能操作下载和查看
// return;
// }
const file = this._value[i]
// const fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1);
// // 常见的图片文件后缀名
// const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'];
// // 视频类型列表
// const videoTypes = ['mp4', 'webm', 'ogg'];
// 判断文件后缀名是否在常见图片文件后缀名数组中
if (isVideoLink(`${this.url_config}image/${file.id}`) || isImageLink(`${this.url_config}image/${file.id}`)) {
// 是图片和视频
this.showDisplay = true;
this.showIframe = true;
this.iframeUrl = `${this.url_config}image/${file.id}`;
} else {
window.open(`${this.url_config}image/${file.id}`)
}
// openLocalFile(file.name, `${options.url}/${file.id}?name=${file.name}`)
// openLocalFile(file.name, `${BASE_URL}/image/${file.id}`)
},
getSize(size) {
if (size > 1048576) {
return (size / 1048576).toFixed(1) + 'MB'
} else if (size > 1024) {
return (size / 1024).toFixed(1) + 'KB'
} else {
return size + 'B'
}
},
deleteFile(i, file) {
console.log(i, file)
uni.showModal({
title: '提示',
content: '您确认要删除该文件吗,删除后需要重新上传,确认删除?',
success: function(res) {
if (res.confirm) {
console.log(this._value[i])
delFile(this._value[i].id).then(() => {
this._value.splice(i, 1)
this.$emit('update:modelValue',this. _value)
this.fileMap.delete(file.name)
this.fileList.splice(i, 1)
this.$refs.fileUpload.clear(file.name)
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.msg || '删除文件失败'
})
})
}
}
});
},
show(show = true) {
if (show) {
this.$refs.fileUpload.show()
} else {
this.$refs.fileUpload.hide()
}
}
}
}
</script>
<style lang="scss" scoped>
.w-upload-btn {
padding: 10rpx;
background-color: #F7F7F7;
text-align: center;
color: #b3b3b3;
display: flex;
justify-content: center;
align-items: center;
font-size: 24rpx;
}
.w-file-list {
&>view {
display: flex;
}
.w-file {
flex: 1;
padding: 4rpx 20rpx;
background-color: #F7F7F7;
border-radius: 10rpx;
display: flex;
align-items: center;
margin-top: 4rpx;
image {
width: 24rpx;
height: 24rpx;
margin-right: 10rpx;
}
.w-file-name {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
/* 设置文本溢出时显示省略号 */
white-space: nowrap;
}
}
}
.fixed {
position: fixed;
z-index: 9999;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, .3);
display: none;
&.show {
display: initial;
}
}
.iframeMain {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 650rpx;
font-size: 0;
.iframe {
width: 100%;
height: 600rpx;
}
}
</style>