实现 下拉滚动加载分页数据、导出动态加载进度条显示

main
HUOJIN\92525 2025-05-08 17:02:34 +08:00
parent 9b61dab6c6
commit ffdf0aaf71
3 changed files with 139 additions and 19 deletions

View File

@ -59,11 +59,20 @@ export const addressApi = {
return postRequest('/address/importAddress', file);
},
createExportTask: () => {
return postRequest('/address/createExportTask', {});
},
getExportProgress: (taskId: string) => {
return getRequest(`/address/progress/${taskId}`, {});
},
/**
* @author hj
*/
exportAddress: () => {
return getDownload('/address/exportAddress', {});
exportAddress: (taskId: string) => {
return getDownload(`/address/exportAddress/${taskId}`, {});
}
};

View File

@ -56,6 +56,12 @@
</template>
导入
</a-button>
<a-modal v-model:open="open" :title="progressTitle" :maskClosable="false" :footer="null">
<a-progress
:percent="progressPercent"
:status="progressStatus"
/>
</a-modal>
<a-button @click="onExportAddress" type="primary" v-privilege="'address:exportAddress'">
<template #icon>
@ -79,6 +85,7 @@
bordered
:loading="tableLoading"
:pagination="false"
:scroll="{ x: 1500, y: 350 }"
:row-selection="{ selectedRowKeys: selectedRowKeyList, onChange: onSelectChange }"
>
<template #bodyCell="{ text, record, column }">
@ -180,7 +187,6 @@ import AddressForm from '/@/views/business/wms/base/address/address-form.vue';
import {TABLE_ID_CONST} from "/@/constants/support/table-id-const";
import AddressSelect from "/@/views/business/wms/base/address/address-select.vue";
import {fileApi} from "/@/api/support/file-api";
// ---------------------------- ----------------------------
// loading
const tableLoading = ref(false);
@ -420,9 +426,56 @@ async function onImportAddress() {
}
//
function onExportAddress() {
addressApi.exportAddress();
}
const progressTitle = ref('文件导出中,请稍等...');
const progressPercent = ref(0);//
const progressStatus = ref('active');//
const currentTaskId = ref('');//ID
const open = ref<boolean>(false);//
const onExportAddress = async () => {
try {
open.value = true;
//ID
const {data: taskId} = await addressApi.createExportTask();
currentTaskId.value = taskId;
progressStatus.value = 'active';
//
addressApi.exportAddress(currentTaskId.value);
//
const timer = setInterval(async () => {
try {
//
const {data: progress} = await addressApi.getExportProgress(currentTaskId.value);
if (progress === -1) {
clearInterval(timer);
progressStatus.value = 'exception';
return;
}
progressPercent.value = progress;
if (progress >= 100) {
clearInterval(timer);
progressStatus.value = 'success';
progressTitle.value = '文件导出完成';
// 1
setTimeout(() => {
open.value = false;
progressPercent.value = 0;
}, 1000);
}
} catch (error) {
clearInterval(timer);
progressStatus.value = 'exception';
progressPercent.value = 0;
}
}, 1000); //
} catch (error) {
message.error('导出失败');
}
};
onMounted(queryData);

View File

@ -7,14 +7,19 @@
<a-select
v-model:value="selectValue"
:style="`width: ${width}`"
:placeholder="placeholder"
:placeholder="props.placeholder"
:showSearch="true"
:allowClear="true"
:size="size"
@change="handleChange"
@search="handleSearch"
@popupScroll="handleScroll"
@blur="handleBlur"
:disabled="disabled"
:mode="multiple ? 'multiple' : undefined"
:mode="multiple ? 'multiple' : ''"
optionFilterProp="label"
:loading="loading"
>
>
<a-select-option v-for="address in addressList" :key="address.addressId" :label="address.name">
{{ address.name }}
@ -25,7 +30,18 @@
<script setup lang="ts">
import {onMounted, ref, watch} from 'vue';
import {addressApi} from "/@/api/business/wms/base/address/address-api";
import {smartSentry} from '/@/lib/smart-sentry';
import {debounce} from "lodash";
import {smartSentry} from "/@/lib/smart-sentry";
const loading = ref(false);
const page = ref({
pageNum: 1,
pageSize: 10,
total: 0,
name: ''
});
interface Address {
addressId: number;
@ -33,10 +49,7 @@ interface Address {
}
const props = defineProps({
modelValue: {
type: [Number, String, Object, Array],
default: undefined
},
value: [Number, String, Object, Array],
width: {
type: String,
default: '200px',
@ -57,18 +70,39 @@ const props = defineProps({
type: Boolean,
default: false,
},
status: {
type: String,
default: null,
},
disabledFlag: {
type: Boolean,
default: null,
},
});
const addressList = ref<Address[]>([]);
const selectValue = ref(props.modelValue);
const selectValue = ref(props.value);
async function queryData() {
async function queryData(append = false) {
try {
const res = await addressApi.queryAddress({});
addressList.value = res.data;
loading.value = true;
let res = await addressApi.queryAddress({
pageNum: page.value.pageNum,
pageSize: page.value.pageSize,
name: page.value.name
});
if (append) {
addressList.value = [...addressList.value, ...res.data.list];
} else {
addressList.value = res.data.list;
}
page.value.total = res.data.total;
} catch (e) {
smartSentry.captureError(e);
} finally {
loading.value = false;
}
}
function querySelectedAddress(value: any) {
@ -89,9 +123,33 @@ function handleChange(value: any) {
emit('change', selectedAddress);
}
// modelValue
//
const handleSearch = debounce(async (value: string) => {
page.value.name = value;
page.value.pageNum = 1;
await queryData();
}, 500);
//
const handleScroll = async (e: Event) => {
const {scrollTop, clientHeight, scrollHeight} = e.target as HTMLElement;
if (scrollHeight - (scrollTop + clientHeight) < 10 && !loading.value) {
if (addressList.value.length < page.value.total) {
page.value.pageNum++;
await queryData(true);
}
}
};
//
const handleBlur = async () => {
page.value.pageNum = 1;
await queryData();
};
// value
watch(
() => props.modelValue,
() => props.value,
(newValue) => {
selectValue.value = newValue;
}