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.

663 lines
32 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>
<div>
<div v-if="!props.disabled && props.text" style="display: inline-flex;" :class="{ doing: doing || !uploadKey }"
@click="open()">
<slot name="button"><el-button>{{ props.text }}</el-button></slot>
</div>
<input ref="fileInputRef" v-if="!props.disabled" :accept="props.accept" @change="fileInputChange" type="file"
style="position: absolute; top:-100vh;" :multiple="props.max != 1" />
<div class="list">
<slot :list="list">
<div v-for="(item, index) in data" :key="index" class="item"
:class="{ error: item.error, abort: item.abort, border: props.border }"
:style="{ '--ps': (item.uploading?.loaded || 0) * 100 / (item.uploading?.total || 1) + '%' }">
<div class="icon" :class="['icon-' + item.ext]"></div>
<a v-if="item.raw" href="javascript:void(0)">{{ item.name }}</a>
<a v-else :href="baseUrl + base + 'download?' + request.params({ url: item.url, key: uploadKey }).toString()"
target="_blank">{{ item.name }}</a>
<div v-if="item.uploading && !item.abort" class="btn" @click="item.uploading.abort()">取消</div>
<div v-if="item.url && !props.disabled" @click="remove(item)" class="btn"></div>
</div>
</slot>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, computed, getCurrentInstance } from 'vue'
import { request } from '@/utils'
import { ElMessage } from 'element-plus'
const base = "/file/upload/"
const baseUrl = import.meta.env.VITE_APP_BASE_API
const { proxy } = getCurrentInstance()
const props = defineProps({
/**
* 上传的文件
*/
modelValue: {
type: [Array, String],
required: true
},
/**
* 上传的数量,0表示无限制,1表示单文件上传
*/
max: {
type: Number,
default: 0
},
/**
* 获取上传凭证的方法
*/
getUploadKey: {
type: Function,
default: async () => {
let r = await request.get("/uploadKey")
return r.data
}
},
/**
* 上传路径前缀
*/
prefix: {
type: String,
default: "default"
},
/**
* 是否保存上传文件名
* keepFilename
*/
keepFilename: {
type: Boolean,
default: true
},
/**
* 禁止上传(文件预览模式)
*/
disabled: {
type: Boolean,
default: false
},
/**
* 按钮文字
*/
text: {
type: String,
default: '上传文件'
},
/**
* 上传中?
*/
uploading: {
type: Boolean,
default: false
},
/**
* 允许上传的文件扩展名列表,默认:'' ,office:'.doc,.docx,.ppt,.pptx,.xls,.xlsx'
*/
accept: {
type: String,
default: ''
},
/**
* 允许上传的文件最大大小,0表示不限制默认0
*/
maxSize: {
type: Number,
default: 0
},
/**
* 并行上传数量默认2
*/
threadNum: {
type: Number,
default: 2
},
/** 重试次数默认3 */
retry: {
type: Number,
default: 3
},
/**
* 分片大小默认5Mb
*/
chunksize: {
type: Number,
default: 5 * 1024 * 1024
},
border: {
type: Boolean,
default: true
}
})
const emit = defineEmits(["update:modelValue", "change", "update:uploading"]);
const mv = computed({
get() {
return props.modelValue
},
set(value) {
emit("update:modelValue", value)
emit("change", value)
}
})
watch(mv, () => {
if (props.max == 1) {
data.value = []
if (mv.value) {
data.value = [{ url: mv.value ,ext: getExt(mv.value), name: getName(mv.value) }]
}
} else {
data.value = []
if (mv.value) {
data.value = mv.value.map(a => ({ url: a ,ext: getExt(a), name: getName(a)}))
}
}
})
const uploading = computed({
get() {
return props.uploading
},
set(value) {
emit("update:uploading", value)
}
})
const data = ref([])
const uploadKey = ref("");
const getExt = (url) => {
return url.substring(url.lastIndexOf(".") + 1)
}
const getName = (url) => {
return url.substring(url.lastIndexOf("/") + 1)
}
onMounted(async () => {
uploadKey.value = await props.getUploadKey()
if (props.max == 1) {
data.value = []
if (mv.value) {
data.value = [{ url: mv.value, ext: getExt(mv.value), name: getName(mv.value) }]
}
} else {
data.value = []
if (mv.value) {
data.value = mv.value.map(a => ({ url: a, ext: getExt(a), name: getName(a) }))
}
}
})
const remove = (one) => {
data.value.splice(data.value.indexOf(one), 1)
if (props.max == 1) {
mv.value = data.value[0]?.url
} else {
mv.value = data.value.filter(a => 'url' in a).map(a => a.url)
}
request.post(base + "remove?r=" + Math.random(), request.params({ key: uploadKey.value, url: one.url }))
}
onUnmounted(async () => {
await request.get(base + "removeUploadKey-" + uploadKey.value)
})
window.addEventListener('beforeunload', async () => {
await request.get(base + "removeUploadKey-" + uploadKey.value)
})
/**
* 刷新上传凭证
*/
const reloadUploadKey = async () => {
request.get(base + "removeUploadKey-" + uploadKey.value)
uploadKey.value = await props.getUploadKey()
}
const fileInputRef = ref(null);
/**
* 打开文件选择对话框
*/
const open = () => {
if (doing.value) {
return
}
try {
fileInputRef.value.click();
} catch (e) { }
}
const fileInputChange = () => {
let files = fileInputRef.value.files
if (files.length > 0) {
// fileInputRef.value.value = ''
for (let file of files) {
addUploadFile(file)
}
uploadFiles()
}
}
const addUploadFile = async (file) => {
if (props.max > 1 && props.max == data.value.length) {
ElMessage.error('最多只允许上传' + props.max + '个文件')
return
}
// 判断类型
if (props.accept) {
let ext = file.name.toLowerCase().substring(file.name.lastIndexOf("."))
if (props.accept.indexOf(ext) == -1) {
ElMessage.error(file.name + '类型错误')
return
}
}
if (props.maxSize > 0) {
if (file.size > props.maxSize) {
ElMessage.error(file.name + '大小超过了' + props.maxSize.toFileSize())
return
}
}
if (props.max == 1) {
data.value.length = 0
}
data.value.push({ raw: file, ext: getExt(file.name), name: file.name })
}
let doing = ref(false);
const uploadFiles = async () => {
if (doing.value) {
return
}
doing.value = true
uploading.value = true
await reloadUploadKey()
let index = 0
let doOne = async () => {
while (index < data.value.length) {
await uploadFile(index++)
}
}
let a = [];
for (let i = 0; i < props.threadNum; i++) {
a.push(doOne())
}
Promise.all(a).then(() => {
}).finally(() => {
data.value = data.value.filter(a => !a.error && !a.abort)
doing.value = false
uploading.value = false
})
}
const uploadFile = async (index, retry = 0) => {
let one = data.value[index];
if (!one) {
return
}
if (one.url) {
return
}
if (retry >= props.retry) {
one.error = true
return
}
if (one.uploading || one.error || one.abort) {
return
}
retry++
one.uploading = { loaded: 0, total: one.raw.size }
one.uploading.controller = new AbortController();
one.uploading.abort = () => {
one.uploading.controller.abort()
if (one.raw.size > props.chunksize) {
request.post(base + 'multipartUploadAbort?uploadId=' + one.uploading.uploadId)
}
}
if (one.raw.size <= props.chunksize) {
let formData = new FormData()
formData.append("prefix", props.prefix)
formData.append("key", uploadKey.value)
formData.append("keepFilename", props.keepFilename)
formData.append("file", one.raw)
let onUploadProgress = (event) => {
one.uploading.loaded = event.loaded
}
try {
let r = await request.post(base + "?r=" + Math.random(), formData, {
onUploadProgress,
timeout: 600000,
showLoading: false,
signal: one.uploading.controller.signal
})
if (r.code == 200) {
delete one.raw
delete one.uploading
one.url = r.data
if (props.max == 1) {
mv.value = r.data
} else {
mv.value = data.value.filter(a => 'url' in a).map(a => a.url)
}
} else {
delete one.uploading
await uploadFile(index, retry)
}
} catch (e) {
delete one.uploading
await uploadFile(index, retry)
}
} else {
try {
await uploadFileBig(one)
} catch (e) {
delete one.uploading
await uploadFile(index, retry)
}
}
}
/**
* 大文件上传
* @param one
*/
const uploadFileBig = async (one) => {
let chunksList = chunkFile(one.raw, props.chunksize)
let r = await request.post(base + "multipartUploadInit?r=" + Math.random(), request.params({ prefix: props.prefix, filename: one.raw.name, key: uploadKey.value, keepFilename: props.keepFilename }))
let uploadId = r.data
one.uploading.uploadId = uploadId
for (let i = 0; i < chunksList.length; i++) {
try {
await uploadChunk(one, chunksList, i, uploadId, 0)
} catch (e) {
one.error = true
request.post(base + 'multipartUploadAbort?uploadId=' + one.uploading.uploadId)
return;
}
}
r = await request.post(base + 'multipartUploadComplete?uploadId=' + one.uploading.uploadId)
if (r.code == 200) {
delete one.raw
delete one.uploading
one.url = r.data
if (props.max == 1) {
mv.value = r.data
} else {
mv.value = data.value.filter(a => 'url' in a).map(a => a.url)
}
} else {
one.error = true
request.post(base + 'multipartUploadAbort?uploadId=' + one.uploading.uploadId)
return;
}
}
/**
* 上传分片
* @param index
* @param retry
*/
const uploadChunk = async (one, chunksList, index, uploadId, retry = 0) => {
if (retry >= props.retry) {
throw new Error('上传分片失败')
}
retry++
let formData = new FormData()
formData.append('uploadId', uploadId)
formData.append('file', chunksList[index])
formData.append('partNumber', index + 1)
let onUploadProgress = (event) => {
one.uploading.loaded = props.chunksize * index + event.loaded
}
try {
let r = await request.post(base + "multipartUpload?r=" + index + '' + Math.random(), formData, {
onUploadProgress,
timeout: 600000,
showLoading: false,
signal: one.uploading.controller.signal
})
if (r.code != 200) {
await uploadChunk(one, chunksList, index, uploadId, retry)
}
} catch (e) {
await uploadChunk(one, chunksList, index, uploadId, retry)
}
}
/**
* 分片
* @param file 文件
* @param chunksize 分片大小
*/
const chunkFile = (file, chunksize) => {
const chunks = Math.ceil(file.size / chunksize)
const chunksList = []
let currentChunk = 0
while (currentChunk < chunks) {
const start = currentChunk * chunksize;
const end = Math.min(file.size, start + chunksize);
const chunk = file.slice(start, end);
chunksList.push(chunk);
currentChunk++;
}
return chunksList;
}
defineExpose({ open, reloadUploadKey })
</script>
<style lang="scss" scoped>
.doing {
opacity: .5;
position: relative;
&::before {
content: '';
position: absolute;
height: 100%;
width: 100%;
background-color: #0000;
cursor: not-allowed;
}
}
.list {
.item {
display: flex;
align-items: center;
position: relative;
overflow: hidden;
border-radius: .3em;
margin-top: .5em;
padding: .5em;
&.border {
border: solid 1px #00000007;
}
&.abort {
opacity: .5;
}
&.error {
border-color: var(--el-color-danger, #f56c6c);
}
&>:nth-child(2) {
cursor: pointer;
&:hover {
transform: translate(1px, 1px);
}
}
&::before {
content: '';
pointer-events: none;
background-color: #00000005;
position: absolute;
top: 0;
left: 0;
height: 100%;
width: var(--ps, 0);
}
.btn {
font-size: .7em;
color: var(--el-color-danger, #f56c6c);
margin-left: 1em;
cursor: pointer;
&:hover {
transform: translate(1px, 1px);
}
}
}
}
.icon {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABXgAAABGCAMAAABBnQx/AAAAA3NCSVQICAjb4U/gAAAC/VBMVEX///+srKyZmZlzc3NAQkE5OkEoKSsgICAUEw4AAADx1pSZmZmIiIgoKSsUEw4AAAAUEw4AAACsrKwUEw4AAACsrKwgICAAAAC1tbXXrEqsrKy9vb21tbWsrKzV2tTFxcWZmZne3t7FxcW9vb2srKwwXyEoKSsUEw7e3t7W2d7MzMzFxcW1tbWsrKykpKS8ljzpXDshfQEzZplKVIRERkwuR385OkG1EBD////4///+/9r7/uzv///5/8jn/f/39/f59P36/on//2bY+/3w8fX+8c7b9/zw7+7T9v/l7/zk8tjk7vH97bjK9urm5+324vT75rfB8f/m5ub95qq68+zW6PXg5eX239f64KWt7v/d3+j53pze3t7N4fvo4K3x1O742pTR3e/723jN38fW2d7V2tT31ojI45Lx1pTnzvf712vD4anD2O7k0dH20XvI0d7vz4Gs1vb5zFzMzMz2wcGp3Ju2zeyw2Iz4xkzFxcXmxHSnyOr4wy6k03u3w9nqwFmZyfC4wc2Mx/W9vb3ds7qlvd6WyYWyvK7dtFi1tbWJvt77p2j1riXzpJG7sa72qFqtsLiLwW1WxOzXrEr1pxOsrKzWqVh9s+V8ruF1sd6tp5eXrn+kpKSAtGdkvknNnVXekZJhvED1i1fmjHJ4rGPvkQthtkOPnK+ZmZlnoNqHmsRTtThzqGC8ljxso1tbqkDmgylCrxtMqzBYk9pgnVDvckh7ibxQktWIiIjobW03rAl4hLNDnydek1CpfkCyektSh8+SgFdufbg9iNJTikFderaGd2PpXDtMfMXjWlqTdjRLijc5khxAfsBmdqDTXFwvgNBzc3M1jRhJgTT4SUmSaE1Ob7HAU1MzcrVCbLU9b58kcsJmZmaUXighfQHvOTk8YqwzZpl3VyxKVIQzVqDMMzNPUlowXyFvTCIrTZZISlPEKipERkxdQxwuR39AQkHxERF2MR6RJCQ5OkFMNxkAPnMzMzO1EBBCLxMSN11WHSkoKSsgICAUEw4AAABBEXoEAAAA/3RSTlMAERERERERERERIiIiIiIiMzNERERVVVVmmZm7u7vMzMzd3d3d3d3d7u7u7u7u7u7u7u7u7u7u7v////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+8LOaEAAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAIABJREFUeJztnQ18FNW5/6nga6lo9aLoVenV+re1Lb2o11mIbCobRhJZYCABwqrB7GIkoQEXgU0wJllCsxRs+IcloglBgrKgvKgYkssVFVGKtGguL7YajQJSSHlJJcVUsJ973ub9zMyZzQQWmt9nd/bM2Z1nz5kz57vPPnPmTI8e3epWt7rVrW51q1vd6la3nNMVV/QjOtcl6Va3ukVTL5P3Lrr+5h/5fH6on9x8Y++zVqZuxSERtgMqKyvLy8sLCnJyxj9c0E3ebnUrodSrV9++t9994uilRh+4/g6fL0Pged7t4Xmv4APw/f7ZLGC3rHSFGrYF03LGjx+VkjIIaPBgsEhJSam8wnjzf48wKRq+/OxVqVvdumCFiNvcEGtubT106FBfare6/g6/z+vmgFyupCSXCyZ4IeC/2ZDTSjnTpS88K46pXz+MWujWjgKsTZFIC/WgpJRyE/BG3CzyCMFbf2BamITaN2yFid5qVhYnbDBbsdgr55+VyE2OWDEvjEPH3Fk6dBFx7z4RC/kRUr1NgLuHbu+j/+D1dwQQdQFzgTwez1AgD8jwCP4bzYITRM506QvPimOqBG4tlbQapZTXrh3Qz6DFIu4MBmX6g547TcNM7Pvm4q7YF3EUxuML3XpJ19pgtWJ1xJx3VtxC1Jy8jnQlh/pjV3frXr363tX0i+pIBfJxTwQ5LA8k791Xa3fT934U8CJXFzq7SQi6I0aMgIuhHMf7/NdboteZLn3hWXFMlYao1YL3iSlTyvvROwJjnQIh3n3nD00Kw75v/qPrY1VMhcn0hczK4oQNVitWR8x5ZyXDEwzdakYIxsPFBw4X48I41B8dKQtNJJDb7HdhBaGP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);
background-repeat: no-repeat;
background-position-y: 0;
background-size: 140em 7em;
width: 7em;
height: 7em;
background-position: -14em center;
font-size: .4em;
margin-right: .5em;
flex-flow: 1;
flex-shrink: 1;
&.icon-dir {
background-position: 0 center;
}
&.icon-zip {
background-position: -7em center;
}
&.icon-filelist {
background-position: -21em center;
}
&.icon-rar,
&.icon-7z,
&.icon-tar,
&.icon-gz {
background-position: -28em center;
}
&.icon-xls,
&.icon-xlsx {
background-position: -35em center;
}
&.icon-doc,
&.icon-docx {
background-position: -42em center;
}
&.icon-ppt,
&.icon-pptx {
background-position: -49em center;
}
&.icon-vsd {
background-position: -56em center;
}
&.icon-pdf {
background-position: -63em center;
}
&.icon-txt,
&.icon-md,
&.icon-json,
&.icon-htm,
&.icon-xml,
&.icon-html,
&.icon-js,
&.icon-css,
&.icon-php,
&.icon-jsp,
&.icon-asp {
background-position: -70em center;
}
&.icon-apk {
background-position: -77em center;
}
&.icon-exe {
background-position: -84em center;
}
&.icon-ipa {
background-position: -91em center;
}
&.icon-mp4,
&.icon-mov,
&.icon-mpeg,
&.icon-rm,
&.icon-rmvb {
background-position: -98em center;
}
&.icon-wav,
&.icon-wmv,
&.icon-mid,
&.icon-mp3 {
background-position: -105em center;
}
&.icon-bmp,
&.icon-jpg,
&.icon-jpeg,
&.icon-png,
&.icon-webp,
&.icon-psd,
&.icon-tiff,
&.icon-tif,
&.icon-eps,
&.icon-raw,
&.icon-svg,
&.icon-ai,
&.icon-avif,
&.icon-apng,
&.icon-wmf,
&.icon-pcd,
&.icon-gif {
background-position: -112em center;
}
}
</style>