[Vxe Table]虚拟列表渲染18万条数据

2025-08-12

https://vxetable.cn/

要做一个选择Excel文件读取数据然后选择要删除数据的功能。

使用xlsx.js解析完成Excel的数据之后,需要展示出来,让用户勾选哪些不需要删除。

//main.js
import { VxeUI } from 'vxe-table'
import zhCN from 'vxe-table/lib/locale/lang/zh-CN.js'
VxeUI.setI18n('zh-CN', zhCN)
VxeUI.setLanguage('zh-CN')
<VxeTable
          height="600"
          :data="tableData"
          :cell-config="{ height: 25 }"
          :virtual-y-config="{ enabled: true, gt: 0 }"
          :checkbox-config="{ trigger: 'row' }"
          border
          ref="tableRef"
        >
          <vxe-column type="checkbox" width="60"></vxe-column>
          <VxeColumn type="seq" width="100"></VxeColumn>
          <VxeColumn v-for="(item, index) in tableColumns" :key="index" :field="item.code" :title="item.text"></VxeColumn>
        </VxeTable>
//数据量特别大 使用分批请求

import { del } from '@/api/export/restrictedBox/index'

async function sendRequest(batch) {
  try {
    const res = await del(batch)
    if (res.code != 200) throw new Error(`${res.msg}`)
    return res.data
  } catch (err) {
    throw err
  }
}

// 分批工具
function chunkArray(array, size) {
  const chunks = []
  for (let i = 0; i < array.length; i += size) {
    chunks.push(array.slice(i, i + size))
  }
  return chunks
}

// 并发执行器(支持暂停/恢复 + 重试 + 动态进度条)
function createTaskRunner(tasks, concurrency, maxRetries = 3) {
  let index = 0
  let completed = 0
  const total = tasks.length
  const results = []
  let paused = false

  function logProgressInline() {
    const percent = ((completed / total) * 100).toFixed(2)
    const barLength = 30
    const filledLength = Math.round((completed / total) * barLength)
    const bar = '█'.repeat(filledLength) + '-'.repeat(barLength - filledLength)
    console.clear()
    console.log(`进度: [${bar}] ${completed}/${total} 批 (${percent}%)`)
  }

  async function runTask(taskIndex, retriesLeft) {
    try {
      const res = await tasks[taskIndex]()
      completed++
      logProgressInline()
      return res
    } catch (err) {
      if (retriesLeft > 0) {
        return runTask(taskIndex, retriesLeft - 1)
      } else {
        completed++
        logProgressInline()
        return null
      }
    }
  }

  async function worker() {
    while (index < total) {
      if (paused) {
        await new Promise(resolve => {
          const interval = setInterval(() => {
            if (!paused) {
              clearInterval(interval)
              resolve()
            }
          }, 100)
        })
      }
      const currentIndex = index++
      results[currentIndex] = await runTask(currentIndex, maxRetries)
    }
  }

  async function start() {
    logProgressInline()
    await Promise.all(Array.from({ length: concurrency }, worker))
    console.log('✅ 全部完成')
    return results
  }

  function pause() {
    paused = true
    console.log('⏸ 任务已暂停')
  }

  function resume() {
    paused = false
    console.log('▶️ 任务已恢复')
  }

  return { start, pause, resume, results }
}

// 主执行函数
export default async function main(data) {
  try {
    const batches = chunkArray(data, 100) // 每批 100 条
    console.log(`总共有 ${batches.length} 批需要发送`)

    const tasks = batches.map(batch => async () => {
      await sendRequest(batch)
      return true
    })

    const runner = createTaskRunner(tasks, 5, 3) // 并发 5 批,失败重试 3 次

    await runner.start()
    console.log('全部发送完成')

    return true
  } catch (error) {
    console.error('Error occurred while sending requests:', error)
    return false
  }
}

NEXT
Claude Code Router v1.0.33配置指南:轻松连接各类三方API——附邪修环境切换法