This commit is contained in:
2026-08-03 14:58:17 +08:00
parent bc44a7942d
commit ee997ae894
17 changed files with 1694 additions and 303 deletions
+115 -1
View File
@@ -2,28 +2,41 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
import { http } from '@/api/http'
import {
assignPlatformInternalUserRoles,
changePlatformManagedUserStatus,
changePlatformInternalUserStatus,
changePlatformTenantStatus,
changePlatformPermissionStatus,
changePlatformRoleStatus,
createPlatformPermission,
createPlatformManagedUser,
createPlatformRole,
createPlatformTenant,
deletePlatformPermission,
deletePlatformRole,
downloadTenantQualification,
listPlatformTenants,
listPlatformTenantOrderCounts,
listTenantQualifications,
listCurrentPlatformPermissionCodes,
listPlatformPermissions,
listPlatformRoles,
listPlatformInternalUsers,
listPlatformManagedUsers,
getPlatformUserOptions,
qualificationFileName,
replacePlatformRolePermissions,
resetPlatformInternalUserPassword,
resetPlatformManagedUserPassword,
submitPlatformTenantReview,
updatePlatformInternalUser,
updatePlatformManagedUser,
updatePlatformPermission,
updatePlatformRole,
updatePlatformTenant,
uploadPlatformTenantQualification,
type PlatformPermissionResource,
type PlatformInternalUser,
type PlatformManagedUser,
type PlatformRoleResource,
} from './platformIam'
@@ -73,6 +86,25 @@ const internalUser: PlatformInternalUser = {
roleIds: [4000001],
}
const managedUser: PlatformManagedUser = {
membershipId: '3000002',
userId: '2000002',
authUserId: '1000002',
username: 'zhangwei',
displayName: '张伟',
phone: '13800138000',
email: 'zhangwei@example.com',
tenantId: '10001',
tenantName: '华远贸易',
memberType: 'EMPLOYEE',
memberNo: 'MEMBER-3000002',
status: 'ACTIVE',
roleIds: ['40001'],
roleNames: ['租户管理员'],
lastLoginAt: '2026-06-01T10:30:00',
protectedAccount: false,
}
describe('platform IAM roles', () => {
beforeEach(() => {
vi.mocked(http.get).mockReset()
@@ -172,6 +204,39 @@ describe('platform IAM roles', () => {
expect(http.put).toHaveBeenNthCalledWith(4, `/platform/v1/iam/internal-users/${internalUser.membershipId}/roles`, { roleIds: [4000001] })
})
it('maintains platform and tenant users through the unified user contract', async () => {
const userOptions = {
tenants: [{ id: '10001', name: '华远贸易', status: 'ACTIVE' }],
roles: [{ id: '40001', tenantId: '10001', name: '租户管理员', status: 'ACTIVE' }],
}
const create = {
username: 'zhangwei', displayName: '张伟', phone: '13800138000', email: 'zhangwei@example.com',
tenantId: '10001', roleIds: ['40001'], password: 'Password1', status: 'ACTIVE' as const,
}
const update = {
displayName: '张伟', phone: '13800138000', email: 'zhangwei@example.com',
tenantId: '10001', roleIds: ['40001'],
}
vi.mocked(http.get).mockResolvedValueOnce({ code: '200', message: 'success', data: [managedUser] })
.mockResolvedValueOnce({ code: '200', message: 'success', data: userOptions })
vi.mocked(http.post).mockResolvedValue({ code: '200', message: 'success', data: managedUser })
vi.mocked(http.put).mockResolvedValue({ code: '200', message: 'success', data: managedUser })
await expect(listPlatformManagedUsers()).resolves.toEqual([managedUser])
await expect(getPlatformUserOptions()).resolves.toEqual(userOptions)
await expect(createPlatformManagedUser(create)).resolves.toEqual(managedUser)
await expect(updatePlatformManagedUser(managedUser.membershipId, update)).resolves.toEqual(managedUser)
await expect(changePlatformManagedUserStatus(managedUser.membershipId, 'DISABLED')).resolves.toEqual(managedUser)
await expect(resetPlatformManagedUserPassword(managedUser.membershipId, 'ChangeMe123')).resolves.toEqual(managedUser)
expect(http.get).toHaveBeenNthCalledWith(1, '/platform/v1/iam/users')
expect(http.get).toHaveBeenNthCalledWith(2, '/platform/v1/iam/users/options')
expect(http.post).toHaveBeenCalledWith('/platform/v1/iam/users', create)
expect(http.put).toHaveBeenNthCalledWith(1, `/platform/v1/iam/users/${managedUser.membershipId}`, update)
expect(http.put).toHaveBeenNthCalledWith(2, `/platform/v1/iam/users/${managedUser.membershipId}/status`, { status: 'DISABLED' })
expect(http.put).toHaveBeenNthCalledWith(3, `/platform/v1/iam/users/${managedUser.membershipId}/password`, { newPassword: 'ChangeMe123' })
})
it('loads the current users permission snapshot without calling the role-management endpoint', async () => {
vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: ['platform:warehouse:list'] })
@@ -197,7 +262,7 @@ describe('platform IAM roles', () => {
it('loads paginated tenants with the documented filters', async () => {
const page = { records: [], page: 2, size: 10, total: 11, pages: 2 }
vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: page })
vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: { ...page, page: '2', size: '10', total: '11', pages: '2' } })
await expect(listPlatformTenants({ page: 2, size: 10, keyword: '柏悦', status: 'ACTIVE' })).resolves.toEqual(page)
expect(http.get).toHaveBeenCalledWith('/platform/v1/iam/tenants', {
@@ -205,6 +270,55 @@ describe('platform IAM roles', () => {
})
})
it('creates, updates, and changes customer status with the platform tenant contract', async () => {
const tenant = { id: '8', tenantCode: 'TEN8', tenantName: '柏悦物流', status: 'ACTIVE' }
const create = {
tenantName: '柏悦物流', legalName: '柏悦物流有限公司', unifiedSocialCreditCode: '91440300MA5ABCDE12',
contactName: '张三', contactPhone: '13800138000', contactEmail: 'ops@example.com', servicePackage: '标准版',
contactWechat: 'baiyue-ops', salesOwnerName: '李四', paymentTermDays: 30, enterpriseType: '有限责任公司',
establishedDate: '2020-01-01', registeredCapital: 1000, registeredCapitalCurrency: 'CNY',
registeredAddress: '深圳市宝安区', internalRemark: '重点客户',
}
vi.mocked(http.post).mockResolvedValue({ code: '200', message: 'success', data: tenant })
vi.mocked(http.put).mockResolvedValue({ code: '200', message: 'success', data: tenant })
await expect(createPlatformTenant(create)).resolves.toEqual(tenant)
const { unifiedSocialCreditCode: _creditCode, ...update } = create
await expect(updatePlatformTenant('8', update)).resolves.toEqual(tenant)
await expect(changePlatformTenantStatus('8', 'DISABLED')).resolves.toEqual(tenant)
expect(http.post).toHaveBeenCalledWith('/platform/v1/iam/tenants', create)
expect(http.put).toHaveBeenNthCalledWith(1, '/platform/v1/iam/tenants/8', update)
expect(http.put).toHaveBeenNthCalledWith(2, '/platform/v1/iam/tenants/8/status', { status: 'DISABLED' })
})
it('loads real order totals for the visible customer tenants', async () => {
const counts = [{ tenantId: '8', orderCount: 12 }, { tenantId: '9', orderCount: 0 }]
vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: counts })
await expect(listPlatformTenantOrderCounts(['8', '9'])).resolves.toEqual(counts)
expect(http.get).toHaveBeenCalledWith('/platform/v1/orders/first-leg/tenant-counts?tenantIds=8,9')
})
it('uploads qualification metadata before explicitly submitting the customer review', async () => {
const uploadResult = { qualificationId: '91', reviewId: null, tenantStatus: 'PROFILE_REQUIRED', documentUrl: '/file.pdf' }
const tenant = { id: '8', tenantCode: 'TEN8', tenantName: '柏悦物流', status: 'PENDING' }
vi.mocked(http.post).mockResolvedValueOnce({ code: '200', message: 'success', data: uploadResult })
.mockResolvedValueOnce({ code: '200', message: 'success', data: tenant })
const file = new File(['%PDF-1.4'], '营业执照.pdf', { type: 'application/pdf' })
await expect(uploadPlatformTenantQualification('8', 'BUSINESS_LICENSE', file, '2030-12-31', '91440300MA5ABCDE12', true)).resolves.toEqual(uploadResult)
await expect(submitPlatformTenantReview('8')).resolves.toEqual(tenant)
const form = vi.mocked(http.post).mock.calls[0]?.[1] as FormData
expect(http.post).toHaveBeenNthCalledWith(1, '/platform/v1/files/qualifications/8', expect.any(FormData))
expect(form.get('file')).toBe(file)
expect(form.get('qualificationType')).toBe('BUSINESS_LICENSE')
expect(form.get('validTo')).toBe('2030-12-31')
expect(form.get('certificateNo')).toBe('91440300MA5ABCDE12')
expect(form.get('replace')).toBe('true')
expect(http.post).toHaveBeenNthCalledWith(2, '/platform/v1/iam/tenants/8/submit-review', {})
})
it('downloads a qualification with the platform file endpoint and a safe filename', async () => {
const blob = new Blob(['image'], { type: 'image/png' })
vi.mocked(http.get).mockResolvedValue(blob)