1
This commit is contained in:
+9
-4
@@ -144,6 +144,7 @@ export async function apiRequest<T>(config: AxiosRequestConfig) {
|
|||||||
export async function apiBlobRequest(config: AxiosRequestConfig) {
|
export async function apiBlobRequest(config: AxiosRequestConfig) {
|
||||||
try {
|
try {
|
||||||
const response = await transport.request<Blob>({ ...config, responseType: 'blob' })
|
const response = await transport.request<Blob>({ ...config, responseType: 'blob' })
|
||||||
|
await throwBlobApiError(response.data, response.status)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await throwBlobApiError(error)
|
await throwBlobApiError(error)
|
||||||
@@ -154,6 +155,7 @@ export async function apiBlobRequest(config: AxiosRequestConfig) {
|
|||||||
export async function apiBlobResponseRequest(config: AxiosRequestConfig) {
|
export async function apiBlobResponseRequest(config: AxiosRequestConfig) {
|
||||||
try {
|
try {
|
||||||
const response = await transport.request<Blob>({ ...config, responseType: 'blob' })
|
const response = await transport.request<Blob>({ ...config, responseType: 'blob' })
|
||||||
|
await throwBlobApiError(response.data, response.status)
|
||||||
return { blob: response.data, headers: response.headers }
|
return { blob: response.data, headers: response.headers }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await throwBlobApiError(error)
|
await throwBlobApiError(error)
|
||||||
@@ -161,16 +163,19 @@ export async function apiBlobResponseRequest(config: AxiosRequestConfig) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function throwBlobApiError(error: unknown) {
|
async function throwBlobApiError(error: unknown, responseStatus?: number) {
|
||||||
if (!axios.isAxiosError(error) || !(error.response?.data instanceof Blob)) return
|
const blob = error instanceof Blob
|
||||||
|
? error
|
||||||
|
: axios.isAxiosError(error) && error.response?.data instanceof Blob ? error.response.data : null
|
||||||
|
if (!blob || !blob.type.toLowerCase().includes('json')) return
|
||||||
try {
|
try {
|
||||||
const body = JSON.parse(await error.response.data.text()) as unknown
|
const body = JSON.parse(await blob.text()) as unknown
|
||||||
if (!isApiEnvelope(body)) return
|
if (!isApiEnvelope(body)) return
|
||||||
const fieldErrors = asFieldErrors(body.data)
|
const fieldErrors = asFieldErrors(body.data)
|
||||||
throw new ApiError(
|
throw new ApiError(
|
||||||
apiErrorMessage(body.message, fieldErrors),
|
apiErrorMessage(body.message, fieldErrors),
|
||||||
body.code,
|
body.code,
|
||||||
error.response.status,
|
responseStatus ?? (axios.isAxiosError(error) ? error.response?.status : undefined),
|
||||||
fieldErrors,
|
fieldErrors,
|
||||||
typeof body.traceId === 'string' ? body.traceId : null,
|
typeof body.traceId === 'string' ? body.traceId : null,
|
||||||
typeof body.requestId === 'string' ? body.requestId : null,
|
typeof body.requestId === 'string' ? body.requestId : null,
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ const source = readFileSync(new URL('./InboundCodeAssociationDialog.vue', import
|
|||||||
|
|
||||||
test('loads only the customer-scoped server association and fails closed', () => {
|
test('loads only the customer-scoped server association and fails closed', () => {
|
||||||
assert.match(source, /getMerchantInboundCodeAssociation\(inboundCode\)/)
|
assert.match(source, /getMerchantInboundCodeAssociation\(inboundCode\)/)
|
||||||
|
assert.match(source, /getFirstLegStatusLabel\(association\.orderStatus\)/)
|
||||||
|
assert.doesNotMatch(source, /FIRST_LEG_ORDER_STATUSES/)
|
||||||
assert.match(source, /association\.value = null/)
|
assert.match(source, /association\.value = null/)
|
||||||
assert.match(source, /关联摘要加载失败/)
|
assert.match(source, /关联摘要加载失败/)
|
||||||
assert.match(source, /@click="loadAssociation"/)
|
assert.match(source, /@click="loadAssociation"/)
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, watch } from 'vue'
|
import { computed, ref, watch } from 'vue'
|
||||||
import { AlertTriangle, Link2, RefreshCw } from '@lucide/vue'
|
import { AlertTriangle, Link2, RefreshCw } from '@lucide/vue'
|
||||||
import { FIRST_LEG_ORDER_STATUSES } from '@chongchong/shared'
|
|
||||||
import {
|
import {
|
||||||
getMerchantInboundCodeAssociation,
|
getMerchantInboundCodeAssociation,
|
||||||
type MerchantInboundCodeAssociation,
|
type MerchantInboundCodeAssociation,
|
||||||
} from '@/modules/first-leg/api/inboundCodeAssociations'
|
} from '@/modules/first-leg/api/inboundCodeAssociations'
|
||||||
|
import { getFirstLegStatusLabel } from '@/modules/first-leg/utils/firstLegOrder'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
modelValue: boolean
|
modelValue: boolean
|
||||||
@@ -30,10 +30,6 @@ function displayValue(value: string | null | undefined) {
|
|||||||
return value?.trim() || '—'
|
return value?.trim() || '—'
|
||||||
}
|
}
|
||||||
|
|
||||||
function statusLabel(value: string) {
|
|
||||||
return FIRST_LEG_ORDER_STATUSES.find((item) => item.code === value)?.label ?? displayValue(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
function destinationLabel(value: MerchantInboundCodeAssociation) {
|
function destinationLabel(value: MerchantInboundCodeAssociation) {
|
||||||
return [value.destinationWarehouseCode, value.destinationWarehouseName].filter(Boolean).join(' · ') || '—'
|
return [value.destinationWarehouseCode, value.destinationWarehouseName].filter(Boolean).join(' · ') || '—'
|
||||||
}
|
}
|
||||||
@@ -87,7 +83,7 @@ watch(() => [props.modelValue, props.inboundCode] as const, ([open]) => {
|
|||||||
</header>
|
</header>
|
||||||
<dl class="inbound-association-grid">
|
<dl class="inbound-association-grid">
|
||||||
<div><dt>订单号</dt><dd>{{ displayValue(association.orderNo) }}</dd></div>
|
<div><dt>订单号</dt><dd>{{ displayValue(association.orderNo) }}</dd></div>
|
||||||
<div><dt>订单状态</dt><dd>{{ statusLabel(association.orderStatus) }}</dd></div>
|
<div><dt>订单状态</dt><dd>{{ getFirstLegStatusLabel(association.orderStatus) }}</dd></div>
|
||||||
<div><dt>客户名称</dt><dd>{{ displayValue(association.customerName) }}</dd></div>
|
<div><dt>客户名称</dt><dd>{{ displayValue(association.customerName) }}</dd></div>
|
||||||
<div><dt>目的国家</dt><dd>{{ displayValue(association.destinationCountryCode) }}</dd></div>
|
<div><dt>目的国家</dt><dd>{{ displayValue(association.destinationCountryCode) }}</dd></div>
|
||||||
<div class="is-wide"><dt>目的仓</dt><dd>{{ destinationLabel(association) }}</dd></div>
|
<div class="is-wide"><dt>目的仓</dt><dd>{{ destinationLabel(association) }}</dd></div>
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ test('distinguishes first-leg draft, review, active handling and completion', ()
|
|||||||
assert.equal(getFirstLegStatusTone('LOADED'), 'success')
|
assert.equal(getFirstLegStatusTone('LOADED'), 'success')
|
||||||
assert.equal(getFirstLegStatusTone('DELIVERED'), 'success')
|
assert.equal(getFirstLegStatusTone('DELIVERED'), 'success')
|
||||||
assert.equal(getFirstLegStatusTone('COMPLETED'), 'success')
|
assert.equal(getFirstLegStatusTone('COMPLETED'), 'success')
|
||||||
|
assert.equal(getFirstLegStatusLabel('SUBMITTED'), '\u5f85\u5ba1\u6838')
|
||||||
assert.equal(getFirstLegStatusLabel('COMPLETED'), '已完成')
|
assert.equal(getFirstLegStatusLabel('COMPLETED'), '已完成')
|
||||||
assert.equal(getFirstLegStatusLabel('UNRECOGNIZED'), '未知状态')
|
assert.equal(getFirstLegStatusLabel('UNRECOGNIZED'), '未知状态')
|
||||||
assert.equal(getFirstLegStatusTone('UNRECOGNIZED'), 'info')
|
assert.equal(getFirstLegStatusTone('UNRECOGNIZED'), 'info')
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ const transportModeLabels = new Map<FirstLegTransportMode, string>(
|
|||||||
FIRST_LEG_TRANSPORT_MODES.map((item) => [item.code, item.label]),
|
FIRST_LEG_TRANSPORT_MODES.map((item) => [item.code, item.label]),
|
||||||
)
|
)
|
||||||
|
|
||||||
export function getFirstLegStatusLabel(status: FirstLegOrderStatus) {
|
export function getFirstLegStatusLabel(status: string) {
|
||||||
return statusLabels.get(status) ?? '未知状态'
|
const canonicalStatus = status === 'SUBMITTED' ? 'PENDING_REVIEW' : status
|
||||||
|
return statusLabels.get(canonicalStatus as FirstLegOrderStatus) ?? '未知状态'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFirstLegTransportModeLabel(mode: FirstLegTransportMode | null) {
|
export function getFirstLegTransportModeLabel(mode: FirstLegTransportMode | null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user