实现 下拉滚动加载分页数据、导出动态加载进度条显示
							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