This commit is contained in:
2026-08-10 16:24:54 +08:00
parent e119b48662
commit 820432a381
52 changed files with 1015 additions and 705 deletions
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { Download, Eye, RefreshCw, RotateCcw } from '@lucide/vue'
import { Download, Eye, RotateCcw } from '@lucide/vue'
import { ElMessage } from 'element-plus'
import { getApiErrorDetails, getApiErrorMessage, type ApiErrorDetails } from '@/shared/api/http'
import {
@@ -12,8 +12,10 @@ import {
type PlatformExportTask,
} from '@/modules/downloads/api/platformExportTasks'
import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'
import AdminPage from '@/shared/components/AdminPage.vue'
import AppDrawer from '@/shared/components/AppDrawer.vue'
import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.vue'
import ListPageLayout from '@/shared/components/ListPageLayout.vue'
import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue'
import { useAccessPreviewStore } from '@/core/access/accessPreview'
@@ -232,22 +234,27 @@ onBeforeUnmount(() => {
</script>
<template>
<AdminPage>
<div class="business-page download-center-page">
<QueryToolbar v-model="filters" class="surface-panel" ariaLabel="下载任务筛选" :fields="queryFields" preference-key="downloads-query" @search="applyFilters" />
<ListPageLayout ariaLabel="下载任务列表">
<template #toolbar>
<QueryToolbar v-model="filters" class="surface-panel" ariaLabel="下载任务筛选" :fields="queryFields" preference-key="downloads-query" @search="applyFilters" />
</template>
<section v-if="loadError" class="surface-panel download-error" role="alert">
<div><strong>下载任务暂时无法加载</strong><p>{{ loadError.message }}</p><ApiErrorMeta :details="loadError" /></div>
<el-button type="primary" :loading="loading" @click="loadTasks()">重新加载</el-button>
</section>
<template v-if="loadError" #state>
<section class="surface-panel download-error" role="alert">
<div><strong>下载任务暂时无法加载</strong><p>{{ loadError.message }}</p><ApiErrorMeta :details="loadError" /></div>
<el-button type="primary" :loading="loading" @click="loadTasks()">重新加载</el-button>
</section>
</template>
<section v-else class="surface-panel table-panel" :aria-busy="loading">
<section v-if="!loadError" class="surface-panel table-panel" :aria-busy="loading">
<div v-if="syncWarning" class="download-sync-warning" role="status">
<span>自动刷新暂时失败,正在保留当前任务并继续重试:{{ syncWarning.message }}</span>
<ApiErrorMeta :details="syncWarning" />
</div>
<DataTable v-model:page="page" v-model:page-size="pageSize" :data="result.records" :columns="columns" preference-key="downloads-table" :loading="loading" :total="result.total" row-key="id" empty-text="暂无符合筛选条件的下载任务" aria-label="下载任务列表">
<template #toolbar-start><div class="download-table-heading"><h2>下载任务</h2><span>共 {{ result.total }} 个任务</span></div></template>
<template #toolbar-actions><el-button :loading="loading" @click="loadTasks()"><RefreshCw :size="16" />刷新</el-button></template>
<template #pagination-left="{ total: tableTotal }"><span>共 {{ tableTotal }} 个任务</span></template>
<template #actions="{ row }"><div class="table-actions">
<el-button v-if="(row as PlatformExportTask)?.id" link type="primary" @click="openDetail(row as PlatformExportTask)"><Eye :size="15" />详情</el-button>
<el-button v-if="(row as PlatformExportTask).status === 'SUCCEEDED'" link type="primary" :loading="downloadingId === (row as PlatformExportTask).id" @click="downloadTask(row as PlatformExportTask)"><Download :size="15" />下载</el-button>
@@ -263,6 +270,7 @@ onBeforeUnmount(() => {
<template #failure="{ row }"><span class="failure-cell" :class="{ 'failure-message': Boolean((row as PlatformExportTask).failureMessage) }">{{ (row as PlatformExportTask).failureMessage || '—' }}</span></template>
</DataTable>
</section>
</ListPageLayout>
<AppDrawer
v-model="detailOpen"
@@ -305,6 +313,7 @@ onBeforeUnmount(() => {
</div>
</AppDrawer>
</div>
</AdminPage>
</template>
<style scoped>
@@ -313,8 +322,6 @@ onBeforeUnmount(() => {
.download-error { padding: 18px; }
.download-error strong { color: var(--cc-danger); font-size: 14px; }
.download-error p { margin: 5px 0; color: var(--cc-text); font-size: 13px; }
.download-table-heading h2 { margin: 0; color: var(--cc-text); font-size: 16px; }
.download-table-heading span { display: block; margin-top: 3px; color: var(--cc-muted); font-size: 12px; }
.download-sync-warning { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 18px; border-bottom: 1px solid #fedf89; background: #fffaeb; color: #93370d; font-size: 12px; }
.table-actions { display: flex; min-height: 32px; align-items: center; gap: 8px; }
.table-actions :deep(.el-button + .el-button) { margin-left: 0; }