Merge branch 'release/test' of http://git.buggoglobal.com/html/pda-overseas-uniapp into release/test

This commit is contained in:
2026-11-05 14:53:59 +08:00
5 changed files with 39 additions and 19 deletions
+4
View File
@@ -28,6 +28,10 @@
<script> <script>
import { listExceptionReturns, startExceptionReturn, uploadExceptionReturnEvidence, receiveExceptionReturn } from '@/api/exception-returns.js' import { listExceptionReturns, startExceptionReturn, uploadExceptionReturnEvidence, receiveExceptionReturn } from '@/api/exception-returns.js'
export default { export default {
emits: ['working-change'],
watch: {
current(value) { this.$emit('working-change', Boolean(value)) },
},
data() { return { tasks: [], current: null, selectedTask: null, quantities: [], palletCode: '', locationCode: '', photos: [], busy: false, error: '', message: '', revision: 0 } }, data() { return { tasks: [], current: null, selectedTask: null, quantities: [], palletCode: '', locationCode: '', photos: [], busy: false, error: '', message: '', revision: 0 } },
computed: { computed: {
ready() { return this.current && this.palletCode.trim() && this.locationCode.trim() && this.photos.length && this.quantities.some(value => Number(value) > 0) }, ready() { return this.current && this.palletCode.trim() && this.locationCode.trim() && this.photos.length && this.quantities.some(value => Number(value) > 0) },
+8 -9
View File
@@ -1,11 +1,11 @@
<template> <template>
<view v-if="user" class="page-shell portal-page work-page receipt-page" :class="{ 'pda-task-list receipt-lookup-page': receiptDomain === 'customer' && !current && !result }"> <view v-if="user" class="page-shell portal-page work-page receipt-page" :class="{ 'pda-task-list receipt-lookup-page': receiptDomain === 'customer' && !current && !result }">
<PortalHeader title="退货入库" :user="user" /> <PortalHeader title="退货入库" :user="user" />
<view class="receipt-domain-tabs" role="tablist" aria-label="退货入库类型"> <view v-if="!current && !result && !exceptionWorking" class="receipt-domain-tabs" role="tablist" aria-label="退货入库类型">
<button :class="['receipt-domain-tab', { active: receiptDomain === 'customer' }]" role="tab" :aria-selected="receiptDomain === 'customer'" :disabled="busy" @tap="switchDomain('customer')">客户退货入库</button> <button :class="['receipt-domain-tab', { active: receiptDomain === 'customer' }]" role="tab" :aria-selected="receiptDomain === 'customer'" :disabled="busy" @tap="switchDomain('customer')">客户退货入库</button>
<button :class="['receipt-domain-tab', { active: receiptDomain === 'exception' }]" role="tab" :aria-selected="receiptDomain === 'exception'" :disabled="busy" @tap="switchDomain('exception')">异常退货入库</button> <button :class="['receipt-domain-tab', { active: receiptDomain === 'exception' }]" role="tab" :aria-selected="receiptDomain === 'exception'" :disabled="busy" @tap="switchDomain('exception')">异常退货入库</button>
</view> </view>
<ExceptionReturnWork v-if="receiptDomain === 'exception'" /> <ExceptionReturnWork v-if="receiptDomain === 'exception'" @working-change="exceptionWorking = $event" />
<scroll-view v-if="receiptDomain === 'customer'" class="work-scroll" scroll-y><view class="portal-content work-content"> <scroll-view v-if="receiptDomain === 'customer'" class="work-scroll" scroll-y><view class="portal-content work-content">
<view v-if="!current && !result" class="work-card receipt-lookup-card"> <view v-if="!current && !result" class="work-card receipt-lookup-card">
<text class="card-title">扫描 SKU 69 码</text> <text class="card-title">扫描 SKU 69 码</text>
@@ -56,10 +56,8 @@
</view> </view>
</template> </template>
<view v-if="unitType === 'PALLET'" class="item-list receipt-sku-list"><view v-for="item in selectedItems" :key="item.skuCode" class="item-card"><view class="row-head"><view><text class="business-code">{{ item.skuCode }}</text><text class="meta-line">{{ item.productNameZh || '商品名称未填写' }}</text></view><text class="remaining-copy">剩余 {{ remaining(item) }}</text></view><view class="sku-quantity-fields"><view class="quantity-row"><text>数量</text><input class="number-input" type="number" :value="quantity(item.skuCode)" placeholder="0" @input="setQuantity(item, $event.detail.value)" /></view><view v-if="unitType === 'PALLET'" class="quantity-row"><text>SKU 箱数</text><input class="number-input" type="number" :value="boxCount(item.skuCode)" placeholder="0" @input="setBoxCount(item, $event.detail.value)" /></view></view></view></view></view> <view v-if="unitType === 'PALLET'" class="item-list receipt-sku-list"><view v-for="item in selectedItems" :key="item.skuCode" class="item-card"><view class="row-head"><view><text class="business-code">{{ item.skuCode }}</text><text class="meta-line">{{ item.productNameZh || '商品名称未填写' }}</text></view><text class="remaining-copy">剩余 {{ remaining(item) }}</text></view><view class="sku-quantity-fields"><view class="quantity-row"><text>数量</text><input class="number-input" type="number" :value="quantity(item.skuCode)" placeholder="0" @input="setQuantity(item, $event.detail.value)" /></view><view v-if="unitType === 'PALLET'" class="quantity-row"><text>SKU 箱数</text><input class="number-input" type="number" :value="boxCount(item.skuCode)" placeholder="0" @input="setBoxCount(item, $event.detail.value)" /></view></view></view></view></view>
<view v-if="unitType === 'PALLET'" class="summary-bar"><view><text class="summary-label">{{ unitType === 'PARCEL' ? '本次合计' : '本托合计' }}</text><text class="summary-value">{{ receiptQuantity }}</text></view><button class="primary submit-button" :disabled="!canConfirm || busy" @tap="confirmReceipt">{{ busy ? '提交中…' : unitType === 'PARCEL' ? '确认包裹签收' : '确认签收并入托' }}</button></view> <view class="summary-bar"><view><text class="summary-label">{{ unitType === 'PALLET' ? '本托合计' : '本次合计' }}</text><text class="summary-value">{{ receiptQuantity }}</text></view><view class="receipt-action-buttons"><button class="primary submit-button" :disabled="busy || !canConfirm || (unitType !== 'PALLET' && !allBoxRowsConfirmed)" @tap="confirmReceipt">{{ busy ? '提交中…' : '确认签收' }}</button><button class="secondary manual-complete" :disabled="busy" @tap="manualComplete">缺货完结</button></view></view>
<view class="work-card"><view class="row-head"><view><text class="card-title">退货打托照片</text></view><text class="status-pill">{{ photoFileIds.length }} / 20 张</text></view><button class="secondary" :disabled="busy || photoFileIds.length >= 20" @tap="choosePhoto()">拍照或从相册选择</button><view v-if="photoFileIds.length" class="photo-grid"><view v-for="(fileId,index) in photoFileIds" :key="fileId" class="photo-tile"><image class="photo-thumbnail" :src="photoUrls[fileId]" mode="aspectFill" @tap="previewPhoto(fileId)" /><text class="photo-name">{{ photoNames[index] || '退货打托照片' }}</text><button class="link-button" :disabled="busy" @tap="removePhoto(index)">移除</button></view></view></view> <view class="work-card"><view class="row-head"><view><text class="card-title">退货打托照片</text></view><text class="status-pill">{{ photoFileIds.length }} / 20 张</text></view><button class="secondary" :disabled="busy || photoFileIds.length >= 20" @tap="choosePhoto()">拍照或从相册选择</button><view v-if="photoFileIds.length" class="photo-grid"><view v-for="(fileId,index) in photoFileIds" :key="fileId" class="photo-tile"><image class="photo-thumbnail" :src="photoUrls[fileId]" mode="aspectFill" @tap="previewPhoto(fileId)" /><text class="photo-name">{{ photoNames[index] || '退货打托照片' }}</text><button class="link-button" :disabled="busy" @tap="removePhoto(index)">移除</button></view></view></view>
<view v-if="unitType !== 'PALLET'" class="summary-bar"><view><text class="summary-label">本次合计</text><text class="summary-value">{{ receiptQuantity }}</text></view><button class="primary submit-button" :disabled="busy || !canConfirm || !allBoxRowsConfirmed || !photoFileIds.length" @tap="confirmReceipt">{{ busy ? '提交中…' : '确认签收入库' }}</button></view>
<button v-if="current.status === 'PARTIALLY_RECEIVED'" class="secondary manual-complete" :disabled="busy" @tap="manualComplete">缺货手动完结</button>
<view v-if="current.completedPallets?.length" class="work-card"><text class="card-title">本单已完成打托</text><view class="item-list"><view v-for="pallet in current.completedPallets" :key="pallet.palletCode" class="item-card"><text class="business-code">{{ pallet.palletCode }}</text><text class="meta-line">{{ pallet.skuCode }} · {{ pallet.quantity }} 件</text><text class="meta-line">签收批次:{{ pallet.receiptBatchNo }}</text></view></view></view> <view v-if="current.completedPallets?.length" class="work-card"><text class="card-title">本单已完成打托</text><view class="item-list"><view v-for="pallet in current.completedPallets" :key="pallet.palletCode" class="item-card"><text class="business-code">{{ pallet.palletCode }}</text><text class="meta-line">{{ pallet.skuCode }} · {{ pallet.quantity }} 件</text><text class="meta-line">签收批次:{{ pallet.receiptBatchNo }}</text></view></view></view>
</template> </template>
@@ -82,7 +80,7 @@
export default { export default {
components: { PortalHeader, ScanTargetInput, ExceptionReturnWork }, components: { PortalHeader, ScanTargetInput, ExceptionReturnWork },
data() { return { receiptDomain: 'customer', user: session.currentUser, current: null, candidates: null, result: null, receiptResults: [], selectedSku: '', palletCheck: null, newPalletHtml: '', unitType: 'PALLET', unitCode: '', boxRows: [{ items: {}, length: '', width: '', height: '', weight: '', originalPackaging: true, confirmed: false }], palletLength: '', palletWidth: '', palletHeight: '', palletWeight: '', unitOptions: [{ value: 'PALLET', label: '托盘' }, { value: 'BOX', label: '箱子' }, { value: 'PARCEL', label: '包裹' }], photoFileIds: [], photoNames: [], photoUrls: {}, activeTarget: 'lookup', busy: false, error: null } }, data() { return { receiptDomain: 'customer', exceptionWorking: false, user: session.currentUser, current: null, candidates: null, result: null, receiptResults: [], selectedSku: '', palletCheck: null, newPalletHtml: '', unitType: 'PALLET', unitCode: '', boxRows: [{ items: {}, length: '', width: '', height: '', weight: '', originalPackaging: true, confirmed: false }], palletLength: '', palletWidth: '', palletHeight: '', palletWeight: '', unitOptions: [{ value: 'PALLET', label: '托盘' }, { value: 'BOX', label: '箱子' }, { value: 'PARCEL', label: '包裹' }], photoFileIds: [], photoNames: [], photoUrls: {}, activeTarget: 'lookup', busy: false, error: null } },
computed: { computed: {
entryMode: { get() { return warehouseWork.returnReceipt.entryMode }, set(value) { updateWarehouseWork('returnReceipt', { entryMode: value }) } }, entryMode: { get() { return warehouseWork.returnReceipt.entryMode }, set(value) { updateWarehouseWork('returnReceipt', { entryMode: value }) } },
lookupCode: { get() { return warehouseWork.returnReceipt.lookupCode }, set(value) { updateWarehouseWork('returnReceipt', { lookupCode: value }) } }, lookupCode: { get() { return warehouseWork.returnReceipt.lookupCode }, set(value) { updateWarehouseWork('returnReceipt', { lookupCode: value }) } },
@@ -143,7 +141,7 @@
printPallet() { if (!this.newPalletHtml) return; /* #ifdef H5 */ const view = window.open('', '_blank'); if (view) { view.document.write(this.newPalletHtml); view.document.close(); view.focus(); view.print() } else this.setError(new Error('请允许打开标签打印窗口'), '打印失败'); /* #endif */ /* #ifndef H5 */ this.setError(new Error('当前设备未配置打印服务'), '打印失败'); /* #endif */ }, printPallet() { if (!this.newPalletHtml) return; /* #ifdef H5 */ const view = window.open('', '_blank'); if (view) { view.document.write(this.newPalletHtml); view.document.close(); view.focus(); view.print() } else this.setError(new Error('请允许打开标签打印窗口'), '打印失败'); /* #endif */ /* #ifndef H5 */ this.setError(new Error('当前设备未配置打印服务'), '打印失败'); /* #endif */ },
printReturnCarton(label) { if (!label?.printableHtml) return; /* #ifdef H5 */ const view = window.open('', '_blank'); if (view) { view.document.write(label.printableHtml); view.document.close(); view.focus(); view.print() } else this.setError(new Error('请允许打开标签打印窗口'), '打印失败'); /* #endif */ /* #ifndef H5 */ this.setError(new Error('当前设备未配置打印服务'), '打印失败'); /* #endif */ }, printReturnCarton(label) { if (!label?.printableHtml) return; /* #ifdef H5 */ const view = window.open('', '_blank'); if (view) { view.document.write(label.printableHtml); view.document.close(); view.focus(); view.print() } else this.setError(new Error('请允许打开标签打印窗口'), '打印失败'); /* #endif */ /* #ifndef H5 */ this.setError(new Error('当前设备未配置打印服务'), '打印失败'); /* #endif */ },
acceptTracking(raw) { this.trackingNo = String(raw?.detail?.value ?? raw ?? '').trim(); playSuccessSound() }, acceptTracking(raw) { this.trackingNo = String(raw?.detail?.value ?? raw ?? '').trim(); playSuccessSound() },
async confirmReceipt() { if (this.busy) return; const totalBoxCount = this.palletBoxCount; if (this.unitType === 'PALLET' && totalBoxCount <= 0) { this.setError(new Error('请先填写各 SKU 的箱数'), '托盘签收校验失败'); return } if (!this.canConfirm || this.busy || (this.unitType !== 'PALLET' && !this.allBoxRowsConfirmed)) return; if (this.unitType !== 'PALLET' && !this.photoFileIds.length) { this.setError(new Error('请先拍照或上传签收照片,再确认签收入库'), '签收校验失败'); return } const willComplete = this.current.expectedItems.every((item) => (this.unitType !== 'PALLET' ? this.boxRows.reduce((sum, box) => sum + (Number(box.items[item.skuCode]) || 0), 0) : this.quantity(item.skuCode)) >= this.remaining(item)); if (willComplete && !this.photoFileIds.length) { const modal = await new Promise((resolve) => uni.showModal({ title: '缺少退货打托照片', content: '本次签收将完成整单入库,请先拍照并上传后再确认打托。', confirmText: '去拍照', cancelText: '取消', success: resolve })); if (modal?.confirm) this.error = { message: '请先拍照并上传退货打托照片后再确认' }; return } async confirmReceipt() { if (this.busy) return; const totalBoxCount = this.palletBoxCount; if (this.unitType === 'PALLET' && totalBoxCount <= 0) { this.setError(new Error('请先填写各 SKU 的箱数'), '托盘签收校验失败'); return } if (!this.canConfirm || this.busy || (this.unitType !== 'PALLET' && !this.allBoxRowsConfirmed)) return; const willComplete = this.current.expectedItems.every((item) => (this.unitType !== 'PALLET' ? this.boxRows.reduce((sum, box) => sum + (Number(box.items[item.skuCode]) || 0), 0) : this.quantity(item.skuCode)) >= this.remaining(item)); if (!this.photoFileIds.length && (this.unitType !== 'PALLET' || willComplete)) { uni.showModal({ title: '请先拍照', content: '请先拍照或从相册上传签收照片,再点击确认签收。', showCancel: false, confirmText: '知道了' }); return }
await this.run(async () => { await this.run(async () => {
const rows = this.unitType !== 'PALLET' ? this.boxRows : [null] const rows = this.unitType !== 'PALLET' ? this.boxRows : [null]
let expectedReceivedQuantity = this.current.expectedItems.reduce((sum, item) => sum + Number(item.receivedQuantity || 0), 0) let expectedReceivedQuantity = this.current.expectedItems.reduce((sum, item) => sum + Number(item.receivedQuantity || 0), 0)
@@ -254,13 +252,14 @@
.receipt-page :deep(.portal-header-shell){flex-shrink:0} .receipt-page :deep(.portal-header-shell){flex-shrink:0}
.receipt-page>.work-scroll{flex:1;height:0;min-height:0} .receipt-page>.work-scroll{flex:1;height:0;min-height:0}
.receipt-page .work-content{padding-bottom:calc(24px + env(safe-area-inset-bottom))} .receipt-page .work-content{padding-bottom:calc(24px + env(safe-area-inset-bottom))}
.receipt-page .summary-bar{position:static} .receipt-page .summary-bar{position:static;margin-bottom:10px}
.receipt-domain-tabs{display:flex;flex-shrink:0;gap:4px;margin:10px 14px 0;padding:4px;border:1px solid #d8e4f5;border-radius:10px;background:#e8eff9} .receipt-domain-tabs{display:flex;flex-shrink:0;gap:4px;margin:10px 14px 0;padding:4px;border:1px solid #d8e4f5;border-radius:10px;background:#e8eff9}
.receipt-domain-tab{box-sizing:border-box;flex:1;min-width:0;min-height:40px;margin:0;padding:0 8px;border-radius:7px;color:#52677f;background:transparent;font-size:14px;line-height:40px} .receipt-domain-tab{box-sizing:border-box;flex:1;min-width:0;min-height:40px;margin:0;padding:0 8px;border-radius:7px;color:#52677f;background:transparent;font-size:14px;line-height:40px}
.receipt-domain-tab::after{border:0} .receipt-domain-tab::after{border:0}
.receipt-domain-tab.active{color:#135ee8;background:#fff;font-weight:700;box-shadow:0 1px 5px rgba(28,69,121,.1)} .receipt-domain-tab.active{color:#135ee8;background:#fff;font-weight:700;box-shadow:0 1px 5px rgba(28,69,121,.1)}
.receipt-domain-tab[disabled]{opacity:.6} .receipt-domain-tab[disabled]{opacity:.6}
.manual-complete{margin-top:12px} .summary-bar>.receipt-action-buttons{display:flex;flex:1;min-width:0;gap:8px}
.receipt-action-buttons>.primary,.receipt-action-buttons>.secondary{flex:1;min-width:0;width:auto;margin:0;padding:0 6px;white-space:nowrap}
.receipt-lookup-page{background:#f1f5fd} .receipt-lookup-page{background:#f1f5fd}
.receipt-lookup-page .work-content{padding-top:14px} .receipt-lookup-page .work-content{padding-top:14px}
@@ -106,7 +106,7 @@
</template> </template>
</template> </template>
<view v-if="error" class="transfer-error" role="alert"><text class="feedback-title">操作失败</text><text>{{ error.message || error }}</text></view> <view v-if="error" class="transfer-error" role="alert"><text class="feedback-title">操作失败</text><text>{{ simpleErrorMessage(error) }}</text></view>
<view v-if="success" class="transfer-success" role="status"><text class="feedback-title">提交成功</text><text>测量与托盘打托已完成</text></view> <view v-if="success" class="transfer-success" role="status"><text class="feedback-title">提交成功</text><text>测量与托盘打托已完成</text></view>
<view v-if="completedPallets.length" class="print-card"> <view v-if="completedPallets.length" class="print-card">
<view class="photo-head"><view><text class="measure-title">新托盘标签</text><text class="measure-hint">{{ completedDestinationLabel }} · 逐托打开 PDF 后打印并粘贴</text></view></view> <view class="photo-head"><view><text class="measure-title">新托盘标签</text><text class="measure-hint">{{ completedDestinationLabel }} · 逐托打开 PDF 后打印并粘贴</text></view></view>
@@ -204,6 +204,7 @@ export default {
onHide() { this.stopScanner() }, onHide() { this.stopScanner() },
beforeUnmount() { this.stopScanner() }, beforeUnmount() { this.stopScanner() },
methods: { methods: {
simpleErrorMessage(error) { return String(error?.message || error || '操作失败,请重试').replace(/[((]\s*(?:错误码|code|requestId|traceId)\s*[::=][\s\S]*$/i, '').replace(/(?:requestId|traceId)\s*[::=][\s\S]*$/i, '').trim() || '操作失败,请重试' },
// 快照只包含业务数据;复制、批量修改或改托后会自动失效并重新展开。 // 快照只包含业务数据;复制、批量修改或改托后会自动失效并重新展开。
cartonConfirmationSignature(box) { cartonConfirmationSignature(box) {
return JSON.stringify({ pallet: String(box.transferPalletId || ''), dimensions: [box.length, box.width, box.height, box.weight].map(Number), items: box.items.map(line => [line.skuCode, Number(line.quantity)]) }) return JSON.stringify({ pallet: String(box.transferPalletId || ''), dimensions: [box.length, box.width, box.height, box.weight].map(Number), items: box.items.map(line => [line.skuCode, Number(line.quantity)]) })
+19 -9
View File
@@ -67,7 +67,7 @@ test('final photo upload waits for explicit confirmation and failed uploads cann
assert.equal(requests.length, 0) assert.equal(requests.length, 0)
await page.confirmReceipt() await page.confirmReceipt()
assert.equal(requests.length, failUpload ? 0 : 1) assert.equal(requests.length, failUpload ? 0 : 1)
if (failUpload) assert.match(page.error.message, /照片/) if (failUpload) assert.equal(page.error.message, 'upload failed')
} }
}) })
@@ -96,13 +96,23 @@ test('parcel photos accumulate without submitting until explicit receipt confirm
assert.equal(page.current, null) assert.equal(page.current, null)
}) })
test('parcel signing requires a photo even for a partial receipt', async () => { test('missing receipt photos show a reminder without submitting or adding a page error', async () => {
let requests = 0 for (const type of ['BOX', 'PARCEL', 'PALLET']) {
const page = setup(async () => { requests++; return {} }) let requests = 0
page.unitType = 'PARCEL'; page.boxRows = [physicalRow({ 'SKU-TEST': 2 })] const modals = []
await page.confirmReceipt() const page = setup(async () => { requests++; return {} }, new Map(), 'operator:warehouse', {
assert.equal(requests, 0) uni: { showModal: options => modals.push(options) }
assert.match(page.error.message, /照片/) })
page.unitType = type; page.boxRows = [physicalRow({ 'SKU-TEST': 10 })]
page.quantity = () => 10; page.remaining = () => 10
await page.confirmReceipt()
assert.equal(requests, 0)
assert.equal(modals.length, 1)
assert.match(modals[0].content, /照片/)
assert.equal(modals[0].showCancel, false)
assert.equal(page.error, undefined)
assert.ok(page.current)
}
}) })
test('editing the draft before the camera returns prevents late photo submission', async () => { test('editing the draft before the camera returns prevents late photo submission', async () => {
@@ -123,7 +133,7 @@ function setup(confirm, saved = new Map(), scope = 'operator:warehouse', runtime
const context = vm.createContext({ reactive: value => value, ReturnLabelConfirmation: {}, PortalHeader: {}, ScanTargetInput: {}, ExceptionReturnWork: {}, const context = vm.createContext({ reactive: value => value, ReturnLabelConfirmation: {}, PortalHeader: {}, ScanTargetInput: {}, ExceptionReturnWork: {},
playSuccessSound() {}, playErrorSound() {}, confirmReturnReceipt: confirm, playSuccessSound() {}, playErrorSound() {}, confirmReturnReceipt: confirm,
...runtime, ...runtime,
uni: { setStorageSync: (key, value) => saved.set(key, structuredClone(value)), getStorageSync: key => saved.get(key), removeStorageSync: key => saved.delete(key), ...runtime.uni } }) uni: { showModal() {}, setStorageSync: (key, value) => saved.set(key, structuredClone(value)), getStorageSync: key => saved.get(key), removeStorageSync: key => saved.delete(key), ...runtime.uni } })
const store = readFileSync(new URL('../src/stores/warehouse-work.js', import.meta.url), 'utf8') const store = readFileSync(new URL('../src/stores/warehouse-work.js', import.meta.url), 'utf8')
vm.runInContext(store.replace(/^import .*$/mg, '').replace(/export /g, ''), context) vm.runInContext(store.replace(/^import .*$/mg, '').replace(/export /g, ''), context)
const page = readFileSync(new URL('../src/pages/return-receipt/return-receipt.vue', import.meta.url), 'utf8') const page = readFileSync(new URL('../src/pages/return-receipt/return-receipt.vue', import.meta.url), 'utf8')
@@ -300,3 +300,9 @@ test('新增预报箱无SKU绑定时恢复为可编辑箱,保留已有草稿',
assert.ok(added) assert.ok(added)
assert.ok(value.declaredSkuCodes.includes(added.items[0].skuCode)) assert.ok(value.declaredSkuCodes.includes(added.items[0].skuCode))
}) })
test('warehouse transfer errors show guidance without diagnostic identifiers', () => {
const { value: page } = setup()
assert.equal(page.simpleErrorMessage({message:'该单为仓库上门取货,请先完成车辆取货送仓\nrequestId: request-1'}), '该单为仓库上门取货,请先完成车辆取货送仓')
assert.equal(page.simpleErrorMessage({message:'操作失败(错误码:S0503;requestId:request-1;traceId:trace-1)'}), '操作失败')
})