优化
This commit is contained in:
@@ -0,0 +1,310 @@
|
||||
import ElementPlus from 'element-plus'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { enableAutoUnmount, flushPromises, mount, type VueWrapper } from '@vue/test-utils'
|
||||
import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||||
import { useAuthStore } from '@/core/auth/auth'
|
||||
import {
|
||||
getPlatformLocation,
|
||||
listPlatformLocations,
|
||||
type PlatformLocationResource,
|
||||
} from '../api/platformLocations'
|
||||
import { listPlatformTenants, type PlatformTenantResource } from '../../../iam/api/platformIam'
|
||||
import { listPlatformWarehouses, type PlatformWarehouseResource } from '../../../warehouses/api/platformWarehouses'
|
||||
import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue'
|
||||
import DataTable from '@/shared/components/DataTable.vue'
|
||||
import LocationsView from './LocationsView.vue'
|
||||
|
||||
vi.mock('../../../iam/api/platformIam', () => ({ listPlatformTenants: vi.fn() }))
|
||||
vi.mock('../../../warehouses/api/platformWarehouses', () => ({ listPlatformWarehouses: vi.fn() }))
|
||||
vi.mock('../api/platformLocations', () => ({
|
||||
listPlatformLocations: vi.fn(),
|
||||
getPlatformLocation: vi.fn(),
|
||||
createPlatformLocation: vi.fn(),
|
||||
updatePlatformLocation: vi.fn(),
|
||||
changePlatformLocationStatus: vi.fn(),
|
||||
deletePlatformLocation: vi.fn(),
|
||||
}))
|
||||
|
||||
class ResizeObserverStub implements ResizeObserver {
|
||||
observe() {}
|
||||
unobserve() {}
|
||||
disconnect() {}
|
||||
}
|
||||
|
||||
function createMemoryStorage(): Storage {
|
||||
const values = new Map<string, string>()
|
||||
return {
|
||||
get length() { return values.size },
|
||||
clear: () => values.clear(),
|
||||
getItem: (key) => values.get(key) ?? null,
|
||||
key: (index) => [...values.keys()][index] ?? null,
|
||||
removeItem: (key) => values.delete(key),
|
||||
setItem: (key, value) => values.set(key, value),
|
||||
}
|
||||
}
|
||||
|
||||
const tenant = (id: number | string): PlatformTenantResource => ({
|
||||
id,
|
||||
tenantCode: String(id),
|
||||
tenantName: '雪花企业',
|
||||
status: 'ACTIVE',
|
||||
legalName: '雪花企业',
|
||||
legalRepresentative: null,
|
||||
unifiedSocialCreditCode: null,
|
||||
contactName: null,
|
||||
contactPhone: null,
|
||||
contactEmail: null,
|
||||
servicePackage: null,
|
||||
contactWechat: null,
|
||||
salesOwnerName: null,
|
||||
paymentTermDays: null,
|
||||
enterpriseType: null,
|
||||
establishedDate: null,
|
||||
registeredCapital: null,
|
||||
registeredCapitalCurrency: null,
|
||||
registeredAddress: null,
|
||||
internalRemark: null,
|
||||
createdAt: null,
|
||||
approvedAt: null,
|
||||
})
|
||||
|
||||
const tenantId = '9223372036854775806'
|
||||
const warehouseId = '9223372036854775805'
|
||||
const warehouse: PlatformWarehouseResource = {
|
||||
id: warehouseId,
|
||||
tenantId,
|
||||
warehouseCode: 'CN-YW-01',
|
||||
warehouseName: '义乌收货仓',
|
||||
warehouseType: 'DOMESTIC',
|
||||
countryCode: 'CN',
|
||||
timezone: 'Asia/Shanghai',
|
||||
contactName: null,
|
||||
contactPhone: null,
|
||||
contactEmail: null,
|
||||
status: 'ACTIVE',
|
||||
remark: null,
|
||||
}
|
||||
|
||||
const availableLocation: PlatformLocationResource = {
|
||||
id: '9223372036854775804',
|
||||
tenantId,
|
||||
warehouseId,
|
||||
zoneCode: 'A',
|
||||
zoneName: '常规区',
|
||||
locationCode: 'A1-01',
|
||||
locationName: 'A1 区 01 位',
|
||||
locationType: 'SHELF',
|
||||
maxWeightKg: '500.000',
|
||||
sharedOverflow: false,
|
||||
status: 'AVAILABLE',
|
||||
remark: '靠近入库口',
|
||||
version: 3,
|
||||
updatedAt: '2026-08-04T10:20:00',
|
||||
}
|
||||
|
||||
const occupiedLocation: PlatformLocationResource = {
|
||||
...availableLocation,
|
||||
id: '9223372036854775803',
|
||||
locationCode: 'A1-02',
|
||||
locationName: 'A1 区 02 位',
|
||||
status: 'OCCUPIED',
|
||||
version: 5,
|
||||
}
|
||||
|
||||
async function mountView() {
|
||||
vi.stubGlobal('localStorage', createMemoryStorage())
|
||||
vi.stubGlobal('sessionStorage', createMemoryStorage())
|
||||
const pinia = createPinia()
|
||||
setActivePinia(pinia)
|
||||
const auth = useAuthStore()
|
||||
auth.token = 'token'
|
||||
auth.permissions = [
|
||||
'platform:location:list',
|
||||
'platform:location:create',
|
||||
'platform:location:edit',
|
||||
'platform:location:status',
|
||||
'platform:location:delete',
|
||||
]
|
||||
useAccessPreviewStore().initializeAfterLogin()
|
||||
const wrapper = mount(LocationsView, {
|
||||
attachTo: document.body,
|
||||
global: { plugins: [pinia, ElementPlus] },
|
||||
})
|
||||
await flushPromises()
|
||||
return wrapper
|
||||
}
|
||||
|
||||
async function selectScope(wrapper: VueWrapper) {
|
||||
let toolbar = wrapper.findComponent(QueryToolbar)
|
||||
toolbar.vm.$emit('update:modelValue', { ...(toolbar.props('modelValue') as QueryModel), customerId: tenantId })
|
||||
await flushPromises()
|
||||
toolbar = wrapper.findComponent(QueryToolbar)
|
||||
toolbar.vm.$emit('update:modelValue', { ...(toolbar.props('modelValue') as QueryModel), warehouseId })
|
||||
await flushPromises()
|
||||
const searchButton = toolbar.findAll('button').find((button) => button.text().trim() === '查询')
|
||||
await searchButton!.trigger('click')
|
||||
await flushPromises()
|
||||
}
|
||||
|
||||
enableAutoUnmount(afterEach)
|
||||
afterAll(() => vi.unstubAllGlobals())
|
||||
|
||||
describe('LocationsView', () => {
|
||||
beforeEach(() => {
|
||||
vi.stubGlobal('ResizeObserver', ResizeObserverStub)
|
||||
document.body.innerHTML = ''
|
||||
vi.mocked(listPlatformTenants).mockReset().mockResolvedValue({
|
||||
records: [tenant(tenantId)], page: 1, size: 200, total: 1, pages: 1,
|
||||
})
|
||||
vi.mocked(listPlatformWarehouses).mockReset().mockResolvedValue({
|
||||
records: [warehouse], page: 1, size: 200, total: 1, pages: 1,
|
||||
})
|
||||
vi.mocked(listPlatformLocations).mockReset().mockResolvedValue({
|
||||
records: [availableLocation, occupiedLocation], page: 1, size: 20, total: 2, pages: 1,
|
||||
})
|
||||
vi.mocked(getPlatformLocation).mockReset().mockResolvedValue({
|
||||
location: availableLocation, warehouseCode: warehouse.warehouseCode, warehouseName: warehouse.warehouseName,
|
||||
})
|
||||
})
|
||||
|
||||
it('starts with all customers and queries the full list without empty IDs', async () => {
|
||||
const wrapper = await mountView()
|
||||
const toolbar = wrapper.findComponent(QueryToolbar)
|
||||
const fields = toolbar.props('fields') as QueryField[]
|
||||
|
||||
expect(listPlatformTenants).toHaveBeenCalledWith({ page: 1, size: 200 })
|
||||
expect(wrapper.find('[aria-label="所属企业"]').exists()).toBe(true)
|
||||
expect(fields[0]?.placeholder).toBe('全部客户')
|
||||
expect((toolbar.props('modelValue') as QueryModel).customerId).toBe('')
|
||||
expect(fields.map(({ key, width }) => [key, width])).toEqual([
|
||||
['customerId', 260], ['warehouseId', 240], ['zoneCode', 210],
|
||||
['locationCode', 220], ['locationType', 170], ['status', 160],
|
||||
])
|
||||
expect(listPlatformWarehouses).not.toHaveBeenCalled()
|
||||
expect(listPlatformLocations).toHaveBeenCalledWith({
|
||||
page: 1,
|
||||
size: 20,
|
||||
zoneCode: '',
|
||||
locationCode: '',
|
||||
locationType: '',
|
||||
status: '',
|
||||
})
|
||||
const searchButton = toolbar.findAll('button').find((button) => button.text().trim() === '查询')
|
||||
await searchButton!.trigger('click')
|
||||
await flushPromises()
|
||||
expect(listPlatformLocations).toHaveBeenCalledTimes(2)
|
||||
expect(wrapper.text()).not.toContain('请选择客户')
|
||||
expect(wrapper.text()).not.toContain('请选择所属企业')
|
||||
expect(wrapper.text()).not.toContain('租户')
|
||||
expect(wrapper.text()).not.toContain('企业 ID')
|
||||
})
|
||||
|
||||
it('loads the selected customer, warehouse, and location hierarchy without narrowing snowflake IDs', async () => {
|
||||
const wrapper = await mountView()
|
||||
await selectScope(wrapper)
|
||||
|
||||
expect(wrapper.find('.table-panel .panel-heading').exists()).toBe(false)
|
||||
expect(listPlatformWarehouses).toHaveBeenCalledWith(tenantId, 1, 200)
|
||||
expect(listPlatformLocations).toHaveBeenLastCalledWith({
|
||||
page: 1,
|
||||
size: 20,
|
||||
tenantId,
|
||||
warehouseId,
|
||||
zoneCode: '',
|
||||
locationCode: '',
|
||||
locationType: '',
|
||||
status: '',
|
||||
})
|
||||
expect(wrapper.text()).toContain('义乌收货仓')
|
||||
expect(wrapper.text()).toContain('A1-01')
|
||||
expect(wrapper.findAll('thead th').map((item) => item.text().trim())).toEqual([
|
||||
'操作', '库位编码', '所属仓库', '库区', '库位类型', '最大承重(kg)', '状态', '备注',
|
||||
])
|
||||
})
|
||||
|
||||
it('keeps the operation column first and hides edit actions for occupied resources', async () => {
|
||||
const wrapper = await mountView()
|
||||
await selectScope(wrapper)
|
||||
const headings = wrapper.findAll('thead th').map((item) => item.text().trim())
|
||||
expect(headings[0]).toBe('操作')
|
||||
|
||||
const bodyRows = wrapper.findAll('tbody tr')
|
||||
expect(bodyRows[0]?.text()).toContain('编辑')
|
||||
expect(bodyRows[1]?.text()).toContain('详情')
|
||||
expect(bodyRows[1]?.text()).not.toContain('编辑')
|
||||
expect(bodyRows[1]?.text()).not.toContain('更多')
|
||||
})
|
||||
|
||||
it('opens an authenticated detail view with warehouse context', async () => {
|
||||
const wrapper = await mountView()
|
||||
const detailButton = wrapper.find('.el-table__body-wrapper tbody tr button')
|
||||
expect(detailButton.text()).toBe('详情')
|
||||
await detailButton.trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(getPlatformLocation).toHaveBeenCalledWith(tenantId, warehouseId, availableLocation.id)
|
||||
expect(document.body.textContent).toContain('库位详情')
|
||||
expect(document.body.textContent).toContain('义乌收货仓(CN-YW-01)')
|
||||
expect(document.body.textContent).toContain(`所属企业雪花企业(${tenantId})`)
|
||||
expect(document.body.textContent).not.toContain('企业 ID')
|
||||
expect(document.body.textContent).toContain('库位名称A1 区 01 位')
|
||||
expect(document.body.textContent).toContain('v3')
|
||||
})
|
||||
|
||||
it('presents occupied locations as read-only business resources', async () => {
|
||||
vi.mocked(getPlatformLocation).mockResolvedValueOnce({
|
||||
location: occupiedLocation,
|
||||
warehouseCode: warehouse.warehouseCode,
|
||||
warehouseName: warehouse.warehouseName,
|
||||
})
|
||||
const wrapper = await mountView()
|
||||
const occupiedRow = wrapper.findAll('tbody tr')[1]
|
||||
await occupiedRow!.find('button').trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(document.body.textContent).toContain('状态已占用')
|
||||
expect(document.body.textContent).toContain('当前库位正在被业务使用,只允许查看。')
|
||||
})
|
||||
|
||||
it('clears customer and warehouse on reset and immediately restores the full query', async () => {
|
||||
const wrapper = await mountView()
|
||||
await selectScope(wrapper)
|
||||
const toolbar = wrapper.findComponent(QueryToolbar)
|
||||
const resetButton = toolbar.findAll('button').find((button) => button.text().trim() === '重置')
|
||||
|
||||
await resetButton!.trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
const model = wrapper.findComponent(QueryToolbar).props('modelValue') as QueryModel
|
||||
expect(model.customerId).toBe('')
|
||||
expect(model.warehouseId).toBe('')
|
||||
expect(listPlatformLocations).toHaveBeenLastCalledWith({
|
||||
page: 1,
|
||||
size: 20,
|
||||
zoneCode: '',
|
||||
locationCode: '',
|
||||
locationType: '',
|
||||
status: '',
|
||||
})
|
||||
expect(wrapper.text()).not.toContain('请选择客户')
|
||||
})
|
||||
|
||||
it('paginates the all-customer list without adding customer or warehouse IDs', async () => {
|
||||
vi.mocked(listPlatformLocations).mockResolvedValue({
|
||||
records: [availableLocation, occupiedLocation], page: 1, size: 20, total: 40, pages: 2,
|
||||
})
|
||||
const wrapper = await mountView()
|
||||
wrapper.findComponent(DataTable).vm.$emit('update:page', 2)
|
||||
await flushPromises()
|
||||
|
||||
expect(listPlatformLocations).toHaveBeenLastCalledWith({
|
||||
page: 2,
|
||||
size: 20,
|
||||
zoneCode: '',
|
||||
locationCode: '',
|
||||
locationType: '',
|
||||
status: '',
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user