优化
This commit is contained in:
@@ -113,6 +113,7 @@ function statusMeta(status: PlatformTenantStatus) {
|
||||
if (status === 'PROFILE_REQUIRED') return { label: '待完善', type: 'info' as const }
|
||||
if (status === 'PENDING') return { label: '待审核', type: 'warning' as const }
|
||||
if (status === 'REJECTED') return { label: '已驳回', type: 'danger' as const }
|
||||
if (status === 'ARCHIVED') return { label: '已归档', type: 'info' as const }
|
||||
return { label: '已停用', type: 'info' as const }
|
||||
}
|
||||
function qualificationLabel(type: string) {
|
||||
@@ -373,7 +374,7 @@ watch(orderPage, (page, previousPage) => {
|
||||
<template #actions>
|
||||
<div v-if="customer" class="header-actions">
|
||||
<el-tag :type="statusMeta(customer.status).type" effect="light" round>{{ statusMeta(customer.status).label }}</el-tag>
|
||||
<el-button v-if="access.can('platform:customer:edit')" @click="goEdit"><Pencil :size="16" />编辑信息</el-button>
|
||||
<el-button v-if="access.can('platform:customer:edit') && customer.status !== 'ARCHIVED'" @click="goEdit"><Pencil :size="16" />编辑信息</el-button>
|
||||
<el-button v-if="access.can('platform:customer:status') && ['ACTIVE', 'DISABLED'].includes(customer.status)" :type="customer.status === 'ACTIVE' ? 'danger' : 'success'" :loading="statusChanging" @click="changeStatus"><Power :size="16" />{{ customer.status === 'ACTIVE' ? '停用账号' : '启用账号' }}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -529,7 +529,7 @@ describe('CustomersView', () => {
|
||||
const auth = useAuthStore()
|
||||
auth.permissions = [...auth.permissions, 'platform:customer:delete']
|
||||
useAccessPreviewStore().initializeAfterLogin()
|
||||
vi.mocked(archivePlatformTenant).mockResolvedValue({ ...fullTenant, status: 'DISABLED' })
|
||||
vi.mocked(archivePlatformTenant).mockResolvedValue({ ...fullTenant, status: 'ARCHIVED' })
|
||||
|
||||
mount(CustomersView, { attachTo: document.body, global: { plugins: [pinia, ElementPlus] } })
|
||||
await flushPromises()
|
||||
@@ -578,6 +578,24 @@ describe('CustomersView', () => {
|
||||
expect(document.body.textContent).toContain('代登录原因')
|
||||
})
|
||||
|
||||
it('treats archived customers as read-only and terminal', async () => {
|
||||
const auth = useAuthStore()
|
||||
auth.permissions = [...auth.permissions, 'platform:customer:edit', 'platform:customer:status', 'platform:customer:delete']
|
||||
useAccessPreviewStore().initializeAfterLogin()
|
||||
vi.mocked(listPlatformTenants).mockResolvedValue({
|
||||
records: [{ ...fullTenant, status: 'ARCHIVED' }], page: 1, size: 10, total: 1, pages: 1,
|
||||
})
|
||||
|
||||
mount(CustomersView, { attachTo: document.body, global: { plugins: [pinia, ElementPlus] } })
|
||||
await flushPromises()
|
||||
|
||||
expect(document.body.textContent).toContain('已归档')
|
||||
expect(tableButtonByText('编辑')).toBeUndefined()
|
||||
expect(tableButtonByText('启用')).toBeUndefined()
|
||||
expect(tableButtonByText('停用')).toBeUndefined()
|
||||
expect(tableButtonByText('删除')).toBeUndefined()
|
||||
})
|
||||
|
||||
it('renders all permitted actions directly for multiple customers', async () => {
|
||||
const auth = useAuthStore()
|
||||
auth.permissions = [...auth.permissions, 'platform:customer:reset-password', 'platform:customer:impersonate', 'platform:customer:status', 'platform:customer:delete']
|
||||
|
||||
@@ -131,7 +131,7 @@ const queryFields: QueryField[] = [
|
||||
{ key: 'status', type: 'select', label: '状态', placeholder: '全部状态', options: [
|
||||
{ label: '待完善', value: 'PROFILE_REQUIRED' }, { label: '待审核', value: 'PENDING' },
|
||||
{ label: '启用', value: 'ACTIVE' }, { label: '已驳回', value: 'REJECTED' },
|
||||
{ label: '已停用', value: 'DISABLED' },
|
||||
{ label: '已停用', value: 'DISABLED' }, { label: '已归档', value: 'ARCHIVED' },
|
||||
] },
|
||||
]
|
||||
|
||||
@@ -271,6 +271,7 @@ function statusMeta(status: PlatformTenantStatus) {
|
||||
if (status === 'PROFILE_REQUIRED') return { label: '待完善', type: 'info' as const }
|
||||
if (status === 'PENDING') return { label: '待审核', type: 'warning' as const }
|
||||
if (status === 'REJECTED') return { label: '已驳回', type: 'danger' as const }
|
||||
if (status === 'ARCHIVED') return { label: '已归档', type: 'info' as const }
|
||||
return { label: '已停用', type: 'info' as const }
|
||||
}
|
||||
|
||||
@@ -644,8 +645,8 @@ function canImpersonate(row: PlatformTenantResource) {
|
||||
function canChangeStatus(row: PlatformTenantResource) {
|
||||
return access.can('platform:customer:status') && ['ACTIVE', 'DISABLED'].includes(row.status)
|
||||
}
|
||||
function canArchive() {
|
||||
return access.can('platform:customer:delete')
|
||||
function canArchive(row: PlatformTenantResource) {
|
||||
return access.can('platform:customer:delete') && ['PROFILE_REQUIRED', 'REJECTED'].includes(row.status)
|
||||
}
|
||||
type CustomerRowAction = 'reset-password' | 'impersonate' | 'status' | 'delete'
|
||||
const customerRowActionIcons: Record<CustomerRowAction, Component> = {
|
||||
@@ -664,7 +665,7 @@ function customerSecondaryActions(row: PlatformTenantResource): CustomerRowActio
|
||||
...(canResetPassword(row) ? ['reset-password' as const] : []),
|
||||
...(canImpersonate(row) ? ['impersonate' as const] : []),
|
||||
...(canChangeStatus(row) ? ['status' as const] : []),
|
||||
...(canArchive() ? ['delete' as const] : []),
|
||||
...(canArchive(row) ? ['delete' as const] : []),
|
||||
]
|
||||
}
|
||||
function customerActionLabel(row: PlatformTenantResource, action: CustomerRowAction) {
|
||||
@@ -819,7 +820,7 @@ async function submitArchive() {
|
||||
archiveError.value = null
|
||||
try {
|
||||
await archivePlatformTenant(archiveTenant.value.id)
|
||||
ElMessage.success('客户已删除,历史数据已保留且账号已停用')
|
||||
ElMessage.success('客户已归档,历史数据已保留且账号已停用')
|
||||
archiveDialogOpen.value = false
|
||||
archiveTenant.value = null
|
||||
archiveConfirmCode.value = ''
|
||||
@@ -1016,7 +1017,7 @@ onMounted(() => { void loadCustomers() })
|
||||
<template #actions="{ row }">
|
||||
<div class="table-actions">
|
||||
<el-button v-if="access.can('platform:customer:list')" class="customer-action-button customer-action-detail" size="small" @click="showDetail(row as PlatformTenantResource)"><Eye :size="14" />详情</el-button>
|
||||
<el-button v-if="access.can('platform:customer:edit')" class="customer-action-button customer-action-edit" size="small" @click="openEdit(row as PlatformTenantResource)"><Pencil :size="14" />编辑</el-button>
|
||||
<el-button v-if="access.can('platform:customer:edit') && (row as PlatformTenantResource).status !== 'ARCHIVED'" class="customer-action-button customer-action-edit" size="small" @click="openEdit(row as PlatformTenantResource)"><Pencil :size="14" />编辑</el-button>
|
||||
<el-button v-if="hasReviewAction(row as PlatformTenantResource)" class="customer-action-button customer-action-review" size="small" :disabled="reviewSubmitting" @click="openDecision(row as PlatformTenantResource, access.can('platform:customer:approve') ? 'approve' : 'reject')"><ShieldCheck :size="14" />审核</el-button>
|
||||
<el-button v-for="action in customerSecondaryActions(row as PlatformTenantResource)" :key="action" :class="[`customer-action-button`, `customer-action-${action}`, { 'is-enable': action === 'status' && (row as PlatformTenantResource).status !== 'ACTIVE', 'is-disable': action === 'status' && (row as PlatformTenantResource).status === 'ACTIVE' }]" size="small" :disabled="customerActionDisabled(action)" @click="handleMoreAction(row as PlatformTenantResource, action)"><component :is="customerRowActionIcons[action]" :size="14" />{{ customerActionLabel(row as PlatformTenantResource, action) }}</el-button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user