136 lines
3.6 KiB
Vue
136 lines
3.6 KiB
Vue
<!--
|
||
* @Author: zhaojinfeng 121016171@qq.com
|
||
* @Date: 2023-08-16 17:33:41
|
||
* @LastEditors: Hefeng 1057605508@qq.com
|
||
* @LastEditTime: 2023-09-15 12:51:29
|
||
* @FilePath: \th-components-vue3\packages\upload-list\index.vue
|
||
* @Description:
|
||
*
|
||
-->
|
||
<template>
|
||
<el-upload
|
||
v-model:file-list="userFiles"
|
||
:class="{ 'user-files': listType === 'picture-card' && userFiles.length >= limit }"
|
||
:accept="accept"
|
||
:disabled="disabled"
|
||
:before-upload="beforeUpload"
|
||
:http-request="httpRequest"
|
||
:list-type="listType"
|
||
:limit="limit"
|
||
@preview="preview"
|
||
@success="success"
|
||
@remove="remove"
|
||
>
|
||
<slot>
|
||
<el-icon v-if="listType === 'picture-card'">
|
||
<Plus />
|
||
</el-icon>
|
||
<el-button v-if="listType !== 'picture-card' && userFiles.length < limit" type="primary" plain :disabled="disabled">
|
||
点击上传
|
||
</el-button>
|
||
</slot>
|
||
</el-upload>
|
||
</template>
|
||
|
||
<script lang="ts" setup name="ThUploadList">
|
||
import { Plus } from '@element-plus/icons-vue'
|
||
import type { UploadFile, UploadFiles, UploadRawFile, UploadRequestOptions, UploadUserFile } from 'element-plus'
|
||
|
||
const props = withDefaults(
|
||
defineProps<{
|
||
/** 可上传的文件类型 */
|
||
accept?: string
|
||
/** 文件集合 */
|
||
fileList?: FileVO[]
|
||
/** 文件上传的请求函数 */
|
||
request: (formData: FormData, args?: any) => Promise<FileVO>
|
||
/** 自定义文件上传路径前缀 */
|
||
filePath?: string
|
||
/** 禁用组件 */
|
||
disabled?: boolean
|
||
/** 最大上传大小(Mb) */
|
||
maxsize?: number
|
||
/** 文件列表的类型 */
|
||
listType?: 'text' | 'picture' | 'picture-card'
|
||
/** 允许上传文件的最大数量 */
|
||
limit?: number
|
||
}>(), {
|
||
fileList: () => [],
|
||
maxsize: 100,
|
||
limit: Infinity,
|
||
},
|
||
)
|
||
|
||
const emit = defineEmits<{
|
||
(event: 'update:file-list', file: FileVO[]): void
|
||
(event: 'preview', file: UploadFile): void
|
||
}>()
|
||
|
||
const userFiles = ref<UploadUserFile[]>([])
|
||
|
||
function beforeUpload(rawFile: UploadRawFile) {
|
||
if (rawFile.size > props.maxsize * 1024 * 1024) {
|
||
const err = `文件大小不能超过${props.maxsize}Mb`
|
||
ElMessage.error(err)
|
||
return false
|
||
}
|
||
return true
|
||
}
|
||
async function httpRequest({ file, onProgress, onSuccess, onError }: UploadRequestOptions) {
|
||
const formData = new FormData()
|
||
formData.append('file', file)
|
||
if (props.filePath)
|
||
formData.append('filePath', props.filePath)
|
||
try {
|
||
const res = await props.request(formData, {
|
||
onUploadProgress(e: ProgressEvent) {
|
||
onProgress({ ...e, percent: Math.floor(e.loaded * 100 / e.total) })
|
||
},
|
||
})
|
||
onSuccess(res)
|
||
}
|
||
catch (err) {
|
||
onError(err)
|
||
}
|
||
}
|
||
|
||
function preview(uploadFile: UploadFile) {
|
||
emit('preview', uploadFile)
|
||
}
|
||
|
||
const { pause, resume } = watchPausable(
|
||
() => props.fileList, (fileList) => {
|
||
userFiles.value = fileList.map(file => ({
|
||
...file,
|
||
status: 'success',
|
||
percentage: 100,
|
||
uid: file.id,
|
||
}))
|
||
},
|
||
{ immediate: true },
|
||
)
|
||
|
||
function success(response: FileVO, uploadFile: UploadFile, uploadFiles: UploadFiles) {
|
||
// 将返回响应合并到文件上
|
||
Object.assign(uploadFile, response)
|
||
// 手动更新,暂停监听,避免因props.fileList更新再次更新uploadFile
|
||
pause()
|
||
emit('update:file-list', uploadFiles)
|
||
resume()
|
||
}
|
||
|
||
function remove(_uploadFile: UploadFile, uploadFiles: UploadFiles) {
|
||
userFiles.value = uploadFiles
|
||
// 手动更新,暂停监听,避免因props.fileList更新再次更新uploadFile
|
||
pause()
|
||
emit('update:file-list', uploadFiles)
|
||
resume()
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
.user-files .el-upload--picture-card{
|
||
display: none;
|
||
}
|
||
</style>
|