From 8307510fc399e3cdbac51ace8d9d881396c6208d Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Wed, 26 Aug 2026 11:42:46 +0800 Subject: [PATCH] fix(admin): load picker warehouses from domestic master --- src/modules/iam/api/platformIam.test.ts | 44 +++++++----- src/modules/iam/api/platformIam.ts | 39 +++++++++-- .../iam/pages/InternalUsersView.test.ts | 68 +++++++++++++++++++ 3 files changed, 127 insertions(+), 24 deletions(-) diff --git a/src/modules/iam/api/platformIam.test.ts b/src/modules/iam/api/platformIam.test.ts index df42ce2f..ecaa74c0 100644 --- a/src/modules/iam/api/platformIam.test.ts +++ b/src/modules/iam/api/platformIam.test.ts @@ -1,6 +1,5 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import { http } from '@/shared/api/http' -import { overseasHttp } from '@/shared/api/overseasHttp' import { approveEnterpriseReview, archivePlatformTenant, @@ -51,10 +50,6 @@ vi.mock('@/shared/api/http', () => ({ unwrapApiResponse: (response: { data: T }) => response.data, })) -vi.mock('@/shared/api/overseasHttp', () => ({ - overseasHttp: { get: vi.fn() }, -})) - const role: PlatformRoleResource = { id: 4000002, tenantId: 0, @@ -123,7 +118,6 @@ describe('platform IAM roles', () => { vi.mocked(http.post).mockReset() vi.mocked(http.put).mockReset() vi.mocked(http.delete).mockReset() - vi.mocked(overseasHttp.get).mockReset() }) it('loads roles from the platform IAM prefix', async () => { @@ -218,9 +212,13 @@ describe('platform IAM roles', () => { }) it('maintains paginated platform users through the unified user contract', async () => { - const userOptions = { + const userOptionsPayload = { tenants: [{ id: '0', name: '平台', status: 'ACTIVE' }], - roles: [{ id: '40001', tenantId: '0', roleCode: 'PLATFORM_OPERATOR', name: '运营管理员', status: 'ACTIVE' }], + roles: [{ id: '40001', tenantId: '0', name: '运营管理员', status: 'ACTIVE' }], + } + const userOptions = { + ...userOptionsPayload, + roles: [{ ...userOptionsPayload.roles[0], roleCode: 'PLATFORM_OPERATOR' }], } const create = { username: 'zhangwei', displayName: '张伟', phone: '13800138000', email: 'zhangwei@example.com', @@ -234,7 +232,11 @@ describe('platform IAM roles', () => { vi.mocked(http.get).mockResolvedValueOnce({ code: '200', message: 'success', data: { ...userPage, page: '2', size: '10', total: '11', pages: '2' }, }) - .mockResolvedValueOnce({ code: '200', message: 'success', data: userOptions }) + .mockResolvedValueOnce({ code: '200', message: 'success', data: userOptionsPayload }) + .mockResolvedValueOnce({ + code: '200', message: 'success', + data: [{ ...role, id: '40001', roleCode: 'PLATFORM_OPERATOR' }], + }) vi.mocked(http.post).mockResolvedValue({ code: '200', message: 'success', data: managedUser }) vi.mocked(http.put).mockResolvedValue({ code: '200', message: 'success', data: managedUser }) @@ -249,28 +251,36 @@ describe('platform IAM roles', () => { params: { page: 2, size: 10, keyword: '张伟', status: 'ACTIVE' }, }) expect(http.get).toHaveBeenNthCalledWith(2, '/platform/v1/iam/users/options') + expect(http.get).toHaveBeenNthCalledWith(3, '/platform/v1/iam/roles') 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 only active shared receiving overseas warehouses through the overseas gateway', async () => { - vi.mocked(overseasHttp.get).mockResolvedValue({ + it('loads only active shared receiving overseas warehouses from domestic warehouse master data', async () => { + vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: { records: [ - { id: '90071992547409931', customerId: '0', warehouseCode: 'LAX-01', warehouseName: '洛杉矶收货仓', warehouseType: 'OVERSEAS', countryCode: 'US', status: 'ACTIVE' }, - { id: '2', customerId: '100', warehouseCode: 'CUST', warehouseName: '客户仓', warehouseType: 'OVERSEAS', countryCode: 'US', status: 'ACTIVE' }, - { id: '3', customerId: '0', warehouseCode: 'PARTNER', warehouseName: '合作仓', warehouseType: 'OVERSEAS_PARTNER', countryCode: 'US', status: 'ACTIVE' }, - ], page: 1, size: 200, total: 3, pages: 1, + { id: '90071992547409931', tenantId: '0', warehouseCode: 'LAX-01', warehouseName: '洛杉矶收货仓', warehouseType: 'OVERSEAS', countryCode: 'US', status: 'ACTIVE' }, + { id: '90071992547409932', tenantId: '0', warehouseCode: 'NYC-01', warehouseName: '纽约收货仓', warehouseType: 'OVERSEAS', countryCode: 'US', status: 'ACTIVE' }, + { id: '2', tenantId: '100', warehouseCode: 'CUST', warehouseName: '客户仓', warehouseType: 'OVERSEAS', countryCode: 'US', status: 'ACTIVE' }, + { id: '3', tenantId: '0', warehouseCode: 'PARTNER', warehouseName: '合作仓', warehouseType: 'OVERSEAS_PARTNER', countryCode: 'US', status: 'ACTIVE' }, + { id: '4', tenantId: '0', warehouseCode: 'ONT8', warehouseName: 'ONT8', warehouseType: 'FBA', countryCode: 'US', status: 'ACTIVE' }, + { id: '5', tenantId: '0', warehouseCode: 'SEA-INACTIVE', warehouseName: '西雅图停用仓', warehouseType: 'OVERSEAS', countryCode: 'US', status: 'INACTIVE' }, + ], page: 1, size: 200, total: 6, pages: 1, }, }) await expect(listSharedReceivingOverseasWarehouseOptions()).resolves.toEqual([ { id: '90071992547409931', warehouseCode: 'LAX-01', warehouseName: '洛杉矶收货仓', countryCode: 'US' }, + { id: '90071992547409932', warehouseCode: 'NYC-01', warehouseName: '纽约收货仓', countryCode: 'US' }, ]) - expect(overseasHttp.get).toHaveBeenCalledWith('/platform/v1/warehouse-admin', { - params: { customerId: '0', page: 1, size: 200, capabilityCode: 'RECEIVING', status: 'ACTIVE' }, + expect(http.get).toHaveBeenCalledWith('/platform/v1/warehouse-admin', { + params: { + tenantId: '0', page: 1, size: 200, capabilityCode: 'RECEIVING', + warehouseType: 'OVERSEAS', status: 'ACTIVE', + }, }) }) diff --git a/src/modules/iam/api/platformIam.ts b/src/modules/iam/api/platformIam.ts index adb523ad..9689de43 100644 --- a/src/modules/iam/api/platformIam.ts +++ b/src/modules/iam/api/platformIam.ts @@ -1,5 +1,4 @@ import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http' -import { overseasHttp } from '@/shared/api/overseasHttp' import type { PlatformPermissionResource } from '@/shared/types/platformPermission' export type { PlatformPermissionResource } from '@/shared/types/platformPermission' @@ -277,6 +276,11 @@ export interface PlatformUserOptions { roles: Array<{ id: number | string; tenantId: number | string; roleCode: string; name: string; status: string }> } +interface PlatformUserOptionsPayload { + tenants: PlatformUserOptions['tenants'] + roles: Array> +} + export interface SharedReceivingOverseasWarehouseOption { id: string warehouseCode: string @@ -565,15 +569,27 @@ export async function listPlatformManagedUsers(query: PlatformManagedUserQuery) } } -export function getPlatformUserOptions() { - return getData('/platform/v1/iam/users/options') +export async function getPlatformUserOptions(): Promise { + const [optionsResponse, rolesResponse] = await Promise.all([ + http.get, ApiEnvelope>('/platform/v1/iam/users/options'), + http.get, ApiEnvelope>('/platform/v1/iam/roles'), + ]) + const options = unwrapApiResponse(optionsResponse) + const roleCodes = new Map(unwrapApiResponse(rolesResponse).map((role) => [String(role.id), role.roleCode])) + return { + tenants: options.tenants, + roles: options.roles.map((role) => ({ + ...role, + roleCode: roleCodes.get(String(role.id)) ?? '', + })), + } } export async function listSharedReceivingOverseasWarehouseOptions() { interface WarehousePage { records: Array<{ id: number | string - customerId: number | string + tenantId: number | string warehouseCode: string warehouseName: string warehouseType: string @@ -581,12 +597,21 @@ export async function listSharedReceivingOverseasWarehouseOptions() { status: string }> } - const response = await overseasHttp.get, ApiEnvelope>( + const response = await http.get, ApiEnvelope>( '/platform/v1/warehouse-admin', - { params: { customerId: '0', page: 1, size: 200, capabilityCode: 'RECEIVING', status: 'ACTIVE' } }, + { + params: { + tenantId: '0', + page: 1, + size: 200, + capabilityCode: 'RECEIVING', + warehouseType: 'OVERSEAS', + status: 'ACTIVE', + }, + }, ) return unwrapApiResponse(response).records - .filter((warehouse) => String(warehouse.customerId) === '0' + .filter((warehouse) => String(warehouse.tenantId) === '0' && warehouse.warehouseType === 'OVERSEAS' && warehouse.status === 'ACTIVE') .map((warehouse) => ({ diff --git a/src/modules/iam/pages/InternalUsersView.test.ts b/src/modules/iam/pages/InternalUsersView.test.ts index c2f027ba..a7498766 100644 --- a/src/modules/iam/pages/InternalUsersView.test.ts +++ b/src/modules/iam/pages/InternalUsersView.test.ts @@ -220,6 +220,74 @@ describe('InternalUsersView platform internal user management', () => { }) }) + it('clears a warehouse binding after switching away from WAREHOUSE_PICKER', async () => { + vi.mocked(getPlatformUserOptions).mockResolvedValueOnce({ + tenants: [{ id: '0', name: '平台', status: 'ACTIVE' }], + roles: [ + { id: '40', tenantId: '0', roleCode: 'PLATFORM_OPERATOR', name: '运营管理员', status: 'ACTIVE' }, + { id: '4000005', tenantId: '0', roleCode: 'WAREHOUSE_PICKER', name: '仓库拣货员', status: 'ACTIVE' }, + ], + }) + const wrapper = await mountView() + const setupState = (wrapper.vm.$ as unknown as { + setupState: { + openCreate: () => void + form: { roleIds: string[]; overseasWarehouseId: string } + } + }).setupState + setupState.openCreate() + setupState.form.roleIds = ['4000005'] + await flushPromises() + setupState.form.overseasWarehouseId = '90071992547409931' + + setupState.form.roleIds = ['40'] + await flushPromises() + + expect(setupState.form.overseasWarehouseId).toBe('') + expect(document.body.textContent).not.toContain('实际海外收货仓') + }) + + it('submits the selected picker warehouse as an unchanged long-id string', async () => { + vi.mocked(getPlatformUserOptions).mockResolvedValueOnce({ + tenants: [{ id: '0', name: '平台', status: 'ACTIVE' }], + roles: [{ id: '4000005', tenantId: '0', roleCode: 'WAREHOUSE_PICKER', name: '仓库拣货员', status: 'ACTIVE' }], + }) + const wrapper = await mountView() + const setupState = (wrapper.vm.$ as unknown as { + setupState: { + openCreate: () => void + saveUser: () => Promise + form: Record + } + }).setupState + setupState.openCreate() + Object.assign(setupState.form, { + username: 'overseas_picker_dev', + displayName: '海外仓操作员', + phone: '17512095155', + email: 'overseas_picker_dev@qq.com', + roleIds: ['4000005'], + overseasWarehouseId: '90071992547409931', + password: 'ChangeMe123!', + confirmPassword: 'ChangeMe123!', + status: 'ACTIVE', + }) + await flushPromises() + await setupState.saveUser() + + expect(createPlatformManagedUser).toHaveBeenCalledWith({ + username: 'overseas_picker_dev', + displayName: '海外仓操作员', + phone: '17512095155', + email: 'overseas_picker_dev@qq.com', + tenantId: '0', + roleIds: ['4000005'], + overseasWarehouseId: '90071992547409931', + password: 'ChangeMe123!', + status: 'ACTIVE', + }) + }) + it('requests server-side pages and filters instead of slicing locally', async () => { const wrapper = await mountView() await wrapper.find('button[aria-label="第 2 页"]').trigger('click')