Merge remote-tracking branch 'origin/release/test' into release/test
This commit is contained in:
@@ -0,0 +1,22 @@
|
|||||||
|
import assert from 'node:assert/strict'
|
||||||
|
import { readFileSync } from 'node:fs'
|
||||||
|
import test from 'node:test'
|
||||||
|
import ts from 'typescript'
|
||||||
|
|
||||||
|
const source = readFileSync(new URL('./returnReceiptDisplay.ts', import.meta.url), 'utf8')
|
||||||
|
const compiled = ts.transpileModule(source, { compilerOptions: { target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.CommonJS } }).outputText
|
||||||
|
const exports = {}
|
||||||
|
new Function('exports', compiled)(exports)
|
||||||
|
|
||||||
|
test('volume rounds upward to exactly three decimal places without increasing exact thousandths', () => {
|
||||||
|
for (const [input, expected] of [[0.186624, '0.187'], [0.15, '0.150'], [1.001, '1.001'], [1.00100001, '1.002'], [0.0000001, '0.001'], [0, '0.000'], [null, '—'], [NaN, '—']]) {
|
||||||
|
assert.equal(exports.formatReturnVolume(input), expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test('parcel waybills appear as tracking numbers while generated parcel codes remain physical codes', () => {
|
||||||
|
assert.equal(exports.receiptTrackingNo({ unitType: 'PARCEL', unitCode: 'sf561626' }), 'sf561626')
|
||||||
|
assert.equal(exports.receiptTrackingNo({ unitType: 'PARCEL', unitCode: 'PK0123456789ABCDEF' }), '')
|
||||||
|
assert.equal(exports.receiptTrackingNo({ unitType: 'PARCEL', unitCode: 'PK0123456789ABCDEF', trackingNo: ' SF123 ' }), 'SF123')
|
||||||
|
assert.equal(exports.receiptTrackingNo({ unitType: 'PALLET', unitCode: 'PLT123' }), '')
|
||||||
|
})
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import type { ReturnReceipt } from '../api/returnOrders'
|
||||||
|
|
||||||
|
export function receiptTrackingNo(receipt: Pick<ReturnReceipt, 'trackingNo' | 'unitCode' | 'unitType'> | Record<string, unknown>) {
|
||||||
|
const trackingNo = typeof receipt.trackingNo === 'string' ? receipt.trackingNo.trim() : ''
|
||||||
|
if (trackingNo) return trackingNo
|
||||||
|
const code = typeof receipt.unitCode === 'string' ? receipt.unitCode.trim() : ''
|
||||||
|
return receipt.unitType === 'PARCEL' && code && !/^PK[0-9A-F]{16}$/.test(code) ? code : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatReturnVolume(value?: number | null) {
|
||||||
|
if (value == null || !Number.isFinite(value) || value < 0) return '—'
|
||||||
|
// Shift the decimal in text to avoid floating-point over-rounding exact thousandths.
|
||||||
|
const [coefficient, exponent = '0'] = String(value).toLowerCase().split('e')
|
||||||
|
const [integer, fraction = ''] = coefficient!.split('.')
|
||||||
|
const digits = integer! + fraction
|
||||||
|
const cutoff = integer!.length + Number(exponent) + 3
|
||||||
|
const scaled = cutoff <= 0 ? '0' : digits.slice(0, cutoff).padEnd(cutoff, '0')
|
||||||
|
const remainder = cutoff < 0 ? digits : digits.slice(Math.max(0, cutoff))
|
||||||
|
const rounded = BigInt(scaled) + (/[1-9]/.test(remainder) ? 1n : 0n)
|
||||||
|
return `${rounded / 1000n}.${String(rounded % 1000n).padStart(3, '0')}`
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import { getMerchantWarehouses, type MerchantWarehouse } from '@/modules/first-l
|
|||||||
import { createIdempotencyKey } from '@/utils/idempotencyKey'
|
import { createIdempotencyKey } from '@/utils/idempotencyKey'
|
||||||
import { createReturnOrder, downloadReturnPhoto, getReturnOrder, listReturnOrders, updateReturnOrder, type ReturnOrderDetail, type ReturnOrderSummary, type ReturnReceipt } from '../api/returnOrders'
|
import { createReturnOrder, downloadReturnPhoto, getReturnOrder, listReturnOrders, updateReturnOrder, type ReturnOrderDetail, type ReturnOrderSummary, type ReturnReceipt } from '../api/returnOrders'
|
||||||
import { getReturnInventoryLabel } from '../api/returnInventory'
|
import { getReturnInventoryLabel } from '../api/returnInventory'
|
||||||
|
import { formatReturnVolume, receiptTrackingNo } from '../utils/returnReceiptDisplay'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{ createPage?: boolean; detailPage?: boolean; returnNo?: string }>(), { createPage: false, detailPage: false, returnNo: '' })
|
const props = withDefaults(defineProps<{ createPage?: boolean; detailPage?: boolean; returnNo?: string }>(), { createPage: false, detailPage: false, returnNo: '' })
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -67,7 +68,7 @@ const receiptColumns: DataTableColumn[] = [
|
|||||||
{ prop: 'receiptBatchNo', label: '批次号', minWidth: 145 },
|
{ prop: 'receiptBatchNo', label: '批次号', minWidth: 145 },
|
||||||
{ prop: 'receiptNo', label: '签收单号', minWidth: 145 },
|
{ prop: 'receiptNo', label: '签收单号', minWidth: 145 },
|
||||||
{ key: 'unitType', label: '实物类型', slotName: 'unitType', width: 90 },
|
{ key: 'unitType', label: '实物类型', slotName: 'unitType', width: 90 },
|
||||||
{ prop: 'unitCode', label: '实物编码', minWidth: 160 },
|
{ key: 'unitCode', label: '实物编码', slotName: 'unitCode', minWidth: 160 },
|
||||||
{ key: 'trackingNo', label: '快递单号', slotName: 'trackingNo', minWidth: 140 },
|
{ key: 'trackingNo', label: '快递单号', slotName: 'trackingNo', minWidth: 140 },
|
||||||
{ key: 'startedBy', label: '开始方式', slotName: 'startedBy', width: 100 },
|
{ key: 'startedBy', label: '开始方式', slotName: 'startedBy', width: 100 },
|
||||||
{ prop: 'receivedQuantity', label: '实收', width: 80 },
|
{ prop: 'receivedQuantity', label: '实收', width: 80 },
|
||||||
@@ -389,7 +390,7 @@ onBeforeUnmount(clearPhotoUrls)
|
|||||||
<h3 class="section-heading-with-action"><span>实物明细({{ selected.pallets?.length || 0 }} 个托盘/箱)</span><span v-if="printableReceipts.length" class="return-label-actions"><el-button type="primary" size="small" @click="printReturnLabel(printableReceipts)">打印全部箱唛({{ printableBoxCount }} 箱)</el-button></span></h3>
|
<h3 class="section-heading-with-action"><span>实物明细({{ selected.pallets?.length || 0 }} 个托盘/箱)</span><span v-if="printableReceipts.length" class="return-label-actions"><el-button type="primary" size="small" @click="printReturnLabel(printableReceipts)">打印全部箱唛({{ printableBoxCount }} 箱)</el-button></span></h3>
|
||||||
<el-collapse v-if="selected.pallets?.length" class="return-pallet-list">
|
<el-collapse v-if="selected.pallets?.length" class="return-pallet-list">
|
||||||
<el-collapse-item v-for="pallet in selected.pallets" :key="pallet.palletCode" :name="pallet.palletCode">
|
<el-collapse-item v-for="pallet in selected.pallets" :key="pallet.palletCode" :name="pallet.palletCode">
|
||||||
<template #title><strong>{{ pallet.unitType === 'BOX' ? '箱子' : '托盘' }} {{ pallet.unitCode || pallet.palletCode }}</strong><span class="return-pallet-summary">{{ pallet.skuTypes }} 种 SKU · {{ pallet.totalQuantity }} 件 · {{ pallet.totalBoxCount }} 箱 · 体积 {{ pallet.volumeCbm == null ? '—' : `${pallet.volumeCbm} m³` }}</span></template>
|
<template #title><strong>{{ pallet.unitType === 'BOX' ? '箱子' : '托盘' }} {{ pallet.unitCode || pallet.palletCode }}</strong><span class="return-pallet-summary">{{ pallet.skuTypes }} 种 SKU · {{ pallet.totalQuantity }} 件 · {{ pallet.totalBoxCount }} 箱 · 体积 {{ formatReturnVolume(pallet.volumeCbm) }} m³</span></template>
|
||||||
<div class="return-pallet-measurements">长 {{ pallet.length ?? '—' }} cm · 宽 {{ pallet.width ?? '—' }} cm · 高 {{ pallet.height ?? '—' }} cm · 重量 {{ pallet.weight ?? '—' }} kg</div>
|
<div class="return-pallet-measurements">长 {{ pallet.length ?? '—' }} cm · 宽 {{ pallet.width ?? '—' }} cm · 高 {{ pallet.height ?? '—' }} cm · 重量 {{ pallet.weight ?? '—' }} kg</div>
|
||||||
<el-table :data="pallet.items" size="small" border>
|
<el-table :data="pallet.items" size="small" border>
|
||||||
<el-table-column prop="skuCode" label="SKU" min-width="150" />
|
<el-table-column prop="skuCode" label="SKU" min-width="150" />
|
||||||
@@ -437,7 +438,8 @@ onBeforeUnmount(clearPhotoUrls)
|
|||||||
<h3>签收批次</h3>
|
<h3>签收批次</h3>
|
||||||
<DataTable :data="selected.receipts" :columns="receiptColumns" row-key="receiptNo" empty-text="暂无签收批次">
|
<DataTable :data="selected.receipts" :columns="receiptColumns" row-key="receiptNo" empty-text="暂无签收批次">
|
||||||
<template #unitType="{ row }">{{ row.unitType === 'PALLET' ? '托盘' : row.unitType === 'BOX' ? '箱子' : '包裹' }}</template>
|
<template #unitType="{ row }">{{ row.unitType === 'PALLET' ? '托盘' : row.unitType === 'BOX' ? '箱子' : '包裹' }}</template>
|
||||||
<template #trackingNo="{ row }">{{ row.trackingNo || '无快递单号' }}</template>
|
<template #unitCode="{ row }">{{ row.unitType === 'PARCEL' && row.unitCode === receiptTrackingNo(row) ? '—' : row.unitCode || '—' }}</template>
|
||||||
|
<template #trackingNo="{ row }">{{ receiptTrackingNo(row) || '无快递单号' }}</template>
|
||||||
<template #startedBy="{ row }">{{ startedByLabel(row.startedBy) }}</template>
|
<template #startedBy="{ row }">{{ startedByLabel(row.startedBy) }}</template>
|
||||||
<template #signedAt="{ row }">{{ formatDateTime(row.signedAt) }}</template>
|
<template #signedAt="{ row }">{{ formatDateTime(row.signedAt) }}</template>
|
||||||
</DataTable>
|
</DataTable>
|
||||||
|
|||||||
Reference in New Issue
Block a user