<template>
<PageWrapper title="导入需要校验的 Excel 文件" content="请上传一个有效的 Excel 文件,将计算返回处理结果。">
<div class="bg-white justify-center items-center">
<a-upload-dragger
v-model:fileList="fileList"
name="file"
:multiple="false"
:show-upload-list="false"
:before-upload="beforeUpload"
:action="throttledUploadFile"
:progress="progress"
>
<p class="ant-upload-drag-icon">
<InboxOutlined />
</p>
<p class="ant-upload-text">点击或拖拽文件到此区域上传</p>
<p class="ant-upload-hint">支持上传一个 Excel 文件(.xls 或 .xlsx)</p>
</a-upload-dragger>
<!-- 显示上传进度 -->
<a-progress
v-if="uploadProgress > 0"
:percent="uploadProgress"
status="active"
class="upload-progress"
/>
<div v-if="loading" class="loading-text">文件导入中,请耐心等待...</div>
<div v-if="responseData && responseData.length > 0" class="mt-4">
<h3>计算结果:</h3>
<a-table
:columns="columns"
:dataSource="responseData"
:pagination="false"
bordered
class="full-table"
>
<template #bodyCell="{ column, index }">
<span v-if="column.key === 'index'">{{ index + 1 }}</span>
</template>
</a-table>
</div>
</div>
</PageWrapper>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { PageWrapper } from '@/components/Page';
import { useMessage } from '@/hooks/web/useMessage';
import { InboxOutlined } from '@ant-design/icons-vue';
import { updateOldUserapi } from '@/api/demo/system';
const { createMessage } = useMessage();
const fileList = ref<any[]>([]);
const responseData = ref<any[]>([]);
const loading = ref(false); // 添加加载状态
const uploadProgress = ref(0); // 上传进度状态
const columns = ref([
{
title: '序号',
dataIndex: 'index',
key: 'index',
width: 80,
align: 'center',
},
{
title: '查找结果',
dataIndex: 'errorInfo',
key: 'errorInfo',
width: 180,
},
{
title: '项目编码',
dataIndex: 'projectNo',
key: 'projectNo',
width: 180,
resizable: true,
},
{
title: '项目名称',
dataIndex: 'projectName',
key: 'projectName',
width: 380,
resizable: true,
},
]);
const beforeUpload = (file: File) => {
const isExcel = file.type === 'application/vnd.ms-excel' ||
file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
if (!isExcel) {
createMessage.error('只能上传 Excel 文件(.xls 或 .xlsx)!');
}
return isExcel;
};
// 定义节流函数
const throttle = (fn: Function, delay: number) => {
let lastTime = 0;
return function (...args: any[]) {
const now = Date.now();
if (now - lastTime >= delay) {
lastTime = now;
fn.apply(this, args);
}
};
};
const uploadFile = async (file: File) => {
loading.value = true; // 开始加载
uploadProgress.value = 1;
const updateProgress = (percent: number) => {
uploadProgress.value = percent;
};
try {
for (let i = 40; i <= 90; i += 10) {
await new Promise((resolve) => setTimeout(resolve, 700));
updateProgress(i);
}
const result = await updateOldUserapi(file);
updateProgress(100);
responseData.value = result.map((item: any, index: number) => ({
index: index + 1, // 添加序号
errorInfo: item.errorInfo || '无错误信息', // 默认值
projectNo: item.projectNo,
projectName: item.projectName,
}));
createMessage.success(`${file.name} 文件导入成功.`);
} catch (error) {
createMessage.error(`${file.name} 文件导入超时,请重新导入`);
} finally {
loading.value = false;
setTimeout(() => {
uploadProgress.value = 0;
}, 500);
}
};
const throttledUploadFile = throttle(uploadFile, 5000);
// const handleDrop = (e: DragEvent) => {
// const file = e.dataTransfer.files[0];
// if (file) {
// throttledUploadFile(file);
// }
// };
</script>
<style scoped lang="less">
::v-deep .ant-table-thead > tr > th {
background-color: #f3f9fd !important;
color: #1a5174;
}
::v-deep .ant-table-tbody > tr > td {
color: #1a5174;
}
.full-table {
width: 100%;
}
.loading-text {
margin-top: 20px;
color: #7ccd7d;
font-size: 16px;
}
.upload-progress {
margin-top: 20px;
padding-right: 20px;
}
</style>
②封装的api updateOldUserapi
import { defHttp } from '@/utils/http/axios';
import { ContentTypeEnum } from '@/enums/httpEnum';
import { ErrorMessageMode } from '#/axios';
enum Api {
updateOldUser = '/projectOld/updateOldUser',
}
// 导入校验接口
export const updateOldUserapi = (file: File, mode: ErrorMessageMode = 'modal') => {
const formData = new FormData();
formData.append('file', file);
return defHttp.post({
url: Api.updateOldUser,
params: formData,
headers: {
'Content-Type': 'multipart/form-data',
},
}, { errorMessageMode: mode });
};