实现 下拉滚动加载分页数据、导出动态加载进度条显示
parent
9b61dab6c6
commit
ffdf0aaf71
|
|
@ -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}`, {});
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue