feat: 添加文件上传进度对话框

- 在 codes、data/import 和 data/maintain 模块中添加上传进度对话框
- 对话框包含上传步骤、提示信息和加载动画
- 优化了上传逻辑,增加了步骤状态更新
- 修改了上传相关提示信息,统一为英文
- 调整了下载模板文件名,使用 "UploadTemplate" 前缀
This commit is contained in:
皓月归尘 2025-04-21 01:53:01 +08:00
parent de4463cc24
commit b9b64ceb5a
7 changed files with 188 additions and 18 deletions

View File

@ -101,6 +101,40 @@
</el-popconfirm> </el-popconfirm>
</div> </div>
</template> </template>
<el-dialog
v-model="dialogVisible"
title="Upload Status"
width="50%"
draggable
center
:show-close="false"
:close-on-click-modal="false"
>
<el-steps :active="activeStep" align-center>
<el-step
title="Step 1"
description="Upload File"
finish-status="success"
/>
<el-step
title="Step 2"
description="Parsing Data"
finish-status="success"
/>
<el-step
title="Step 3"
description="Parse Complete"
finish-status="success"
/>
</el-steps>
<el-divider />
<el-alert
title="Data is being parsed, please be patient~"
type="warning"
center
show-icon
/>
</el-dialog>
</el-card> </el-card>
<!-- 查询结果 --> <!-- 查询结果 -->
<el-card v-if="queryResult" shadow="never" class="mt-2"> <el-card v-if="queryResult" shadow="never" class="mt-2">
@ -351,6 +385,8 @@ const {
queryResult, queryResult,
selectedNum, selectedNum,
showUploadArea, showUploadArea,
dialogVisible,
activeStep,
fileIds, fileIds,
fileList, fileList,
uploadStatus, uploadStatus,

View File

@ -58,6 +58,10 @@ export const useIndex = (tableRef: Ref) => {
const fileId = ref<string>(""); const fileId = ref<string>("");
/**上传按钮状态 */ /**上传按钮状态 */
const uploadStatus = ref<boolean>(false); const uploadStatus = ref<boolean>(false);
/**上传对话框 */
const dialogVisible = ref(false);
/**当前上传步骤 */
const activeStep = ref<number>(1);
/** /**
* *
*/ */
@ -201,7 +205,7 @@ export const useIndex = (tableRef: Ref) => {
// 创建 <a> 元素并触发下载 // 创建 <a> 元素并触发下载
const link = document.createElement("a"); const link = document.createElement("a");
link.href = url; link.href = url;
link.download = `上传模版.${type}`; // 设置下载文件名,确保后缀名正确 link.download = `UploadTemplate.${type}`; // 设置下载文件名,确保后缀名正确
document.body.appendChild(link); // 将 <a> 元素添加到 DOM 中 document.body.appendChild(link); // 将 <a> 元素添加到 DOM 中
link.click(); // 模拟点击下载 link.click(); // 模拟点击下载
@ -227,7 +231,7 @@ export const useIndex = (tableRef: Ref) => {
// const maxSize = 20 * 1024 * 1024; // 20MB 限制 // const maxSize = 20 * 1024 * 1024; // 20MB 限制
if (!isExcel) { if (!isExcel) {
message("只能上传 xlsx 或 xls 文件!", { type: "error" }); message("Only xlsx or xls files can be uploaded!", { type: "error" });
return false; return false;
} }
/* /*
@ -242,8 +246,14 @@ export const useIndex = (tableRef: Ref) => {
/**处理文件上传 */ /**处理文件上传 */
const handleUpload = async () => { const handleUpload = async () => {
activeStep.value = 1;
dialogVisible.value = true;
if (fileList.value.length === 0) { if (fileList.value.length === 0) {
message("请先上传文件!", { type: "error", duration: 5000 }); message("Please select the file first!", {
type: "error",
duration: 5000
});
dialogVisible.value = false;
return; return;
} }
uploadStatus.value = true; uploadStatus.value = true;
@ -252,7 +262,7 @@ export const useIndex = (tableRef: Ref) => {
if (file.status === "success") { if (file.status === "success") {
const data = await getQueryCodeAPI(fileId.value); const data = await getQueryCodeAPI(fileId.value);
if (data.success) { if (data.success) {
message("查询成功!", { type: "success" }); message(data.msg, { type: "success" });
queryResult.value = data.data; queryResult.value = data.data;
dataList.value = data.data.response_result; dataList.value = data.data.response_result;
pagination.total = data.data.result_count; pagination.total = data.data.result_count;
@ -266,7 +276,10 @@ export const useIndex = (tableRef: Ref) => {
if (res.success) { if (res.success) {
file.status = "success"; file.status = "success";
fileId.value = res.data.id; fileId.value = res.data.id;
message(`${res.data.name}上传成功!`, { type: "success" }); message(`${res.data.name} Uploaded successfully!`, {
type: "success"
});
activeStep.value = 2;
fileIds.value.push(res.data); fileIds.value.push(res.data);
const data = await getQueryCodeAPI(fileId.value); const data = await getQueryCodeAPI(fileId.value);
if (data.success) { if (data.success) {
@ -295,6 +308,9 @@ export const useIndex = (tableRef: Ref) => {
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} finally {
dialogVisible.value = false;
activeStep.value = 1;
} }
} }
uploadStatus.value = false; uploadStatus.value = false;
@ -536,6 +552,8 @@ export const useIndex = (tableRef: Ref) => {
queryResult, queryResult,
selectedNum, selectedNum,
showUploadArea, showUploadArea,
dialogVisible,
activeStep,
fileIds, fileIds,
fileList, fileList,
uploadStatus, uploadStatus,

View File

@ -192,6 +192,40 @@
</el-popconfirm> </el-popconfirm>
</div> </div>
</template> </template>
<el-dialog
v-model="dialogVisible"
title="Upload Status"
width="50%"
draggable
center
:show-close="false"
:close-on-click-modal="false"
>
<el-steps :active="activeStep" align-center>
<el-step
title="Step 1"
description="Upload File"
finish-status="success"
/>
<el-step
title="Step 2"
description="Parsing Data"
finish-status="success"
/>
<el-step
title="Step 3"
description="Parse Complete"
finish-status="success"
/>
</el-steps>
<el-divider />
<el-alert
title="Data is being parsed, please be patient~"
type="warning"
center
show-icon
/>
</el-dialog>
</el-card> </el-card>
<div <div
v-if="selectedNum > 0" v-if="selectedNum > 0"
@ -385,6 +419,8 @@ const {
selectedNum, selectedNum,
showUploadArea, showUploadArea,
departments, departments,
dialogVisible,
activeStep,
fileList, fileList,
uploadStatus, uploadStatus,
beforeUpload, beforeUpload,

View File

@ -69,6 +69,10 @@ export const useCode = (tableRef: Ref) => {
const fileIds = ref([]); const fileIds = ref([]);
/**上传按钮状态 */ /**上传按钮状态 */
const uploadStatus = ref<boolean>(false); const uploadStatus = ref<boolean>(false);
/**上传对话框 */
const dialogVisible = ref(false);
/**当前上传步骤 */
const activeStep = ref<number>(1);
const getStatusTag = (status: number) => { const getStatusTag = (status: number) => {
switch (status) { switch (status) {
@ -366,7 +370,7 @@ export const useCode = (tableRef: Ref) => {
// 创建 <a> 元素并触发下载 // 创建 <a> 元素并触发下载
const link = document.createElement("a"); const link = document.createElement("a");
link.href = url; link.href = url;
link.download = `上传模版.${type}`; // 设置下载文件名,确保后缀名正确 link.download = `UploadTemplate.${type}`; // 设置下载文件名,确保后缀名正确
document.body.appendChild(link); // 将 <a> 元素添加到 DOM 中 document.body.appendChild(link); // 将 <a> 元素添加到 DOM 中
link.click(); // 模拟点击下载 link.click(); // 模拟点击下载
@ -391,7 +395,7 @@ export const useCode = (tableRef: Ref) => {
// const maxSize = 20 * 1024 * 1024; // 20MB 限制 // const maxSize = 20 * 1024 * 1024; // 20MB 限制
if (!isExcel) { if (!isExcel) {
message("只能上传 xlsx 或 xls 文件!", { type: "error" }); message("Only xlsx or xls files can be uploaded!", { type: "error" });
return false; return false;
} }
/* /*
@ -406,8 +410,14 @@ export const useCode = (tableRef: Ref) => {
/** 处理文件上传 */ /** 处理文件上传 */
const handleUpload = async () => { const handleUpload = async () => {
activeStep.value = 1;
dialogVisible.value = true;
if (fileList.value.length === 0) { if (fileList.value.length === 0) {
message("请先选择文件!", { type: "error", duration: 5000 }); message("Please select the file first!", {
type: "error",
duration: 5000
});
dialogVisible.value = false;
return; return;
} }
@ -422,14 +432,18 @@ export const useCode = (tableRef: Ref) => {
if (res.success) { if (res.success) {
file.status = "success"; file.status = "success";
fileIds.value.push(res.data); // 记录成功上传的文件ID fileIds.value.push(res.data); // 记录成功上传的文件ID
message(`${res.data.name} 上传成功!`, { type: "success" }); message(`${res.data.name} Uploaded successfully!`, {
type: "success"
});
} else { } else {
file.status = "fail"; file.status = "fail";
message(`${file.name} 上传失败!`, { type: "error" }); message(`${file.name} Upload failed!`, { type: "error" });
dialogVisible.value = false;
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
file.status = "fail"; file.status = "fail";
dialogVisible.value = false;
} }
} }
@ -442,12 +456,16 @@ export const useCode = (tableRef: Ref) => {
getKeyList(fileIds.value, "id") getKeyList(fileIds.value, "id")
); );
if (data.success) { if (data.success) {
activeStep.value = 3;
message("批量导入成功!", { type: "success" }); message("批量导入成功!", { type: "success" });
await onSearch(); await onSearch();
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
message("批量导入失败!", { type: "error" }); message("批量导入失败!", { type: "error" });
} finally {
dialogVisible.value = false;
activeStep.value = 1;
} }
} }
}; };
@ -657,6 +675,8 @@ export const useCode = (tableRef: Ref) => {
selectedNum, selectedNum,
showUploadArea, showUploadArea,
departments, departments,
dialogVisible,
activeStep,
fileIds, fileIds,
fileList, fileList,
uploadStatus, uploadStatus,

View File

@ -184,6 +184,40 @@
</div> </div>
</template> </template>
</el-card> </el-card>
<el-dialog
v-model="dialogVisible"
title="Upload Status"
width="50%"
draggable
center
:show-close="false"
:close-on-click-modal="false"
>
<el-steps :active="activeStep" align-center>
<el-step
title="Step 1"
description="Upload File"
finish-status="success"
/>
<el-step
title="Step 2"
description="Parsing Data"
finish-status="success"
/>
<el-step
title="Step 3"
description="Parse Complete"
finish-status="success"
/>
</el-steps>
<el-divider />
<el-alert
title="Data is being parsed, please be patient~"
type="warning"
center
show-icon
/>
</el-dialog>
<div <div
v-if="selectedNum > 0" v-if="selectedNum > 0"
v-motion-fade v-motion-fade
@ -299,6 +333,7 @@ const { t } = useI18n();
*/ */
const tableRef = ref(); const tableRef = ref();
const formRef = ref(); const formRef = ref();
const { const {
form, form,
dataList, dataList,
@ -310,6 +345,8 @@ const {
showUploadArea, showUploadArea,
fileList, fileList,
uploadStatus, uploadStatus,
dialogVisible,
activeStep,
beforeUpload, beforeUpload,
handleUpload, handleUpload,
beforeRemove, beforeRemove,

View File

@ -66,6 +66,10 @@ export const useCode = (tableRef: Ref) => {
const fileIds = ref([]); const fileIds = ref([]);
/**上传按钮状态 */ /**上传按钮状态 */
const uploadStatus = ref<boolean>(false); const uploadStatus = ref<boolean>(false);
/**上传对话框 */
const dialogVisible = ref(false);
/**当前上传步骤 */
const activeStep = ref<number>(1);
/** /**
* *
*/ */
@ -305,7 +309,7 @@ export const useCode = (tableRef: Ref) => {
// 创建 <a> 元素并触发下载 // 创建 <a> 元素并触发下载
const link = document.createElement("a"); const link = document.createElement("a");
link.href = url; link.href = url;
link.download = "上传模版.xlsx"; // 设置下载文件名,确保后缀名正确 link.download = "UploadTemplate.xlsx"; // 设置下载文件名,确保后缀名正确
document.body.appendChild(link); // 将 <a> 元素添加到 DOM 中 document.body.appendChild(link); // 将 <a> 元素添加到 DOM 中
link.click(); // 模拟点击下载 link.click(); // 模拟点击下载
@ -330,7 +334,7 @@ export const useCode = (tableRef: Ref) => {
// const maxSize = 20 * 1024 * 1024; // 20MB 限制 // const maxSize = 20 * 1024 * 1024; // 20MB 限制
if (!isExcel) { if (!isExcel) {
message("只能上传 xlsx 或 xls 文件!", { type: "error" }); message("Only xlsx or xls files can be uploaded!", { type: "error" });
return false; return false;
} }
/* /*
@ -345,30 +349,43 @@ export const useCode = (tableRef: Ref) => {
/** 处理文件上传 */ /** 处理文件上传 */
const handleUpload = async () => { const handleUpload = async () => {
activeStep.value = 1;
dialogVisible.value = true;
if (fileList.value.length === 0) { if (fileList.value.length === 0) {
message("请先选择文件!", { type: "error", duration: 5000 }); message("Please select the file first!", {
type: "error",
duration: 5000
});
dialogVisible.value = false;
return; return;
} }
uploadStatus.value = true; uploadStatus.value = true;
for (const file of fileList.value) { for (const file of fileList.value) {
if (file.status === "success") continue; // 已上传成功的跳过 if (file.status === "success") {
activeStep.value = 2;
continue;
} // 已上传成功的跳过
try { try {
const res = await postUploadFileAPI({ file: file.raw }); const res = await postUploadFileAPI({ file: file.raw });
if (res.success) { if (res.success) {
file.status = "success"; file.status = "success";
fileIds.value.push(res.data); // 记录成功上传的文件ID fileIds.value.push(res.data); // 记录成功上传的文件ID
message(`${res.data.name} 上传成功!`, { type: "success" }); activeStep.value = 2;
message(`${res.data.name} Uploaded successfully!`, {
type: "success"
});
} else { } else {
file.status = "fail"; file.status = "fail";
message(`${file.name} 上传失败!`, { type: "error" }); message(`${file.name} Upload failed!`, { type: "error" });
dialogVisible.value = false;
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
file.status = "fail"; file.status = "fail";
dialogVisible.value = false;
} }
} }
@ -381,12 +398,16 @@ export const useCode = (tableRef: Ref) => {
getKeyList(fileIds.value, "id") getKeyList(fileIds.value, "id")
); );
if (data.success) { if (data.success) {
activeStep.value = 3;
message("批量导入成功!", { type: "success" }); message("批量导入成功!", { type: "success" });
await onSearch(); await onSearch();
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
message("批量导入失败!", { type: "error" }); message("批量导入失败!", { type: "error" });
} finally {
dialogVisible.value = false;
activeStep.value = 1;
} }
} }
}; };
@ -457,6 +478,8 @@ export const useCode = (tableRef: Ref) => {
selectedNum, selectedNum,
departments, departments,
showUploadArea, showUploadArea,
dialogVisible,
activeStep,
fileIds, fileIds,
fileList, fileList,
uploadStatus, uploadStatus,

View File

@ -27,7 +27,7 @@ export default ({ mode }: ConfigEnv): UserConfigExport => {
proxy: { proxy: {
"/api": { "/api": {
// 这里填写后端地址 // 这里填写后端地址
target: "http://localhost:8082", target: "http://127.0.0.1:8082",
changeOrigin: true, changeOrigin: true,
rewrite: path => path.replace(/^\/api/, "") rewrite: path => path.replace(/^\/api/, "")
} }