feat: 文件列表上传组件
This commit is contained in:
71
packages/upload-list/index.vue
Normal file
71
packages/upload-list/index.vue
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<!--
|
||||||
|
* @Author: zhaojinfeng 121016171@qq.com
|
||||||
|
* @Date: 2023-08-16 17:33:41
|
||||||
|
* @LastEditors: zhaojinfeng 121016171@qq.com
|
||||||
|
* @LastEditTime: 2023-08-16 18:23:17
|
||||||
|
* @FilePath: \vue3\packages\upload-list\index.vue
|
||||||
|
* @Description:
|
||||||
|
*
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<el-upload v-model:file-list="value" :accept="accept" :http-request="httpRequest">
|
||||||
|
<el-button type="primary" plain>
|
||||||
|
点击上传
|
||||||
|
</el-button>
|
||||||
|
</el-upload>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup name="ThUploadList">
|
||||||
|
import type { UploadRequestOptions, UploadUserFile } from 'element-plus'
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
/** 可上传的文件类型 */
|
||||||
|
accept?: string
|
||||||
|
/** 文件集合 */
|
||||||
|
fileList?: FileVO[]
|
||||||
|
/** 文件上传的请求函数 */
|
||||||
|
request: (formData: FormData, args?: any) => Promise<FileVO>
|
||||||
|
/** 自定义文件上传路径前缀 */
|
||||||
|
filePath?: string
|
||||||
|
}>(), {
|
||||||
|
fileList: () => [],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(event: 'update:fileList', file: FileVO[]): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
let value = $ref<UploadUserFile[]>([])
|
||||||
|
|
||||||
|
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: onProgress,
|
||||||
|
})
|
||||||
|
onSuccess(res)
|
||||||
|
emit('update:fileList', [...props.fileList, res])
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
onError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
if (value.length === 0) {
|
||||||
|
value = props.fileList.map(file => ({
|
||||||
|
name: file.name!,
|
||||||
|
url: file.url,
|
||||||
|
status: 'success',
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
init()
|
||||||
|
|
||||||
|
watch(() => props.fileList, init)
|
||||||
|
</script>
|
46
stories/UploadList.stories.ts
Normal file
46
stories/UploadList.stories.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/vue3'
|
||||||
|
import ThUploadList from '../packages/upload-list/index.vue'
|
||||||
|
import avatar from './assets/avatar.jpeg'
|
||||||
|
|
||||||
|
// 模拟2秒钟的接口请求
|
||||||
|
function request(formData: FormData) {
|
||||||
|
let name = '佚名文件'
|
||||||
|
let url = avatar
|
||||||
|
const fileName = formData.get('name')
|
||||||
|
const file = formData.get('file')
|
||||||
|
if (typeof fileName === 'string') {
|
||||||
|
name = fileName
|
||||||
|
}
|
||||||
|
else if (typeof file !== 'string' && file) {
|
||||||
|
name = file.name
|
||||||
|
url = URL.createObjectURL(file)
|
||||||
|
}
|
||||||
|
return new Promise<FileVO>((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve({
|
||||||
|
id: Date.now(),
|
||||||
|
name,
|
||||||
|
url,
|
||||||
|
createdBy: 'user',
|
||||||
|
})
|
||||||
|
}, 2000)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const meta = {
|
||||||
|
title: '表单组件/UploadList',
|
||||||
|
component: ThUploadList,
|
||||||
|
args: {
|
||||||
|
accept: '*',
|
||||||
|
fileList: [],
|
||||||
|
request,
|
||||||
|
filePath: '/',
|
||||||
|
},
|
||||||
|
tags: ['autodocs'],
|
||||||
|
} satisfies Meta<typeof ThUploadList>
|
||||||
|
export default meta
|
||||||
|
|
||||||
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
|
export const Base: Story = {
|
||||||
|
name: '基本使用',
|
||||||
|
}
|
2
types/components.d.ts
vendored
2
types/components.d.ts
vendored
@ -28,6 +28,7 @@ declare module 'vue' {
|
|||||||
ElTable: typeof import('element-plus/es')['ElTable']
|
ElTable: typeof import('element-plus/es')['ElTable']
|
||||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||||
ElTransfer: typeof import('element-plus/es')['ElTransfer']
|
ElTransfer: typeof import('element-plus/es')['ElTransfer']
|
||||||
|
ElUpload: typeof import('element-plus/es')['ElUpload']
|
||||||
Header: typeof import('./../packages/header/index.vue')['default']
|
Header: typeof import('./../packages/header/index.vue')['default']
|
||||||
MaskText: typeof import('./../packages/mask-text/index.vue')['default']
|
MaskText: typeof import('./../packages/mask-text/index.vue')['default']
|
||||||
PreviewOffice: typeof import('./../packages/preview-office/index.vue')['default']
|
PreviewOffice: typeof import('./../packages/preview-office/index.vue')['default']
|
||||||
@ -37,6 +38,7 @@ declare module 'vue' {
|
|||||||
SelectTableModal: typeof import('./../packages/select-table-modal/index.vue')['default']
|
SelectTableModal: typeof import('./../packages/select-table-modal/index.vue')['default']
|
||||||
SelectTransferModal: typeof import('./../packages/select-transfer-modal/index.vue')['default']
|
SelectTransferModal: typeof import('./../packages/select-transfer-modal/index.vue')['default']
|
||||||
UploadAvatar: typeof import('./../packages/upload-avatar/index.vue')['default']
|
UploadAvatar: typeof import('./../packages/upload-avatar/index.vue')['default']
|
||||||
|
UploadList: typeof import('./../packages/upload-list/index.vue')['default']
|
||||||
UploadSingleFile: typeof import('./../packages/upload-single-file/index.vue')['default']
|
UploadSingleFile: typeof import('./../packages/upload-single-file/index.vue')['default']
|
||||||
UploadTable: typeof import('./../packages/upload-table/index.vue')['default']
|
UploadTable: typeof import('./../packages/upload-table/index.vue')['default']
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user