优化提交

This commit is contained in:
2026-10-10 13:47:47 +08:00
parent 5751973c83
commit 90e1e646ec
3 changed files with 48 additions and 3 deletions
@@ -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 { createReturnOrder, downloadReturnPhoto, getReturnOrder, listReturnOrders, updateReturnOrder, type ReturnOrderDetail, type ReturnOrderSummary, type ReturnReceipt } from '../api/returnOrders'
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 router = useRouter()
@@ -67,7 +68,7 @@ const receiptColumns: DataTableColumn[] = [
{ prop: 'receiptBatchNo', label: '批次号', minWidth: 145 },
{ prop: 'receiptNo', label: '签收单号', minWidth: 145 },
{ 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: 'startedBy', label: '开始方式', slotName: 'startedBy', width: 100 },
{ 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>
<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">
<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>
<el-table :data="pallet.items" size="small" border>
<el-table-column prop="skuCode" label="SKU" min-width="150" />
@@ -437,7 +438,8 @@ onBeforeUnmount(clearPhotoUrls)
<h3>签收批次</h3>
<DataTable :data="selected.receipts" :columns="receiptColumns" row-key="receiptNo" empty-text="暂无签收批次">
<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 #signedAt="{ row }">{{ formatDateTime(row.signedAt) }}</template>
</DataTable>