feat: 优化上传弹窗

master
绝弹 2023-10-30 22:12:32 +08:00
parent 687f6250eb
commit 751102f4ad
2 changed files with 109 additions and 5 deletions

View File

@ -1,19 +1,114 @@
<template> <template>
<a-modal v-model:visible="modal.visible" title="上传文件" title-align="start" :footer="false" :width="732"> <a-modal v-model:visible="modal.visible" title="上传文件" title-align="start" :width="732">
<a-alert class="mb-4"> 提示支持大小在 1G 以内格式为.png.jpg.webp.mp4.ogg的文件 </a-alert> <!-- <a-alert class="mb-2"> 提示支持大小在 1G 以内格式为.png.jpg.webp.mp4.ogg的文件 </a-alert> -->
<a-upload :custom-request="upload" draggable action="/api/v1/upload"></a-upload> <a-upload
ref="uploadRef"
class="upload"
v-model:file-list="fileList"
:multiple="true"
:custom-request="upload"
:auto-upload="false"
>
<template #upload-button>
<div class="mb-2 flex items-center gap-2">
<div class="flex-1 flex gap-4">
<a-button type="outline"> 选择文件... </a-button>
<span class="flex items-center text-gray-400" @click.prevent.stop>
归类为:
<span>
<a-select v-model="group" :bordered="false" :options="groupOptions"></a-select>
</span>
</span>
</div>
</div>
</template>
<template #upload-item="{ fileItem }">
<li :key="fileItem.uid" class="flex items-center gap-2 border-b py-3">
<div class="flex-1">
<div class="truncate">
{{ fileItem.name }}
</div>
<a-progress :percent="Math.floor(fileItem.percent * 100) / 100" :show-text="false"></a-progress>
<div class="flex items-center justify-between gap-2 text-gray-400">
<span class="text-xs">
{{ numeral(fileItem.file.size).format("0.00 b") }}
</span>
<span class="text-xs">
<span v-if="fileItem.status === 'uploading'"> {{ fileItem.percent * 100 }}% </span>
<span v-if="fileItem.status === 'done'" class="text-green-500">
<i class="icon-park-outline-check-one"></i>
完成
</span>
<span v-if="fileItem.status === 'error'" class="text-red-500">
<i class="icon-park-outline-close-one"></i>
失败
</span>
</span>
</div>
</div>
<div v-show="fileItem.status !== 'done'">
<a-link v-show="fileItem.status === 'uploading'" @click="pauseItem(fileItem)"></a-link>
<a-link v-show="fileItem.status === 'init'" @click="removeItem(fileItem)" status="danger"></a-link>
</div>
</li>
</template>
</a-upload>
<!-- <div v-show="!fileList.length" class="h-[426px]">
<a-empty></a-empty>
</div> -->
<template #footer>
<div class="flex justify-end gap-2 items-center">
<a-button>
清空
</a-button>
<a-button type="primary" @click="startUpload">
上传
</a-button>
</div>
</template>
</a-modal> </a-modal>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { api } from "@/api"; import { api } from "@/api";
import { RequestOption } from "@arco-design/web-vue"; import { FileItem, RequestOption, UploadInstance } from "@arco-design/web-vue";
import axios from "axios"; import axios from "axios";
import numeral from "numeral";
const uploadRef = ref<UploadInstance | null>(null);
const startUpload = () => {
uploadRef.value?.submit();
};
const pauseItem = (fileItem: FileItem) => {
fileItem.status;
uploadRef.value?.abort(fileItem);
};
const removeItem = (fileItem: FileItem) => {
const index = fileList.value.findIndex((i) => i.uid === fileItem.uid);
console.log(fileItem, index);
if (index > -1) {
fileList.value.splice(index, 1);
}
};
const fileList = ref<FileItem[]>([]);
const modal = ref({ const modal = ref({
visible: false, visible: false,
}); });
const group = ref("default");
const groupOptions = [
{
label: "默认分类",
value: "default",
},
{
label: "视频分类",
value: "video",
},
];
const upload = (option: RequestOption) => { const upload = (option: RequestOption) => {
const { fileItem, onError, onProgress, onSuccess } = option; const { fileItem, onError, onProgress, onSuccess } = option;
const source = axios.CancelToken.source(); const source = axios.CancelToken.source();
@ -55,4 +150,9 @@ defineExpose({
}); });
</script> </script>
<style scoped></style> <style lang="less" scoped>
.upload :deep(.arco-upload-list) {
height: 426px;
overflow: auto;
}
</style>

View File

@ -45,13 +45,17 @@ declare module '@vue/runtime-core' {
AModal: typeof import('@arco-design/web-vue')['Modal'] AModal: typeof import('@arco-design/web-vue')['Modal']
APagination: typeof import('@arco-design/web-vue')['Pagination'] APagination: typeof import('@arco-design/web-vue')['Pagination']
APopover: typeof import('@arco-design/web-vue')['Popover'] APopover: typeof import('@arco-design/web-vue')['Popover']
AProgress: typeof import('@arco-design/web-vue')['Progress']
ARadio: typeof import('@arco-design/web-vue')['Radio'] ARadio: typeof import('@arco-design/web-vue')['Radio']
ARadioGroup: typeof import('@arco-design/web-vue')['RadioGroup'] ARadioGroup: typeof import('@arco-design/web-vue')['RadioGroup']
AScrollbar: typeof import('@arco-design/web-vue')['Scrollbar'] AScrollbar: typeof import('@arco-design/web-vue')['Scrollbar']
ASelect: typeof import('@arco-design/web-vue')['Select'] ASelect: typeof import('@arco-design/web-vue')['Select']
ASlider: typeof import('@arco-design/web-vue')['Slider']
ASpace: typeof import('@arco-design/web-vue')['Space'] ASpace: typeof import('@arco-design/web-vue')['Space']
ASpin: typeof import('@arco-design/web-vue')['Spin'] ASpin: typeof import('@arco-design/web-vue')['Spin']
ASwitch: typeof import('@arco-design/web-vue')['Switch'] ASwitch: typeof import('@arco-design/web-vue')['Switch']
ATable: typeof import('@arco-design/web-vue')['Table']
ATableColumn: typeof import('@arco-design/web-vue')['TableColumn']
ATabPane: typeof import('@arco-design/web-vue')['TabPane'] ATabPane: typeof import('@arco-design/web-vue')['TabPane']
ATabs: typeof import('@arco-design/web-vue')['Tabs'] ATabs: typeof import('@arco-design/web-vue')['Tabs']
ATag: typeof import('@arco-design/web-vue')['Tag'] ATag: typeof import('@arco-design/web-vue')['Tag']