402 lines
9.4 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>
<lsj-upload v-if="!readonly" ref="fileUpload" childId="upload1" width="100%" height="100%" :option="options"
:formats="''" :debug="false" :instantly="false" :count="formProps.maxNumber" :size="formProps.maxSize"
:multiple="formProps.multiple" @change="fileChange" instantly @uploadEnd="uploadEnd" @progress="onprogre">
<slot>
<view class="w-upload-btn">
<uni-icons type="cloud-upload" :size="40" color="#b3b3b3"></uni-icons>
<text>{{formProps.placeholder || '请选择附件'}} | 单个附件不得超过{{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.stop="downFile(i)">
<image :src="getFileImgByType(file.name)" mode="aspectFit"></image>
<text class="w-file-name">{{file.name}}</text>
<text :class="{'mr_10': file.size}" @click.stop="onPreview(i)">预览</text>
<uni-tag v-if="file.size" :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="!readonly" @click.stop="deleteFile(i, file)">
<uni-icons type="trash" size="20" color="#ce8d8e"></uni-icons>
</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>
<PreviewIframe @watchChild="watchChildClick" v-else :iframeUrl="iframeUrl"/>
</view>
</view>
</view>
</template>
<script setup>
// import PreviewIframe from "@/components/previewIframe.vue"
import {
ref,
computed,
nextTick,
onMounted
} from 'vue'
import {
BASE_URL
} from '@/api/request.js'
import {
delFile
} from '@/api/resource.js'
import {
onUnload
} from "@dcloudio/uni-app";
import {
getFileImgByType,
saveFileTemp,
removeFileTemp,
openLocalFile,
isVideoLink,
isImageLink
} from '@/utils/tool.js';
const emits = defineEmits(['update:modelValue', 'resize'])
import { encode } from 'js-base64';
defineExpose({
show
})
const showDisplay = ref(false)
const showIframe = ref(false)
const iframeUrl = ref("")
const props = defineProps({
formProps: {
type: Object,
default: () => {
return {}
}
},
modelValue: {
type: Object,
default: () => {
return []
}
},
readonly: Boolean
})
const options = {
url: BASE_URL + '/wflow/res',
header: {
Authorization: "Bearer " + uni.getStorageSync('wflow-token'),
},
name: 'file',
formData: {
isImg: 'false'
}
}
const isHide = ref(false)
const _value = computed({
get() {
return props.modelValue || []
},
set(val) {
emits('update:modelValue', val)
}
})
nextTick(() => {
if (!isHide.value && fileUpload.value) {
fileUpload.value.show()
}
})
onMounted(() => { //处理文件回显
fileList.value = _value.value.map(f => {
return {
name: f.name,
progress: 100,
size: f.size,
url: f.url,
type: 'success'
}
})
if (!props.readonly) {
//可编辑状态下设置文件的列表
fileUpload.value.setFiles(fileList.value)
}
})
const watchChildClick = () => {
console.log("watchChildClick")
showDisplay.value = false;
showIframe.value = false;
}
onUnload(() => {
uni.$off('hideFp')
uni.$off('showFp')
})
//由于webview层级最高这个用来防止点击穿透,事件从uni-popup组件里面发射来
uni.$on('hideFp', () => {
//开发期间可能会偶发找不到ref组件实例的问题
if (fileUpload.value) {
isHide.value = true
fileUpload.value.hide()
}
})
uni.$on('showFp', () => {
try {
isHide.value = false
setTimeout(() => {
if (fileUpload.value) {
fileUpload.value.show()
}
}, 800)
} catch (e) {}
})
const fileUpload = ref()
const fileList = ref([])
const fileMap = ref()
fileMap.value = new Map()
function resizeCollapse() {
setTimeout(() => emits('resize'), 800)
}
function fileChange(file) {
if (file instanceof Map) {
fileList.value = []
fileMap.value.clear()
file.forEach((f) => {
const fileM = {
name: f.name,
progress: f.progress,
size: f.size,
type: f.type
}
fileList.value.push(fileM)
fileMap.value.set(f.name, fileM)
})
fileUpload.value.upload()
}
resizeCollapse();
}
function onprogre(item) {
fileMap.value.get(item.name).progress = item.progress
}
function uploadEnd(file) {
const fileM = fileMap.value.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(_value.value)) {
_value.value = []
}
const _file = JSON.parse(file.responseText)
//将文件
saveFileTemp({
id: _file.id,
name: _file.name,
path: file.path,
size: getSize(file.size)
})
_value.value.push(_file)
//强制更新下数据
emits('update:modelValue', _value)
} else {
//不保存
removeFileTemp(file.name)
}
}
}
function getType(url){
if(isImageLink(url)){
return "image"
}else if(isVideoLink(url)){
return "video"
}else{
return ''
}
}
function downFile(i) {
// if (!props.readonly) {
// //可编辑状态下不能操作下载和查看
// return;
// }
const file = _value.value[i]
// const fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1);
// // 常见的图片文件后缀名
// const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'];
// // 视频类型列表
// const videoTypes = ['mp4', 'webm', 'ogg'];
// 判断文件后缀名是否在常见图片文件后缀名数组中
console.log(file)
const url = file.url ? (file.url.includes("http://") ? file.url : `${BASE_URL}/image/${file.url}`) : `${BASE_URL}/image/${file.id}`;
if (isVideoLink(`${url}`) || isImageLink(`${url}`)) {
// 是图片和视频
showDisplay.value = true;
showIframe.value = true;
iframeUrl.value = `${url}`;
} else {
// window.open(`${url}`)
}
// openLocalFile(file.name, `${options.url}/${file.id}?name=${file.name}`)
// openLocalFile(file.name, `${BASE_URL}/image/${file.id}`)
}
function onPreview(i) {
const file = _value.value[i]
// const fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1);
// // 常见的图片文件后缀名
// const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'];
// // 视频类型列表
// const videoTypes = ['mp4', 'webm', 'ogg'];
// 判断文件后缀名是否在常见图片文件后缀名数组中
console.log(file)
const url = file.url ? (file.url.includes("http://") ? file.url : `${BASE_URL}/image/${file.url}`) : `${BASE_URL}/image/${file.id}`;
if (isVideoLink(`${url}`) || isImageLink(`${url}`)) {
// 是图片和视频
showDisplay.value = true;
showIframe.value = true;
iframeUrl.value = `${url}`;
} else {
// window.open(`${url}`)
showDisplay.value = true;
showIframe.value = true;
iframeUrl.value = `http://219.147.96.221:8012/onlinePreview?url=${encodeURIComponent(encode(url))}`;
}
// http://219.147.96.221:8012/onlinePreview?url=${encodeURIComponent(encode(src))}
}
function 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'
}
}
function deleteFile(i, file) {
console.log(i, file)
uni.showModal({
title: '提示',
content: '您确认要删除该文件吗,删除后需要重新上传,确认删除?',
success: function(res) {
if (res.confirm) {
console.log(_value.value[i])
delFile(_value.value[i].id).then(() => {
_value.value.splice(i, 1)
emits('update:modelValue', _value)
fileMap.value.delete(file.name)
fileList.value.splice(i, 1)
fileUpload.value.clear(file.name)
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.msg || '删除文件失败'
})
})
}
}
});
}
function show(show = true) {
if (show) {
fileUpload.value.show()
} else {
fileUpload.value.hide()
}
}
</script>
<style lang="less" scoped>
.mr_10{
margin-right: 20rpx
}
.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: 1000rpx;
}
}
</style>