packages.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839
  1. <template>
  2. <div class="p-4">
  3. <NCard title="待下载数据">
  4. <NDataTable :columns="columns" :data="jobs" :loading="loading" :row-key="(row: DataDownloadPackageJob) => row.id" />
  5. <div class="mt-4 flex justify-end"><NPagination v-model:page="page" :item-count="total" @update:page="load" /></div>
  6. </NCard>
  7. </div>
  8. </template>
  9. <script setup lang="tsx">
  10. import { NButton, NTag, type DataTableColumns } from 'naive-ui'
  11. import dayjs from 'dayjs'
  12. import { cancelDataDownloadPackage, deleteDataDownloadPackage, downloadDataDownloadPackage, getDataDownloadPackages, retryDataDownloadPackage } from '@/service/dataDownload'
  13. import type { DataDownloadPackageJob } from '@/service/dataDownload/interface'
  14. defineOptions({ name: 'DataDownloadPackages' })
  15. const message = useMessage()
  16. const jobs = ref<DataDownloadPackageJob[]>([])
  17. const loading = ref(false)
  18. const page = ref(1)
  19. const total = ref(0)
  20. const columns: DataTableColumns<DataDownloadPackageJob> = [
  21. { title: '文件名', key: 'filename', minWidth: 260 },
  22. { title: '状态', key: 'status', width: 130, render: row => <NTag type={row.status === 'complete' ? 'success' : row.status === 'failed' ? 'error' : 'warning'}>{row.status}</NTag> },
  23. { title: '进度', key: 'progress', width: 100, render: row => `${row.doneCount}/${row.totalCount}` },
  24. { title: '大小', key: 'size', width: 100, render: row => row.size ? `${(row.size / 1024 / 1024).toFixed(2)} MB` : '-' },
  25. { title: '创建时间', key: 'createdAt', width: 180, render: row => dayjs(row.createdAt).format('YYYY-MM-DD HH:mm:ss') },
  26. { title: '过期时间', key: 'expiresAt', width: 180, render: row => row.expiresAt ? dayjs(row.expiresAt).format('YYYY-MM-DD HH:mm:ss') : '-' },
  27. { title: '操作', key: 'action', width: 250, render: row => <div class="flex gap-2"><NButton size="small" type="primary" disabled={row.status !== 'complete'} onClick={() => downloadDataDownloadPackage(row.id)}>下载</NButton><NButton size="small" disabled={row.status !== 'failed'} onClick={() => retry(row)}>重试</NButton><NButton size="small" disabled={!['pending', 'running'].includes(row.status)} onClick={() => cancel(row)}>取消</NButton><NButton size="small" type="error" disabled={['pending', 'running', 'cancelling'].includes(row.status)} onClick={() => remove(row)}>删除</NButton></div> },
  28. ]
  29. async function load() { loading.value = true; try { const data = await getDataDownloadPackages(page.value, 20); jobs.value = data.items || []; total.value = data.total || 0 } finally { loading.value = false } }
  30. async function cancel(row: DataDownloadPackageJob) { await cancelDataDownloadPackage(row.id); message.success('已请求取消'); await load() }
  31. async function retry(row: DataDownloadPackageJob) { await retryDataDownloadPackage(row.id); message.success('已创建新的打包任务'); await load() }
  32. async function remove(row: DataDownloadPackageJob) { await deleteDataDownloadPackage(row.id); message.success('已删除 ZIP 及记录'); await load() }
  33. onMounted(load)
  34. let timer: number | undefined
  35. watch(jobs, value => { clearTimeout(timer); if (value.some(row => ['pending', 'running', 'cancelling'].includes(row.status))) timer = window.setTimeout(load, 5000) }, { deep: true })
  36. onBeforeUnmount(() => clearTimeout(timer))
  37. </script>