优化
This commit is contained in:
@@ -82,11 +82,20 @@ describe('inbound weight OCR API', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('loads same-warehouse pallet snapshots through Firstleg', async () => {
|
it('normalizes the formal paged pallet response returned by Firstleg', async () => {
|
||||||
const options = [{ palletId: '11', palletCode: 'TP-11', palletType: '木托盘', capacityCbm: 1.2, tareWeightKg: 12 }]
|
const records = [
|
||||||
vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: options })
|
{ palletId: '2092803000000000001', palletCode: 'TP-11', palletType: '木托盘', capacityCbm: 1.2, tareWeightKg: 12 },
|
||||||
|
{ palletId: '2092803000000000002', palletCode: 'TP-12', palletType: '塑料托盘', capacityCbm: 1.1, tareWeightKg: 10 },
|
||||||
|
]
|
||||||
|
vi.mocked(http.get).mockResolvedValue({
|
||||||
|
code: '200',
|
||||||
|
message: 'success',
|
||||||
|
data: { records, page: '1', size: '20', total: '2', pages: '1' },
|
||||||
|
})
|
||||||
|
|
||||||
await expect(getWeightPalletOptions('10001', '20001')).resolves.toEqual(options)
|
await expect(getWeightPalletOptions('10001', '20001')).resolves.toEqual({
|
||||||
|
records, page: 1, size: 20, total: 2, pages: 1,
|
||||||
|
})
|
||||||
expect(http.get).toHaveBeenCalledWith(
|
expect(http.get).toHaveBeenCalledWith(
|
||||||
'/platform/v1/first-leg/inbounds/20001/weight-pallet-options',
|
'/platform/v1/first-leg/inbounds/20001/weight-pallet-options',
|
||||||
{ params: { tenantId: '10001' } },
|
{ params: { tenantId: '10001' } },
|
||||||
@@ -94,7 +103,9 @@ describe('inbound weight OCR API', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('passes an abort signal without changing the frozen pallet endpoint parameters', async () => {
|
it('passes an abort signal without changing the frozen pallet endpoint parameters', async () => {
|
||||||
vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: [] })
|
vi.mocked(http.get).mockResolvedValue({
|
||||||
|
code: '200', message: 'success', data: { records: [], page: '1', size: '20', total: '0', pages: '0' },
|
||||||
|
})
|
||||||
const controller = new AbortController()
|
const controller = new AbortController()
|
||||||
|
|
||||||
await getWeightPalletOptions('10001', '20001', controller.signal)
|
await getWeightPalletOptions('10001', '20001', controller.signal)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import type {
|
|||||||
CreateWeightResultRequest,
|
CreateWeightResultRequest,
|
||||||
WeightImageUploadResult,
|
WeightImageUploadResult,
|
||||||
WeightPalletOption,
|
WeightPalletOption,
|
||||||
|
WeightPalletOptionPage,
|
||||||
WeightResultResource,
|
WeightResultResource,
|
||||||
WeightWorkspaceResource,
|
WeightWorkspaceResource,
|
||||||
} from '../types'
|
} from '../types'
|
||||||
@@ -15,10 +16,23 @@ const imageBasePath = '/platform/v1/files/measurements'
|
|||||||
const maxErrorEnvelopeBytes = 1024 * 1024
|
const maxErrorEnvelopeBytes = 1024 * 1024
|
||||||
const confidenceScale = 100_000
|
const confidenceScale = 100_000
|
||||||
|
|
||||||
|
interface WeightPalletOptionPageResponse {
|
||||||
|
records: WeightPalletOption[]
|
||||||
|
page: number | string
|
||||||
|
size: number | string
|
||||||
|
total: number | string
|
||||||
|
pages: number | string
|
||||||
|
}
|
||||||
|
|
||||||
function segment(value: string) {
|
function segment(value: string) {
|
||||||
return encodeURIComponent(value)
|
return encodeURIComponent(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizedPageNumber(value: number | string, fallback: number, minimum: number) {
|
||||||
|
const parsed = typeof value === 'number' ? value : Number(value)
|
||||||
|
return Number.isFinite(parsed) ? Math.max(minimum, Math.trunc(parsed)) : fallback
|
||||||
|
}
|
||||||
|
|
||||||
export function normalizeWeightConfidence(value: number | null) {
|
export function normalizeWeightConfidence(value: number | null) {
|
||||||
if (value == null || !Number.isFinite(value)) return null
|
if (value == null || !Number.isFinite(value)) return null
|
||||||
const clamped = Math.min(1, Math.max(0, value))
|
const clamped = Math.min(1, Math.max(0, value))
|
||||||
@@ -61,11 +75,18 @@ export async function getWeightWorkspace(tenantId: string, inboundId: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getWeightPalletOptions(tenantId: string, inboundId: string, signal?: AbortSignal) {
|
export async function getWeightPalletOptions(tenantId: string, inboundId: string, signal?: AbortSignal) {
|
||||||
const response = await http.get<ApiEnvelope<WeightPalletOption[]>, ApiEnvelope<WeightPalletOption[]>>(
|
const response = await http.get<ApiEnvelope<WeightPalletOptionPageResponse>, ApiEnvelope<WeightPalletOptionPageResponse>>(
|
||||||
`${measurementBasePath}/${segment(inboundId)}/weight-pallet-options`,
|
`${measurementBasePath}/${segment(inboundId)}/weight-pallet-options`,
|
||||||
{ params: { tenantId }, ...(signal ? { signal } : {}) },
|
{ params: { tenantId }, ...(signal ? { signal } : {}) },
|
||||||
)
|
)
|
||||||
return unwrapApiResponse(response)
|
const page = unwrapApiResponse(response)
|
||||||
|
return {
|
||||||
|
records: page.records,
|
||||||
|
page: normalizedPageNumber(page.page, 1, 1),
|
||||||
|
size: normalizedPageNumber(page.size, page.records.length, 0),
|
||||||
|
total: normalizedPageNumber(page.total, page.records.length, 0),
|
||||||
|
pages: normalizedPageNumber(page.pages, 0, 0),
|
||||||
|
} satisfies WeightPalletOptionPage
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function uploadWeightImage(tenantId: string, inboundId: string, file: File) {
|
export async function uploadWeightImage(tenantId: string, inboundId: string, file: File) {
|
||||||
|
|||||||
@@ -72,6 +72,12 @@ const workspace: WeightWorkspaceResource = {
|
|||||||
weightResults: [pendingWeight],
|
weightResults: [pendingWeight],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function palletPage(records = [{
|
||||||
|
palletId: '50001', palletCode: 'TP-001', palletType: '木托盘', capacityCbm: 1.2, tareWeightKg: 12,
|
||||||
|
}]) {
|
||||||
|
return { records, page: 1, size: 20, total: records.length, pages: records.length ? 1 : 0 }
|
||||||
|
}
|
||||||
|
|
||||||
enableAutoUnmount(afterEach)
|
enableAutoUnmount(afterEach)
|
||||||
|
|
||||||
const allWeightPermissions = [
|
const allWeightPermissions = [
|
||||||
@@ -122,9 +128,7 @@ describe('WeightOcrPanel confirmation behavior', () => {
|
|||||||
vi.clearAllMocks()
|
vi.clearAllMocks()
|
||||||
document.body.innerHTML = ''
|
document.body.innerHTML = ''
|
||||||
vi.mocked(getWeightWorkspace).mockResolvedValue(workspace)
|
vi.mocked(getWeightWorkspace).mockResolvedValue(workspace)
|
||||||
vi.mocked(getWeightPalletOptions).mockResolvedValue([{
|
vi.mocked(getWeightPalletOptions).mockResolvedValue(palletPage())
|
||||||
palletId: '50001', palletCode: 'TP-001', palletType: '木托盘', capacityCbm: 1.2, tareWeightKg: 12,
|
|
||||||
}])
|
|
||||||
vi.mocked(downloadWeightImage).mockResolvedValue(new Blob(['image'], { type: 'image/jpeg' }))
|
vi.mocked(downloadWeightImage).mockResolvedValue(new Blob(['image'], { type: 'image/jpeg' }))
|
||||||
vi.mocked(downloadWeightThumbnail).mockResolvedValue(new Blob(['thumb'], { type: 'image/jpeg' }))
|
vi.mocked(downloadWeightThumbnail).mockResolvedValue(new Blob(['thumb'], { type: 'image/jpeg' }))
|
||||||
vi.stubGlobal('URL', {
|
vi.stubGlobal('URL', {
|
||||||
@@ -326,7 +330,7 @@ describe('WeightOcrPanel confirmation behavior', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('shows an actionable empty state when the warehouse has no pallet options', async () => {
|
it('shows an actionable empty state when the warehouse has no pallet options', async () => {
|
||||||
vi.mocked(getWeightPalletOptions).mockResolvedValueOnce([])
|
vi.mocked(getWeightPalletOptions).mockResolvedValueOnce(palletPage([]))
|
||||||
const wrapper = mountPanel()
|
const wrapper = mountPanel()
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
@@ -334,6 +338,28 @@ describe('WeightOcrPanel confirmation behavior', () => {
|
|||||||
expect(wrapper.findAll('button').some((button) => button.text().includes('重新加载'))).toBe(true)
|
expect(wrapper.findAll('button').some((button) => button.text().includes('重新加载'))).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('renders records from the formal paged response without showing a load failure', async () => {
|
||||||
|
vi.mocked(getWeightPalletOptions).mockResolvedValueOnce({
|
||||||
|
records: [
|
||||||
|
{ palletId: '2092803000000000001', palletCode: 'TP-11', palletType: '木托盘', capacityCbm: 1.2, tareWeightKg: 12 },
|
||||||
|
{ palletId: '2092803000000000002', palletCode: 'TP-12', palletType: '塑料托盘', capacityCbm: 1.1, tareWeightKg: 10 },
|
||||||
|
],
|
||||||
|
page: 1,
|
||||||
|
size: 20,
|
||||||
|
total: 2,
|
||||||
|
pages: 1,
|
||||||
|
})
|
||||||
|
const wrapper = mountPanel()
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
await wrapper.find('.pallet-picker .el-select').trigger('click')
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(document.body.textContent).toContain('木托盘 · 皮重 12.000 KG · 容量 1.2 m³')
|
||||||
|
expect(document.body.textContent).toContain('塑料托盘 · 皮重 10.000 KG · 容量 1.1 m³')
|
||||||
|
expect(wrapper.text()).not.toContain('可选托盘加载失败')
|
||||||
|
})
|
||||||
|
|
||||||
it('shows pallet loading failures without hiding existing weight results', async () => {
|
it('shows pallet loading failures without hiding existing weight results', async () => {
|
||||||
vi.mocked(getWeightPalletOptions).mockRejectedValueOnce(new ApiResponseError('托盘服务暂不可用', 'A0500', 503))
|
vi.mocked(getWeightPalletOptions).mockRejectedValueOnce(new ApiResponseError('托盘服务暂不可用', 'A0500', 503))
|
||||||
const wrapper = mountPanel()
|
const wrapper = mountPanel()
|
||||||
@@ -373,13 +399,13 @@ describe('WeightOcrPanel confirmation behavior', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('virtualizes one thousand pallet candidates instead of rendering one thousand option nodes', async () => {
|
it('virtualizes one thousand pallet candidates instead of rendering one thousand option nodes', async () => {
|
||||||
vi.mocked(getWeightPalletOptions).mockResolvedValue(Array.from({ length: 1_000 }, (_, index) => ({
|
vi.mocked(getWeightPalletOptions).mockResolvedValue(palletPage(Array.from({ length: 1_000 }, (_, index) => ({
|
||||||
palletId: String(60_000 + index),
|
palletId: String(60_000 + index),
|
||||||
palletCode: `TP-${index}`,
|
palletCode: `TP-${index}`,
|
||||||
palletType: `托盘类型 ${index}`,
|
palletType: `托盘类型 ${index}`,
|
||||||
capacityCbm: 1.2,
|
capacityCbm: 1.2,
|
||||||
tareWeightKg: 12,
|
tareWeightKg: 12,
|
||||||
})))
|
}))))
|
||||||
const wrapper = mountPanel()
|
const wrapper = mountPanel()
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
@@ -401,9 +427,9 @@ describe('WeightOcrPanel confirmation behavior', () => {
|
|||||||
const signal = vi.mocked(getWeightPalletOptions).mock.calls[0]?.[2]
|
const signal = vi.mocked(getWeightPalletOptions).mock.calls[0]?.[2]
|
||||||
|
|
||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
resolveOptions?.([{
|
resolveOptions?.(palletPage([{
|
||||||
palletId: 'late', palletCode: 'TP-LATE', palletType: '过期托盘', capacityCbm: 1, tareWeightKg: 10,
|
palletId: 'late', palletCode: 'TP-LATE', palletType: '过期托盘', capacityCbm: 1, tareWeightKg: 10,
|
||||||
}])
|
}]))
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
expect(signal?.aborted).toBe(true)
|
expect(signal?.aborted).toBe(true)
|
||||||
|
|||||||
@@ -242,8 +242,8 @@ async function loadPalletOptions() {
|
|||||||
try {
|
try {
|
||||||
const result = await getWeightPalletOptions(customerId.value, props.inboundId, controller.signal)
|
const result = await getWeightPalletOptions(customerId.value, props.inboundId, controller.signal)
|
||||||
if (sequence !== palletLoadSequence || controller.signal.aborted) return
|
if (sequence !== palletLoadSequence || controller.signal.aborted) return
|
||||||
palletOptions.value = result
|
palletOptions.value = result.records
|
||||||
if (!result.some((option) => option.palletId === selectedPalletId.value)) selectedPalletId.value = ''
|
if (!result.records.some((option) => option.palletId === selectedPalletId.value)) selectedPalletId.value = ''
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (sequence !== palletLoadSequence || controller.signal.aborted) return
|
if (sequence !== palletLoadSequence || controller.signal.aborted) return
|
||||||
palletOptions.value = []
|
palletOptions.value = []
|
||||||
|
|||||||
@@ -43,6 +43,14 @@ export interface WeightPalletOption {
|
|||||||
tareWeightKg: number
|
tareWeightKg: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WeightPalletOptionPage {
|
||||||
|
records: WeightPalletOption[]
|
||||||
|
page: number
|
||||||
|
size: number
|
||||||
|
total: number
|
||||||
|
pages: number
|
||||||
|
}
|
||||||
|
|
||||||
export interface WeightImageUploadResult {
|
export interface WeightImageUploadResult {
|
||||||
fileId: string
|
fileId: string
|
||||||
fileName: string
|
fileName: string
|
||||||
|
|||||||
Reference in New Issue
Block a user