优化
This commit is contained in:
@@ -19,8 +19,16 @@ import { createPlatformExportTask } from '@/modules/downloads'
|
|||||||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||||||
import { useAuthStore } from '@/core/auth/auth'
|
import { useAuthStore } from '@/core/auth/auth'
|
||||||
import QueryToolbar from '@/shared/components/QueryToolbar.vue'
|
import QueryToolbar from '@/shared/components/QueryToolbar.vue'
|
||||||
|
import { showExportTaskCreatedDialog } from '@/shared/components/exportTaskCreatedDialog'
|
||||||
import CustomersView from './CustomersView.vue'
|
import CustomersView from './CustomersView.vue'
|
||||||
|
|
||||||
|
const { routerPush } = vi.hoisted(() => ({ routerPush: vi.fn() }))
|
||||||
|
|
||||||
|
vi.mock('vue-router', async (importOriginal) => ({
|
||||||
|
...await importOriginal<typeof import('vue-router')>(),
|
||||||
|
useRouter: () => ({ push: routerPush }),
|
||||||
|
}))
|
||||||
|
|
||||||
vi.mock('@/modules/iam', () => ({
|
vi.mock('@/modules/iam', () => ({
|
||||||
approveEnterpriseReview: vi.fn(),
|
approveEnterpriseReview: vi.fn(),
|
||||||
changePlatformTenantStatus: vi.fn(),
|
changePlatformTenantStatus: vi.fn(),
|
||||||
@@ -39,6 +47,7 @@ vi.mock('@/modules/iam', () => ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
vi.mock('@/modules/downloads', () => ({ createPlatformExportTask: vi.fn() }))
|
vi.mock('@/modules/downloads', () => ({ createPlatformExportTask: vi.fn() }))
|
||||||
|
vi.mock('@/shared/components/exportTaskCreatedDialog', () => ({ showExportTaskCreatedDialog: vi.fn() }))
|
||||||
|
|
||||||
class ResizeObserverStub implements ResizeObserver {
|
class ResizeObserverStub implements ResizeObserver {
|
||||||
observe() {}
|
observe() {}
|
||||||
@@ -97,7 +106,10 @@ describe('CustomersView', () => {
|
|||||||
vi.mocked(uploadPlatformTenantQualification).mockResolvedValue({
|
vi.mocked(uploadPlatformTenantQualification).mockResolvedValue({
|
||||||
qualificationId: 'qualification-1', reviewId: null, tenantStatus: 'PROFILE_REQUIRED', documentUrl: '/files/license.png',
|
qualificationId: 'qualification-1', reviewId: null, tenantStatus: 'PROFILE_REQUIRED', documentUrl: '/files/license.png',
|
||||||
})
|
})
|
||||||
vi.mocked(createPlatformExportTask).mockResolvedValue({ id: 'export-1', status: 'PENDING' } as never)
|
vi.mocked(createPlatformExportTask).mockResolvedValue({
|
||||||
|
id: 'export-1', taskName: '客户列表', taskNo: 'EXP2084', status: 'PENDING',
|
||||||
|
} as never)
|
||||||
|
vi.mocked(showExportTaskCreatedDialog).mockResolvedValue(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('loads the complete customer detail before editing masked list fields', async () => {
|
it('loads the complete customer detail before editing masked list fields', async () => {
|
||||||
@@ -272,9 +284,27 @@ describe('CustomersView', () => {
|
|||||||
exportType: 'CUSTOMER_LIST', format: 'XLSX', taskName: '客户列表',
|
exportType: 'CUSTOMER_LIST', format: 'XLSX', taskName: '客户列表',
|
||||||
parameters: { keyword: 'Acme', status: 'ACTIVE' },
|
parameters: { keyword: 'Acme', status: 'ACTIVE' },
|
||||||
})
|
})
|
||||||
|
expect(showExportTaskCreatedDialog).toHaveBeenCalledWith({ taskName: '客户列表', taskNo: 'EXP2084' })
|
||||||
expect(listPlatformTenants).toHaveBeenCalledTimes(1)
|
expect(listPlatformTenants).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('opens the download center when the export-created dialog action is confirmed', async () => {
|
||||||
|
vi.mocked(createPlatformExportTask).mockResolvedValue({
|
||||||
|
id: 'export-1', taskName: '客户列表', taskNo: 'EXP2084', status: 'PENDING',
|
||||||
|
} as never)
|
||||||
|
vi.mocked(showExportTaskCreatedDialog).mockResolvedValue(true)
|
||||||
|
mount(CustomersView, { attachTo: document.body, global: { plugins: [pinia, ElementPlus] } })
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
const exportButton = [...document.querySelectorAll<HTMLButtonElement>('button')]
|
||||||
|
.find((button) => button.textContent?.trim() === '导出Excel')
|
||||||
|
exportButton?.click()
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(showExportTaskCreatedDialog).toHaveBeenCalledWith({ taskName: '客户列表', taskNo: 'EXP2084' })
|
||||||
|
expect(routerPush).toHaveBeenCalledWith({ name: 'download-center' })
|
||||||
|
})
|
||||||
|
|
||||||
it('hides customer export when the stable export permission is absent', async () => {
|
it('hides customer export when the stable export permission is absent', async () => {
|
||||||
const auth = useAuthStore()
|
const auth = useAuthStore()
|
||||||
auth.permissions = ['platform:customer:list', 'platform:customer:view']
|
auth.permissions = ['platform:customer:list', 'platform:customer:view']
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'
|
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
import { Building2, CheckCircle2, Download, Eye, FileCheck2, FileText, FileUp, Pencil, Plus, Power, ShieldCheck, ShieldX } from '@lucide/vue'
|
import { Building2, CheckCircle2, Download, Eye, FileCheck2, FileText, FileUp, Pencil, Plus, Power, ShieldCheck, ShieldX } from '@lucide/vue'
|
||||||
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus'
|
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus'
|
||||||
import { getApiErrorDetails, getApiErrorMessage, type ApiErrorDetails } from '@/shared/api/http'
|
import { getApiErrorDetails, getApiErrorMessage, type ApiErrorDetails } from '@/shared/api/http'
|
||||||
@@ -31,6 +32,7 @@ import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'
|
|||||||
import CopyButton from '@/shared/components/CopyButton.vue'
|
import CopyButton from '@/shared/components/CopyButton.vue'
|
||||||
import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.vue'
|
import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.vue'
|
||||||
import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue'
|
import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue'
|
||||||
|
import { showExportTaskCreatedDialog } from '@/shared/components/exportTaskCreatedDialog'
|
||||||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||||||
|
|
||||||
type CustomerFilters = QueryModel & { keyword: string; status: PlatformTenantStatus | '' }
|
type CustomerFilters = QueryModel & { keyword: string; status: PlatformTenantStatus | '' }
|
||||||
@@ -58,6 +60,7 @@ type DetailQualificationPreview = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const access = useAccessPreviewStore()
|
const access = useAccessPreviewStore()
|
||||||
|
const router = useRouter()
|
||||||
const page = ref(1)
|
const page = ref(1)
|
||||||
const pageSize = ref(10)
|
const pageSize = ref(10)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
@@ -650,8 +653,9 @@ function closeApprovalResult() {
|
|||||||
|
|
||||||
async function exportCustomers() {
|
async function exportCustomers() {
|
||||||
exportSubmitting.value = true
|
exportSubmitting.value = true
|
||||||
|
let task: Awaited<ReturnType<typeof createPlatformExportTask>>
|
||||||
try {
|
try {
|
||||||
await createPlatformExportTask({
|
task = await createPlatformExportTask({
|
||||||
exportType: 'CUSTOMER_LIST',
|
exportType: 'CUSTOMER_LIST',
|
||||||
format: 'XLSX',
|
format: 'XLSX',
|
||||||
taskName: '客户列表',
|
taskName: '客户列表',
|
||||||
@@ -660,9 +664,15 @@ async function exportCustomers() {
|
|||||||
status: filters.value.status || undefined,
|
status: filters.value.status || undefined,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
ElMessage.success('导出任务已创建,可前往下载中心查看')
|
} catch (error) {
|
||||||
} catch (error) { ElMessage.error(getApiErrorMessage(error, '客户导出任务创建失败')) }
|
ElMessage.error(getApiErrorMessage(error, '客户导出任务创建失败'))
|
||||||
finally { exportSubmitting.value = false }
|
return
|
||||||
|
} finally {
|
||||||
|
exportSubmitting.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const openDownloadCenter = await showExportTaskCreatedDialog({ taskName: task.taskName, taskNo: task.taskNo })
|
||||||
|
if (openDownloadCenter) await router.push({ name: 'download-center' })
|
||||||
}
|
}
|
||||||
|
|
||||||
watch([page, pageSize], () => { void loadCustomers() })
|
watch([page, pageSize], () => { void loadCustomers() })
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { ElMessageBox } from 'element-plus'
|
||||||
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||||
|
import { showExportTaskCreatedDialog } from './exportTaskCreatedDialog'
|
||||||
|
|
||||||
|
describe('showExportTaskCreatedDialog', () => {
|
||||||
|
beforeEach(() => vi.restoreAllMocks())
|
||||||
|
|
||||||
|
it('offers a direct path to the download center with the task reference', async () => {
|
||||||
|
const confirm = vi.spyOn(ElMessageBox, 'confirm').mockResolvedValue({} as never)
|
||||||
|
|
||||||
|
await expect(showExportTaskCreatedDialog({ taskName: '客户列表', taskNo: 'EXP2084' })).resolves.toBe(true)
|
||||||
|
expect(confirm).toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining('任务编号:EXP2084'),
|
||||||
|
'导出任务已创建',
|
||||||
|
expect.objectContaining({ confirmButtonText: '前往下载中心', cancelButtonText: '留在当前页' }),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('keeps the user on the current page when the dialog is dismissed', async () => {
|
||||||
|
vi.spyOn(ElMessageBox, 'confirm').mockRejectedValue('cancel')
|
||||||
|
|
||||||
|
await expect(showExportTaskCreatedDialog({ taskName: '客户列表' })).resolves.toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { ElMessageBox } from 'element-plus'
|
||||||
|
|
||||||
|
export interface ExportTaskCreatedDialogOptions {
|
||||||
|
taskName: string
|
||||||
|
taskNo?: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function showExportTaskCreatedDialog(options: ExportTaskCreatedDialogOptions) {
|
||||||
|
const taskReference = options.taskNo ? `\n任务编号:${options.taskNo}` : ''
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`${options.taskName}已进入后台生成队列。文件生成后可在下载中心查看并下载。${taskReference}`,
|
||||||
|
'导出任务已创建',
|
||||||
|
{
|
||||||
|
type: 'success',
|
||||||
|
confirmButtonText: '前往下载中心',
|
||||||
|
cancelButtonText: '留在当前页',
|
||||||
|
distinguishCancelAndClose: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user