优化
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import ElementPlus from 'element-plus'
|
||||
import { flushPromises, mount } from '@vue/test-utils'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { listPlatformTenants, type PlatformTenantResource } from '../api/platformIam'
|
||||
import PlatformTenantSelector from './PlatformTenantSelector.vue'
|
||||
|
||||
vi.mock('../api/platformIam', () => ({ listPlatformTenants: vi.fn() }))
|
||||
|
||||
const customer = {
|
||||
id: '190000000000000008',
|
||||
tenantCode: 'CUS-008',
|
||||
tenantName: '柏悦物流',
|
||||
status: 'ACTIVE',
|
||||
} as PlatformTenantResource
|
||||
|
||||
function mountSelector(props: { modelValue?: string; label?: string } = {}) {
|
||||
return mount(PlatformTenantSelector, {
|
||||
props: { modelValue: props.modelValue ?? '', ...(props.label ? { label: props.label } : {}) },
|
||||
global: { plugins: [ElementPlus] },
|
||||
})
|
||||
}
|
||||
|
||||
describe('PlatformTenantSelector customer labels', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
vi.mocked(listPlatformTenants).mockResolvedValue({ records: [customer], page: 1, size: 200, total: 1, pages: 1 })
|
||||
})
|
||||
|
||||
it('shows business identity and status without exposing the internal id', async () => {
|
||||
const wrapper = mountSelector({ modelValue: String(customer.id) })
|
||||
await flushPromises()
|
||||
|
||||
expect(listPlatformTenants).toHaveBeenCalledWith({ page: 1, size: 200 })
|
||||
expect(wrapper.text()).toContain('目标客户')
|
||||
expect(document.body.textContent).toContain('柏悦物流(CUS-008) · 启用')
|
||||
expect(document.body.textContent).not.toContain(String(customer.id))
|
||||
})
|
||||
|
||||
it('keeps the internal id only as the emitted contract value', async () => {
|
||||
const wrapper = mountSelector()
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.emitted('update:modelValue')).toEqual([[String(customer.id)]])
|
||||
expect(wrapper.text()).not.toContain(String(customer.id))
|
||||
})
|
||||
|
||||
it('safely degrades labels when customer name or code is missing', async () => {
|
||||
vi.mocked(listPlatformTenants).mockResolvedValue({
|
||||
records: [
|
||||
{ ...customer, id: '1', tenantName: '', tenantCode: 'CUS-001', status: 'PENDING' },
|
||||
{ ...customer, id: '2', tenantName: '远航供应链', tenantCode: '', status: 'REJECTED' },
|
||||
{ ...customer, id: '3', tenantName: '', tenantCode: '', status: 'UNKNOWN' },
|
||||
],
|
||||
page: 1, size: 200, total: 3, pages: 1,
|
||||
})
|
||||
mountSelector({ modelValue: '1' })
|
||||
await flushPromises()
|
||||
|
||||
expect(document.body.textContent).toContain('CUS-001 · 待审核')
|
||||
expect(document.body.textContent).toContain('远航供应链 · 已驳回')
|
||||
expect(document.body.textContent).toContain('未命名客户 · UNKNOWN')
|
||||
expect(document.body.textContent).not.toMatch(/[((][123] ·/)
|
||||
})
|
||||
|
||||
it('uses a custom business label for both visible and accessible names', async () => {
|
||||
const wrapper = mountSelector({ modelValue: String(customer.id), label: '客户企业' })
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.text()).toContain('客户企业')
|
||||
expect(wrapper.get('[aria-label="客户企业"]').attributes('aria-label')).toBe('客户企业')
|
||||
})
|
||||
|
||||
it('shows an actionable customer-list error and retries', async () => {
|
||||
vi.mocked(listPlatformTenants)
|
||||
.mockRejectedValueOnce('unavailable')
|
||||
.mockResolvedValueOnce({ records: [customer], page: 1, size: 200, total: 1, pages: 1 })
|
||||
const wrapper = mountSelector()
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.get('[role="alert"]').text()).toContain('客户列表加载失败,请重试')
|
||||
await wrapper.get('[role="alert"] button').trigger('click')
|
||||
await flushPromises()
|
||||
expect(listPlatformTenants).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
})
|
||||
@@ -9,7 +9,7 @@ const props = withDefaults(defineProps<{
|
||||
label?: string
|
||||
}>(), {
|
||||
disabled: false,
|
||||
label: '目标企业',
|
||||
label: '目标客户',
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -36,7 +36,10 @@ const statusLabels: Record<string, string> = {
|
||||
|
||||
function tenantLabel(tenant: PlatformTenantResource) {
|
||||
const status = statusLabels[tenant.status] || tenant.status
|
||||
return `${tenant.tenantName}(${tenant.id} · ${status})`
|
||||
const name = tenant.tenantName?.trim()
|
||||
const code = tenant.tenantCode?.trim()
|
||||
const identity = name && code ? `${name}(${code})` : name || code || '未命名客户'
|
||||
return status ? `${identity} · ${status}` : identity
|
||||
}
|
||||
|
||||
async function loadTenants() {
|
||||
@@ -50,7 +53,7 @@ async function loadTenants() {
|
||||
emit('update:modelValue', String(preferred.id))
|
||||
}
|
||||
} catch (reason) {
|
||||
error.value = reason instanceof Error ? reason.message : '企业列表加载失败,请重试'
|
||||
error.value = reason instanceof Error ? reason.message : '客户列表加载失败,请重试'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -67,8 +70,8 @@ onMounted(() => void loadTenants())
|
||||
class="platform-tenant-selector-input"
|
||||
filterable
|
||||
:disabled="disabled || loading || tenants.length === 0"
|
||||
:placeholder="loading ? '正在加载企业' : '请选择目标企业'"
|
||||
aria-label="目标企业"
|
||||
:placeholder="loading ? '正在加载客户' : '请选择目标客户'"
|
||||
:aria-label="label"
|
||||
>
|
||||
<el-option v-for="tenant in tenants" :key="String(tenant.id)" :label="tenantLabel(tenant)" :value="String(tenant.id)" />
|
||||
</el-select>
|
||||
|
||||
@@ -181,8 +181,8 @@ describe('PermissionsView IAM mode', () => {
|
||||
const wrapper = mountServerView(allActionPermissions)
|
||||
await flushPromises()
|
||||
|
||||
const moreButton = wrapper.get('[data-row-id="5100010"] [aria-label="5100010的更多操作"]')
|
||||
expect(moreButton.attributes('title')).toBe('5100010的更多操作')
|
||||
const moreButton = wrapper.get('[data-row-id="5100010"] [aria-label="当前权限的更多操作"]')
|
||||
expect(moreButton.attributes('title')).toBe('当前权限的更多操作')
|
||||
expect(moreButton.attributes('aria-label')).not.toMatch(/undefined|null/)
|
||||
})
|
||||
|
||||
|
||||
@@ -87,10 +87,10 @@ const parentOptions = computed(() => permissions.value.filter((item) => (
|
||||
const permissionColumns: DataTableColumn[] = [
|
||||
{ key: 'actions', label: '操作', width: 280, fixed: 'left', slotName: 'actions' },
|
||||
{ key: 'name', label: '权限名称', minWidth: 260, slotName: 'name' },
|
||||
{ key: 'code', label: '权限编码', minWidth: 220, slotName: 'code' },
|
||||
{ key: 'code', label: '权限编码', minWidth: 220, slotName: 'code', defaultVisible: false },
|
||||
{ key: 'type', prop: 'type', label: '类型', width: 80 },
|
||||
{ key: 'endpoint', label: '路由 / 接口', minWidth: 260, slotName: 'endpoint' },
|
||||
{ key: 'sort', prop: 'sort', label: '排序', width: 72, align: 'right' },
|
||||
{ key: 'endpoint', label: '路由 / 接口', minWidth: 260, slotName: 'endpoint', defaultVisible: false },
|
||||
{ key: 'sort', prop: 'sort', label: '排序', width: 72, align: 'right', defaultVisible: false },
|
||||
{ key: 'status', label: '状态', width: 88, slotName: 'status' },
|
||||
]
|
||||
|
||||
@@ -256,7 +256,7 @@ function showDeleteMore(row: Permission) {
|
||||
return canDeleteRow(row) && permissionActionCount(row) > 3
|
||||
}
|
||||
function moreActionsLabel(row: Permission) {
|
||||
const resourceLabel = [row.name, row.code, row.id]
|
||||
const resourceLabel = [row.name]
|
||||
.find((value) => typeof value === 'string' && value.trim())
|
||||
?.trim() || '当前权限'
|
||||
return `${resourceLabel}的更多操作`
|
||||
|
||||
Reference in New Issue
Block a user