This commit is contained in:
2026-08-17 17:49:10 +08:00
parent 911a3620e1
commit c7334b2cf8
30 changed files with 1043 additions and 249 deletions
@@ -2,7 +2,17 @@ import axios from 'axios'
import { ApiResponseError, http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
export type ExportTaskStatus = 'PENDING' | 'RUNNING' | 'SUCCEEDED' | 'FAILED' | 'EXPIRED'
export type ExportTaskType = 'CUSTOMER_LIST' | string
export type KnownExportTaskType =
| 'CUSTOMER_LIST'
| 'FINANCE_CUSTOMER_ACCOUNT_LIST'
| 'FINANCE_CUSTOMER_ACCOUNT_LEDGER'
| 'FINANCE_FEE_SOURCE_LIST'
| 'FINANCE_RECONCILIATION_STATEMENT_LIST'
| 'FINANCE_RECEIVABLE_SETTLEMENT_LIST'
| 'FINANCE_RECEIVABLE_SETTLEMENT_DETAIL'
| 'FINANCE_PAYABLE_SETTLEMENT_LIST'
| 'FINANCE_PAYABLE_SETTLEMENT_DETAIL'
export type ExportTaskType = KnownExportTaskType | (string & {})
export interface PlatformExportTask {
id: string
@@ -101,6 +101,30 @@ describe('DownloadCenterView', () => {
expect(retryPlatformExportTask).toHaveBeenCalledWith('9')
})
it('labels and retries Finance tasks with their exact source export permission', async () => {
const financeTask = {
...task,
exportType: 'FINANCE_RECONCILIATION_STATEMENT_LIST',
taskName: '客户对账单',
status: 'FAILED' as const,
}
vi.mocked(listPlatformExportTasks).mockResolvedValue({ records: [financeTask], page: 1, size: 20, total: 1, pages: 1 })
const pinia = setActivePinia(createPinia())
const auth = useAuthStore()
auth.token = 'token'
auth.permissions = ['platform:download:list', 'platform:finance:customer-statement:export']
useAccessPreviewStore().initializeAfterLogin()
mount(DownloadCenterView, { attachTo: document.body, global: { plugins: [pinia, ElementPlus] } })
await flushPromises()
expect(document.body.textContent).toContain('客户对账单')
const retry = [...document.querySelectorAll<HTMLButtonElement>('button')]
.find((item) => item.textContent?.trim() === '重试')
retry?.click()
await flushPromises()
expect(retryPlatformExportTask).toHaveBeenCalledWith('9')
})
it('loads a fresh task detail from the backend', async () => {
const wrapper = mount(DownloadCenterView, { attachTo: document.body, global: { plugins: [createPinia(), ElementPlus] } })
await flushPromises()
@@ -25,6 +25,18 @@ type DownloadFilters = QueryModel & {
requestedRange: string[]
}
const exportTypeMeta: Record<string, { label: string; retryPermission: string }> = {
CUSTOMER_LIST: { label: '客户列表', retryPermission: 'platform:customer:export' },
FINANCE_CUSTOMER_ACCOUNT_LIST: { label: '客户账户', retryPermission: 'platform:finance:customer-account:export' },
FINANCE_CUSTOMER_ACCOUNT_LEDGER: { label: '客户账户流水', retryPermission: 'platform:finance:customer-account:export' },
FINANCE_FEE_SOURCE_LIST: { label: '客户应收应付费用来源', retryPermission: 'platform:finance:customer-arap:export' },
FINANCE_RECONCILIATION_STATEMENT_LIST: { label: '客户对账单', retryPermission: 'platform:finance:customer-statement:export' },
FINANCE_RECEIVABLE_SETTLEMENT_LIST: { label: '应收结算单列表', retryPermission: 'platform:finance:settlement-ar:export' },
FINANCE_RECEIVABLE_SETTLEMENT_DETAIL: { label: '应收结算单详情', retryPermission: 'platform:finance:settlement-ar:export' },
FINANCE_PAYABLE_SETTLEMENT_LIST: { label: '应付结算单列表', retryPermission: 'platform:finance:settlement-ap:export' },
FINANCE_PAYABLE_SETTLEMENT_DETAIL: { label: '应付结算单详情', retryPermission: 'platform:finance:settlement-ap:export' },
}
const access = useAccessPreviewStore()
const page = ref(1)
const pageSize = ref(20)
@@ -46,7 +58,7 @@ let detailRequestId = 0
const queryFields: QueryField[] = [
{ key: 'exportType', type: 'select', label: '任务类型', placeholder: '全部任务类型', options: [
{ label: '客户列表', value: 'CUSTOMER_LIST' },
...Object.entries(exportTypeMeta).map(([value, meta]) => ({ label: meta.label, value })),
] },
{ key: 'status', type: 'select', label: '任务状态', placeholder: '全部任务状态', options: [
{ label: '等待处理', value: 'PENDING' }, { label: '处理中', value: 'RUNNING' },
@@ -196,7 +208,7 @@ function safeFileName(value: string) {
return safe || '导出文件.xlsx'
}
function typeLabel(type: string) { return type === 'CUSTOMER_LIST' ? '客户列表' : type }
function typeLabel(type: string) { return exportTypeMeta[type]?.label || type }
function statusMeta(status: ExportTaskStatus) {
const values = {
@@ -223,7 +235,8 @@ function formatSize(bytes: number | null) {
}
function canRetry(task: PlatformExportTask) {
return task.status === 'FAILED' && task.exportType === 'CUSTOMER_LIST' && access.can('platform:customer:export')
const permission = exportTypeMeta[task.exportType]?.retryPermission
return task.status === 'FAILED' && permission !== undefined && access.can(permission)
}
watch([page, pageSize], () => { void loadTasks() })