409 lines
27 KiB
JavaScript
409 lines
27 KiB
JavaScript
import assert from 'node:assert/strict'
|
||
import { readFileSync } from 'node:fs'
|
||
import test from 'node:test'
|
||
|
||
const view = readFileSync(new URL('./WarehouseServiceView.vue', import.meta.url), 'utf8')
|
||
const api = readFileSync(new URL('../api/warehouseServices.ts', import.meta.url), 'utf8')
|
||
|
||
test('贴标总文件与关联模板保持左右分组,退货来源使用专用明细', () => {
|
||
assert.match(view, /class="warehouse-file-groups(?:\s[^"]*)?"/)
|
||
assert.match(view, /\.warehouse-file-groups--compact\s*\{[^}]*grid-template-columns:\s*minmax\(0, 1fr\) minmax\(0, 1fr\)/)
|
||
assert.match(view, /v-if="isReturnRelabelSource" class="warehouse-table-scroll"/)
|
||
assert.match(view, /warehouse-service-page--return-relabel/)
|
||
assert.match(view, /const sourceValue = `RETURN_ORDER:\$\{requestedReturnNo\}`/)
|
||
})
|
||
|
||
test('仓储转运先选择入仓方式并按方式切换地址信息', () => {
|
||
assert.match(view, /value="WAREHOUSE_PICKUP">仓库上门提货/)
|
||
assert.match(view, /value="CUSTOMER_DELIVERY">客户送货到仓/)
|
||
assert.match(view, /form\.deliveryMethod === 'WAREHOUSE_PICKUP'.*提货地址/s)
|
||
assert.match(view, /form\.deliveryMethod === 'CUSTOMER_DELIVERY'.*送货地址.*收货联系人.*联系电话/s)
|
||
assert.match(view, /getMerchantWarehouseDetail\(form\.warehouse\)/)
|
||
})
|
||
|
||
test('仓储转运支持无目的地、FBA 仓和私人仓并显式选择是否换标', () => {
|
||
assert.match(view, />目的去向</)
|
||
assert.match(view, /value="NONE">暂未确定/)
|
||
assert.match(view, /value="FBA">FBA 仓/)
|
||
assert.match(view, /value="PRIVATE">私人仓/)
|
||
assert.match(view, /transferDestinationType === 'PRIVATE'.*私人仓地址.*邮编.*私人仓联系人.*联系电话/s)
|
||
assert.match(view, />是否贴标</)
|
||
assert.match(view, /:value="false">不需要贴标/)
|
||
assert.match(view, /:value="true">需要贴标/)
|
||
assert.doesNotMatch(view, /v-model="form\.relabel" disabled/)
|
||
assert.doesNotMatch(view, /value === 'FBA'\) form\.relabel = true/)
|
||
assert.doesNotMatch(view, /value === 'PRIVATE'.*form\.relabel = false/)
|
||
assert.match(view, /v-if="props\.service === 'transfer' && form\.relabel" class="warehouse-card warehouse-form-section warehouse-transfer-relabel"/)
|
||
assert.match(api, /fbaWarehouseCode\?: string/)
|
||
assert.match(api, /privateDestinationAddress\?: string; privateDestinationPostalCode\?: string/)
|
||
assert.match(api, /fbaShipmentNo\?: string/)
|
||
assert.doesNotMatch(view, /换标费用(CNY)/)
|
||
assert.doesNotMatch(view, /relabelChargeAmount:/)
|
||
})
|
||
|
||
test('换标详情待客户确认时提供确认入口并刷新详情', () => {
|
||
assert.match(view, /application\.status === 'CUSTOMER_CONFIRM_PENDING'[\s\S]*@click="confirmSelectedRelabel">确认换标完成/)
|
||
assert.match(view, /async function confirmSelectedRelabel\(\)[\s\S]*openCompletionConfirmation\(relabelNo, 'labeling'\)/)
|
||
assert.match(view, /async function refreshAfterCompletion\(no: string\)[\s\S]*await openDetail\(\{ '0': no \}\)/)
|
||
})
|
||
|
||
test('仓储转运换标绑定明细自动同步只读的旧 SKU', () => {
|
||
assert.match(view, /watch\(\(\) => cargoRows\.value\.map\(\(row\) => row\.sku\)/)
|
||
assert.match(view, /if \(sourceSku\) row\.sku = sourceSku/)
|
||
assert.match(view, /transferRelabelRows\.value\.push\(\{ \.\.\.createCargoRow\(\), sku: source\?\.sku \|\| '' \}\)/)
|
||
})
|
||
|
||
test('仓储转运换标整票只允许一个目的仓', () => {
|
||
assert.match(view, /props\.service === 'transfer' && transferDestinationType === 'FBA'[^\n]+FBA 目的仓/)
|
||
assert.match(view, /FBA 货件编号<\/span><el-input v-model="form\.fbaShipmentNo" placeholder=""/)
|
||
assert.match(view, /transferDestinationType\.value === 'FBA' && !form\.destination/)
|
||
assert.match(view, /transferDestinationType\.value === 'PRIVATE'.*!form\.privateDestinationPostalCode/)
|
||
assert.match(view, /整票换标货物目的 FBA 仓/)
|
||
assert.match(view, /if \(!transferRelabelDefaultDestination\.value\) \{ ElMessage\.warning\('请选择整票换标货物的 FBA 目的仓'\)/)
|
||
assert.match(view, /destinationWarehouseCode: transferRelabelDefaultDestination\.value \|\| undefined/)
|
||
const transferRelabelSection = view.split('warehouse-transfer-relabel">')[1]?.split('warehouse-transfer-submit-bar')[0] || ''
|
||
assert.doesNotMatch(transferRelabelSection, /v-model="row\.destinationWarehouseId"/)
|
||
assert.doesNotMatch(transferRelabelSection, /<th>FBA 目的仓 \*<\/th>/)
|
||
assert.doesNotMatch(view, /applyTransferRelabelDestination/)
|
||
assert.match(view, /destinationWarehouseId: binding\.destinationWarehouseCode \|\| ''/)
|
||
assert.match(view, /props\.service === 'transfer' \? '客户箱唛号' : '仓库唛头'/)
|
||
assert.match(view, /已导入 \$\{importedRows\.length\} 条仓储转运换标明细/)
|
||
assert.doesNotMatch(transferRelabelSection, /新 FBA 箱唛<\/th><th>FBA 目的仓<\/th>/)
|
||
assert.match(view, /const includeDestination = false/)
|
||
})
|
||
|
||
test('仓储转运不要求客户填写内部入仓号和我方箱唛,但换标时填写客户箱唛', () => {
|
||
const transferConfig = view.match(/transfer:\s*\{[^\n]+/)?.[0] || ''
|
||
const transferSubmit = view.match(/const payload: TransferCreate = \{[^\n]+/)?.[0] || ''
|
||
assert.doesNotMatch(transferConfig, /进仓编号/)
|
||
assert.doesNotMatch(transferSubmit, /inboundCode|sourceLastlegOrderIds/)
|
||
assert.match(view, /货物明细/)
|
||
assert.match(view, /仓库唛头 \*/)
|
||
assert.match(view, /downloadTransferCartonMarkTemplate/)
|
||
assert.match(view, /importTransferCartonMarks/)
|
||
assert.match(view, /<strong>SKU 关联<\/strong>/)
|
||
assert.match(view, /<strong>箱号关联<\/strong>/)
|
||
assert.match(view, /<strong>SKU 混箱<\/strong>/)
|
||
assert.match(view, />下载模板<\/el-button>/)
|
||
assert.match(view, />上传文件<\/el-button>/)
|
||
assert.match(view, /换标类型/)
|
||
assert.match(view, /v-if="labelingMode === 'carton'"/)
|
||
assert.match(view, /v-else-if="labelingMode === 'sku'"/)
|
||
assert.match(view, /v-else class="warehouse-table-scroll"/)
|
||
assert.match(view, /添加 SKU 明细/)
|
||
assert.match(view, /绑定明细/)
|
||
assert.match(view, /旧 SKU \*.*新 SKU \*.*换标数量(件)\*.*新 FBA 箱唛 \*.*备注/)
|
||
assert.match(transferSubmit, /fbaBoxNos: customerCartonMarks/)
|
||
assert.match(transferSubmit, /shippingMark: transferCustomerMarks\(item\)/)
|
||
assert.match(transferSubmit, /relabelItems: form\.relabel/)
|
||
assert.match(view, /props\.service === 'disposal' \? '本次废弃箱数' : '预计箱数'/)
|
||
assert.match(view, /<th v-if="props\.service === 'relabel'">FNSKU \/ 箱唛<\/th>/)
|
||
assert.doesNotMatch(view, /<th v-if="props\.service === 'transfer'">FNSKU \/ 箱唛<\/th>/)
|
||
})
|
||
|
||
test('仓储转运填写货物即可打印,保存或提交保留已打印箱号', () => {
|
||
assert.doesNotMatch(view, /printTransferDraftCartonMarks|CT-\$\{batch\}/)
|
||
assert.match(view, /getTransferCartonLabel\(transferNo\)/)
|
||
assert.match(view, /打印预报箱唛/)
|
||
assert.match(view, /@click="printForecastCartons"/)
|
||
assert.match(view, /cartonMarks: item.generatedCartonMarks/)
|
||
})
|
||
|
||
test('仓储转运换标资料按步骤分组展示', () => {
|
||
assert.match(view, /<span v-if="props\.service === 'transfer'" class="warehouse-step-number">1<\/span>货物明细/)
|
||
assert.match(view, /<span class="warehouse-step-number">2<\/span>换标申请/)
|
||
assert.match(view, /<strong><span>3<\/span>明细关联模板<\/strong>/)
|
||
assert.match(view, /<span class="warehouse-step-number">4<\/span>绑定明细/)
|
||
assert.match(view, /warehouse-transfer-template-group/)
|
||
assert.match(view, /warehouse-transfer-relabel/)
|
||
})
|
||
|
||
test('仓储转运需要换标时上传总文件并挂到关联换标单', () => {
|
||
const transferRelabelSection = view.split('warehouse-transfer-relabel">')[1]?.split('warehouse-transfer-submit-bar')[0] || ''
|
||
assert.match(transferRelabelSection, /warehouse-transfer-total-files/)
|
||
assert.match(transferRelabelSection, />贴标总文件</)
|
||
assert.match(transferRelabelSection, />箱唛总文件</)
|
||
assert.match(transferRelabelSection, />SKU 总文件</)
|
||
assert.match(view, /action === 'submit' && requiresBothTotalFiles\.value/)
|
||
assert.match(view, /const submitted = await submitTransfer\(transferNo\)/)
|
||
assert.match(view, /submitted\.relabelNo \|\| created\.relabelNo/)
|
||
assert.match(view, /uploadRelabelFile\(relabelNo, 'CARTON_TOTAL', cartonTotalFile\.value\)/)
|
||
assert.match(view, /uploadRelabelFile\(relabelNo, 'SKU_TOTAL', skuTotalFile\.value\)/)
|
||
assert.match(view, /转运单已提交,附件待补传/)
|
||
assert.match(transferRelabelSection, /native-type="button"[^>]+chooseCreateTotalFile\('CARTON_TOTAL'\)/)
|
||
assert.match(transferRelabelSection, /native-type="button"[^>]+chooseCreateTotalFile\('SKU_TOTAL'\)/)
|
||
})
|
||
|
||
test('仓储转运换标总文件与明细模板在桌面端左右排列', () => {
|
||
assert.match(view, /class="warehouse-transfer-file-groups(?:\s[^"]*)?"/)
|
||
assert.match(view, /\.warehouse-transfer-file-groups\{display:grid;grid-template-columns:minmax\(0,1\.15fr\) minmax\(360px,\.85fr\)/)
|
||
assert.match(view, /\.warehouse-transfer-total-files,\.warehouse-transfer-template-group\{height:100%;margin:0\}/)
|
||
assert.match(view, /@media\(max-width:1180px\)\{\.warehouse-transfer-file-groups\{grid-template-columns:minmax\(0,1fr\)\}\}/)
|
||
})
|
||
|
||
test('上门提货不提交物流号,需要换标时随转运单登记申请', () => {
|
||
assert.match(view, /trackingNo:\s*!inventoryTransfer\.value && form\.deliveryMethod === 'CUSTOMER_DELIVERY'\s*\?[^:]+:\s*undefined/)
|
||
assert.match(view, /relabelItems: form\.relabel/)
|
||
assert.match(view, /form\.deliveryMethod === 'CUSTOMER_DELIVERY'.*物流跟踪号/s)
|
||
assert.match(view, /提货联系人/)
|
||
assert.match(view, /联系人电话/)
|
||
assert.match(view, /换标联系人/)
|
||
assert.match(view, /form\.pickupContact/)
|
||
assert.match(view, /form\.pickupPhone/)
|
||
assert.match(view, /form\.relabelContact/)
|
||
assert.match(view, /form\.relabelPhone/)
|
||
assert.match(view, /pickupContactName: !inventoryTransfer\.value && form\.deliveryMethod === 'WAREHOUSE_PICKUP' \? form\.pickupContact : undefined/)
|
||
assert.match(view, /pickupContactPhone: !inventoryTransfer\.value && form\.deliveryMethod === 'WAREHOUSE_PICKUP' \? form\.pickupPhone : undefined/)
|
||
assert.match(view, /relabelContactName: form\.relabel \? form\.relabelContact/)
|
||
assert.match(api, /pickupContactName\?: string; pickupContactPhone\?: string/)
|
||
})
|
||
|
||
test('仓储转运列表操作仓使用海外仓接口数据', () => {
|
||
assert.match(view, /loadAllWarehouseRecords\('OVERSEAS', getMerchantWarehouses\)/)
|
||
assert.match(view, /warehouseDisplay\(item\.operatingWarehouseId\)/)
|
||
assert.match(view, /\['OVERSEAS', 'OVERSEAS_PARTNER'\]/)
|
||
assert.match(view, /props\.service === 'relabel' \? fbaWarehouses\.value : operationWarehouses\.value/)
|
||
assert.doesNotMatch(view, /美西洛杉矶仓/)
|
||
})
|
||
|
||
test('仓储转运期望发货时间可选并在订单概览回填发货时间', () => {
|
||
assert.doesNotMatch(view, /预计发货时间/)
|
||
assert.match(view, /期望发货时间/)
|
||
assert.match(view, /v-model="form\.estimatedShipAt"/)
|
||
assert.match(view, /v-model="form\.estimatedShipAt"[^>]+placeholder=""/)
|
||
assert.doesNotMatch(view, /!form\.estimatedShipAt/)
|
||
assert.match(view, /estimatedShipAt: form\.estimatedShipAt/)
|
||
assert.match(view, /<span>期望发货时间<\/span><strong>\{\{ formatDateTime\(selectedDetail\?\.estimatedShipAt\) \}\}<\/strong>/)
|
||
assert.match(view, /<span>实际发货时间<\/span><strong>\{\{ formatDateTime\(selectedDetail\?\.actualShipAt\) \}\}<\/strong>/)
|
||
assert.doesNotMatch(view, /class="warehouse-card warehouse-form-section warehouse-transfer-times"/)
|
||
assert.match(view, /estimatedArrivalAt: detail\.estimatedArrivalAt \|\| '', estimatedShipAt: detail\.estimatedShipAt \|\| ''/)
|
||
assert.match(api, /estimatedShipAt\?: string/)
|
||
})
|
||
|
||
test('客户仓储转运展示每个实际流转状态的中文名称', () => {
|
||
assert.match(view, /label: '草稿', value: 'DRAFT'/)
|
||
assert.match(view, /label: '待审核', value: 'PENDING_REVIEW'/)
|
||
assert.match(view, /label: '入库测量中', value: 'INBOUND_MEASURING'/)
|
||
assert.match(view, /label: '待客户确认实测', value: 'WAIT_CUSTOMER_CONFIRMATION'/)
|
||
assert.match(view, /label: '待确认目的地', value: 'WAIT_FBA_DESTINATION'/)
|
||
assert.match(view, /label: '待排车', value: 'READY_FOR_DISPATCH'/)
|
||
assert.match(view, /WAIT_OUTBOUND: '待出库'/)
|
||
assert.match(view, /OUTBOUNDED: '已出库'/)
|
||
})
|
||
|
||
test('仓储转运列表展示换标单号、换标状态并为两类状态着色', () => {
|
||
const transferConfig = view.match(/transfer:\s*\{[^\n]+/)?.[0] || ''
|
||
assert.match(transferConfig, /'是否换标', '换标单号', '换标状态', '状态'/)
|
||
assert.match(api, /relabelNo\?: string; relabelStatus\?: string; relabelFulfillmentStatus\?: string/)
|
||
assert.match(view, /item\.needRelabel \? '是' : '否', item\.relabelNo, relabelStatus\.label/)
|
||
assert.match(view, /if \(!item\.relabelNo\) return \{ code: 'WAIT_RELABEL', label: '待换标' \}/)
|
||
assert.match(view, /READY_FOR_OUTBOUND: '已换标', COMPLETED: '已换标'/)
|
||
assert.match(view, /#transferRelabelStatus=.*transferRelabelStatusTagType/)
|
||
assert.match(view, /#transferStatus=.*transferStatusTagType/)
|
||
assert.doesNotMatch(view, /是 · 待绑定换标单/)
|
||
})
|
||
|
||
test('仓储转运详情订单概览使用详情接口命名字段回填', () => {
|
||
assert.match(view, /v-else-if="props\.service === 'transfer'" class="warehouse-detail-grid warehouse-transfer-overview-grid"/)
|
||
assert.doesNotMatch(view, /入库箱数/)
|
||
assert.match(view, /'转运单号', '预计箱数', '海外仓'/)
|
||
for (const field of ['transferNo', 'packageCount', 'operatingWarehouseId', 'deliveryMethod', 'needRelabel', 'relabelNo', 'status', 'createdAt']) {
|
||
assert.match(view, new RegExp(`selectedDetail\\?\\.${field}`))
|
||
}
|
||
assert.match(view, /selectedDetail\?\.destinationWarehouseCode \|\| selectedDetail\?\.fbaWarehouseCode/)
|
||
assert.match(view, /transferRelabelStatus\(selectedDetail \|\| \{\}\)/)
|
||
assert.match(view, /transferStatusTagType\(selectedDetail\?\.status \|\| ''\)/)
|
||
})
|
||
|
||
test('仓储转运和贴标申请详情先展示主数据再串行补充仓库名称', () => {
|
||
const loader = view.match(/async function loadDetailPage\(\) \{[\s\S]*?\n\}/)?.[0] || ''
|
||
assert.match(loader, /await openDetail\(\{ '0': detailNumber\.value \}\)/)
|
||
assert.match(loader, /await loadWarehouses\(\)/)
|
||
assert.ok(loader.indexOf('await openDetail') < loader.indexOf('await loadWarehouses'))
|
||
assert.match(view, /props\.service === 'labeling' \? await getRelabel\(value\['0'\]\)/)
|
||
assert.match(view, /: props\.service === 'disposal' \? await getDiscard\(value\['0'\]\) : await getTransfer\(value\['0'\]\)/)
|
||
})
|
||
|
||
test('仓储转运详情展示目的去向和对应目的仓资料并让货物明细铺满', () => {
|
||
assert.match(view, />目的去向<\/span><strong>\{\{ destinationTypeLabel\(selectedDetail\?\.destinationType, selectedDetail\?\.fbaWarehouseCode\) \}\}/)
|
||
assert.match(view, />FBA 目的仓<\/span>.*selectedDetail\?\.destinationWarehouseCode \|\| selectedDetail\?\.fbaWarehouseCode/)
|
||
assert.match(view, />FBA 货件号<\/span><strong>\{\{ selectedDetail\?\.fbaShipmentNo \|\| '—' \}\}/)
|
||
for (const field of ['privateDestinationAddress', 'privateDestinationPostalCode', 'privateDestinationContactName', 'privateDestinationContactPhone']) {
|
||
assert.match(view, new RegExp(`selectedDetail\\?\\.${field}`))
|
||
}
|
||
assert.match(view, /warehouse-service-page--detail \.warehouse-transfer-cargo-card \.warehouse-section-heading,[^}]+\.warehouse-table-scroll\{max-width:none\}/)
|
||
})
|
||
|
||
test('仓储转运订单概览使用紧凑左右信息布局', () => {
|
||
assert.match(view, /warehouse-detail-grid warehouse-transfer-overview-grid/)
|
||
assert.match(view, /warehouse-transfer-overview-grid"><div><span>状态<\/span>.*<span>目的去向<\/span>/)
|
||
assert.match(view, /class="warehouse-overview-wide"><span>私人仓地址/)
|
||
assert.match(view, /warehouse-transfer-overview-grid>\.warehouse-overview-wide\{grid-column:span 2\}/)
|
||
assert.match(view, /warehouse-transfer-overview-grid>div\{min-height:26px;padding:2px 0;border:0\}/)
|
||
assert.match(view, /warehouse-transfer-overview-grid span\{flex:0 0 auto;min-width:76px\}/)
|
||
assert.match(view, /warehouse-transfer-overview-grid\{grid-template-columns:1fr;gap:4px/)
|
||
})
|
||
|
||
test('贴标申请详情使用紧凑订单概览并中文展示换标状态', () => {
|
||
assert.match(view, /WAIT_APPROVAL: '待审核'/)
|
||
assert.match(view, /WAIT_PROCESSING: '待仓库处理'/)
|
||
assert.match(view, /relabelFulfillmentLabel\(selectedRelabelDetail\?\.application\.fulfillmentStatus\)/)
|
||
assert.match(view, />\.warehouse-detail-header\+\.warehouse-card \.warehouse-detail-grid\{grid-template-columns:repeat\(4,minmax\(180px,1fr\)\)/)
|
||
})
|
||
|
||
test('仓储转运详情按接口具名字段展示订单概览', () => {
|
||
const overview = view.split('<h3>订单概览</h3>')[1]?.split('warehouse-transfer-cargo-card')[0] || ''
|
||
assert.match(overview, /v-if="props\.service === 'transfer'"/)
|
||
assert.doesNotMatch(overview, /<span>转运单号<\/span>/)
|
||
assert.match(view.split('<header class="warehouse-detail-header">')[1]?.split('</header>')[0] || '', /selectedDetail\?\.transferNo/)
|
||
assert.match(overview, /selectedDetail\?\.packageCount \?\? '—'/)
|
||
assert.match(overview, /warehouseDisplay\(selectedDetail\?\.operatingWarehouseId\)/)
|
||
assert.match(overview, /selectedDetail\?\.destinationWarehouseName \|\| warehouseDisplay\(selectedDetail\?\.destinationWarehouseCode \|\| selectedDetail\?\.fbaWarehouseCode\)/)
|
||
assert.match(overview, /deliveryMethodLabel\(selectedDetail\?\.deliveryMethod \|\| ''\)/)
|
||
assert.match(overview, /statusLabel\(selectedDetail\?\.status \|\| ''\)/)
|
||
assert.match(overview, /formatDateTime\(selectedDetail\?\.createdAt\)/)
|
||
})
|
||
|
||
test('PDA 打托完成后客户可从列表或详情确认并查看实测数据', () => {
|
||
assert.match(view, /item\.__status === 'WAIT_CUSTOMER_CONFIRMATION'/)
|
||
assert.match(view, /confirmTransferFromList\(item\['0'\]\)/)
|
||
assert.match(view, /selectedDetail\?\.status === 'WAIT_CUSTOMER_CONFIRMATION'/)
|
||
assert.match(view, /PDA 打托实测数据/)
|
||
for (const label of ['托盘号', '库位', '箱数', 'SKU 汇总', '毛重(kg)', '体积(m³)', '完成时间']) assert.equal(view.includes(label), true)
|
||
assert.match(view, /pallet\.warehouseLocationCode/)
|
||
assert.match(view, /palletCartons\(pallet\)\.length/)
|
||
assert.match(view, /pallet\.grossWeightKg/)
|
||
assert.match(view, /pallet\.volumeCbm/)
|
||
assert.doesNotMatch(view, /pallet\.items/)
|
||
})
|
||
|
||
test('仓储转运详情按订单概览、货物预报、PDA 实测数据排序并放大测量照片', () => {
|
||
const detailStart = view.indexOf('<header class="warehouse-detail-header">')
|
||
const detailSource = view.slice(detailStart)
|
||
const overviewIndex = detailSource.indexOf('<h3>订单概览</h3>')
|
||
const measurementIndex = detailSource.indexOf('<h3>PDA 打托实测数据</h3>')
|
||
const cargoIndex = detailSource.indexOf('<h3>预报与实际签收</h3>')
|
||
assert.ok(overviewIndex >= 0 && overviewIndex < measurementIndex)
|
||
assert.ok(cargoIndex < measurementIndex)
|
||
assert.match(view, /class="warehouse-photo-grid warehouse-measurement-photo-grid"/)
|
||
assert.match(view, /class="warehouse-photo-item warehouse-measurement-photo-item"/)
|
||
assert.match(view, /warehouse-measurement-photo-grid\{flex:1;grid-template-columns:repeat\(auto-fill,minmax\(240px,1fr\)\)\}/)
|
||
assert.match(view, /warehouse-measurement-photo-item\{width:100%;height:120px\}/)
|
||
})
|
||
|
||
test('仓储转运详情自动加载 PDA 测量照片并释放 Blob URL', () => {
|
||
assert.match(api, /downloadTransferMeasurementPhoto/)
|
||
assert.match(api, /measurement-photos\/files\/\$\{encodeURIComponent\(fileId\)\}\/download/)
|
||
assert.match(view, /measurementPhotos\?: TransferMeasurementPhoto\[\]/)
|
||
assert.match(view, /fileId: string \| number/)
|
||
assert.match(view, /if \(props\.service === 'transfer'\) void loadMeasurementPhotos\(\)/)
|
||
assert.match(view, /测量打托现场照片/)
|
||
assert.match(view, /:preview-src-list="measurementPhotoPreviewUrls"/)
|
||
assert.match(view, /加载失败,点击重试/)
|
||
assert.match(view, /URL\.createObjectURL\(blob\)/)
|
||
assert.match(view, /URL\.revokeObjectURL\(url\)/)
|
||
assert.match(view, /onBeforeUnmount\(\(\) => \{ clearCompletionPhotos\(\); clearMeasurementPhotos\(\); clearDiscardPhotos\(\) \}\)/)
|
||
})
|
||
|
||
test('PDA 完成后主单显示入库完成并保留客户确认测量入口', () => {
|
||
assert.match(view, /item\.__status === 'WAIT_CUSTOMER_CONFIRMATION'.*确认测量/s)
|
||
assert.match(view, /selectedDetail\?\.status === 'WAIT_CUSTOMER_CONFIRMATION'.*确认测量数据/s)
|
||
assert.doesNotMatch(view, /确认实测并入库/)
|
||
})
|
||
|
||
test('仓储转运可在新建页直接提交,也可保存草稿后编辑提交', () => {
|
||
assert.match(api, /function submitTransfer\(transferNo: string\)/)
|
||
assert.match(api, /function updateTransfer\(transferNo: string, payload: TransferCreate\)/)
|
||
assert.match(api, /warehouse-transfers\/\$\{encodeURIComponent\(transferNo\)\}\/save-draft/)
|
||
assert.match(api, /warehouse-transfers\/\$\{encodeURIComponent\(transferNo\)\}\/submit/)
|
||
assert.match(view, /submit\('draft'\).*保存草稿/s)
|
||
assert.match(view, /async function openEdit\(transferNo: string\)/)
|
||
assert.match(view, /\['DRAFT', 'REJECTED'\]\.includes\(item\.__status\).*openEdit\(item\['0'\]\)/s)
|
||
assert.match(view, /\['DRAFT', 'REJECTED'\]\.includes\(detail\.status \|\| ''\)/)
|
||
assert.match(view, /\['DRAFT', 'REJECTED'\]\.includes\(selectedDetail\?\.status \|\| ''\)/)
|
||
assert.match(view, /v-if="props\.service === 'transfer'"[^>]*type="primary"[^>]*native-type="submit"[^>]*>提交订单/)
|
||
assert.match(view, /await updateTransfer\(editingTransferNo\.value, payload\)/)
|
||
assert.match(view, /await submitTransfer\(transferNo\)/)
|
||
assert.match(view, /<form [^>]*@submit\.prevent="submit\('submit'\)"/)
|
||
assert.match(view, /selectedDetail\?\.status !== 'DRAFT'[^>]*[\s\S]*?printTransferCartons[^>]*[\s\S]*?打印预报箱唛/)
|
||
assert.doesNotMatch(view, /row\.__status !== 'DRAFT'.*printTransferCartons\(row\['0'\]\)/s)
|
||
assert.doesNotMatch(view, /selectedDetail\?\.status === 'DRAFT'[^>]*[\s\S]*?>提交订单/)
|
||
assert.match(view, /native-type="button"[^>]*:loading="saving"[^>]*@click="submit\('draft'\)"/)
|
||
assert.match(view, /DRAFT: '草稿'/)
|
||
assert.doesNotMatch(view, /<h3>箱唛明细<\/h3>/)
|
||
})
|
||
|
||
test('编辑仓储转运时加载库存转运来源候选', () => {
|
||
assert.match(view, /async function loadTransferInventoryCandidates\(warehouseId: string\)/)
|
||
assert.match(view, /if \(props\.service === 'transfer' && form\.warehouse\) \{[\s\S]*await loadTransferInventoryCandidates\(form\.warehouse\)/)
|
||
assert.match(view, /transferInventoryCandidates\.value = \(await listRelabelInventoryCandidates\(warehouseId\)\)\.filter/)
|
||
assert.match(view, /transferInventoryOptions\.value\.some\(\(option\) => option\.value === sourceInboundCode\)/)
|
||
assert.match(view, /selectedTransferInventory\.value = sourceInboundCode/)
|
||
assert.match(view, /detail\.sourceOrders \|\| \[\]/)
|
||
})
|
||
|
||
test('仓储转运来源订单雪花 ID 按字符串传递,避免 Number 精度丢失', () => {
|
||
assert.match(view, /const selectedTransferSourceOrderIds = ref<string\[\]>\(\[\]\)/)
|
||
assert.match(view, /historical\.map\(\(item\) => String\(item\.id \|\| ''\)\)/)
|
||
assert.match(api, /sourceLastlegOrderIds\?: string\[\]/)
|
||
assert.doesNotMatch(view, /sourceLastlegOrderIds[\s\S]{0,160}Number\(/)
|
||
})
|
||
|
||
test('转运贴标单在PDA确认库存前不误报附件上传失败', () => {
|
||
assert.match(view, /if \(!relabelNo\) \{[\s\S]*PDA 入库确认后将自动生成关联换标单/)
|
||
assert.match(view, /届时请进入关联换标单详情上传贴标总文件/)
|
||
assert.doesNotMatch(view, /if \(!relabelNo\) throw new Error\('转运单已提交,但未返回关联换标单号'\)/)
|
||
})
|
||
|
||
test('仓储转运基础货物不强制 SKU 和中文品名,只换箱唛不强制旧 SKU', () => {
|
||
assert.match(view, /商品 SKU\{\{ props\.service === 'transfer' \? '' : ' \*' \}\}/)
|
||
assert.match(view, /中文品名\{\{ props\.service === 'transfer' \? '' : ' \*' \}\}/)
|
||
assert.match(view, /props\.service === 'relabel' \? '请输入商品 SKU' : ''/)
|
||
assert.match(view, /v-if="labelingMode === 'carton'"[^\n]+<th>旧 SKU<\/th>/)
|
||
assert.match(view, /labelingMode\.value !== 'carton' && \(!row\.sku\.trim\(\) \|\| !row\.newSkuCode\.trim\(\)\)/)
|
||
assert.match(api, /skuCode\?: string; productNameZh\?: string/)
|
||
assert.match(api, /originalSku\?: string/)
|
||
})
|
||
|
||
test('SKU 件数和预计箱数独立提交,签收展示实际清点箱数', () => {
|
||
assert.match(view, /quantity: item.quantity, packageCount: Number\(item.expectedPackageCount\)/)
|
||
assert.match(view, /sum \+ Number\(item.expectedPackageCount \|\| 0\)/)
|
||
assert.match(view, /v-model="row.expectedPackageCount"/)
|
||
assert.match(view, /Number.isSafeInteger\(row.quantity\)/)
|
||
assert.match(view, /Number.isSafeInteger\(row.expectedPackageCount\)/)
|
||
assert.match(view, /\['COUNTED', 'DISCARD_PENDING', 'DISCARDED', 'SHIPPED'\]\.includes\(carton.status\)/)
|
||
assert.match(view, /实际签收箱数/)
|
||
})
|
||
|
||
test('转运客户详情保留预报并显示实际签收箱内明细和托盘汇总', () => {
|
||
for (const label of ['预报数量(件)', '预报 SKU 种数', '签收箱号明细', '查看箱号明细', 'SKU 汇总', '毛重(kg)', '体积(m³)']) assert.ok(view.includes(label), label)
|
||
assert.match(view, /countedTransferCartons\(\)\.filter\(\(carton\) => pallet.id != null/)
|
||
assert.match(view, /String\(carton.transferPalletId\) === String\(pallet.id\)/)
|
||
assert.match(view, /carton.transferItemId != null && String\(item.id\) === String\(carton.transferItemId\)/)
|
||
assert.match(view, /@click="showTransferCartons = true"/)
|
||
assert.match(view, /<el-dialog v-model="showTransferCartons"[\s\S]*?<el-collapse-item v-for="carton in countedTransferCartons\(\)"/)
|
||
assert.doesNotMatch(view, /warehouse-transfer-receipt-summary|expandedTransferCartons/)
|
||
const receiptSection = view.slice(view.indexOf('warehouse-transfer-received-card', view.indexOf('<header class="warehouse-detail-header">')), view.indexOf('v-if="props.service === \'transfer\' && selectedDetail?.needRelabel"'))
|
||
assert.doesNotMatch(receiptSection.split('<el-dialog')[0], /<table|<el-table|<el-collapse/)
|
||
|
||
assert.match(view, /暂无实际签收箱,等待 PDA 清点/)
|
||
assert.doesNotMatch(view, /<td>\{\{ \[pallet.lengthCm/)
|
||
})
|
||
|
||
|
||
test('预报实收同区对照、托盘卡片换行、签收按钮紧邻标题', () => {
|
||
const start = view.indexOf('class="warehouse-card warehouse-form-section warehouse-transfer-cargo-card"', view.indexOf('<header class="warehouse-detail-header">'))
|
||
const section = view.slice(start, view.indexOf('warehouse-transfer-received-card', start))
|
||
assert.ok(section.includes('预报与实际签收'))
|
||
assert.ok(section.includes('PDA 打托实测数据'))
|
||
assert.ok(section.includes('receivedItemQuantity(item.id)'))
|
||
assert.ok(section.includes('receivedItemCartons(item.id).length'))
|
||
assert.ok(section.includes('class="warehouse-transfer-pallet-card"'))
|
||
assert.ok(section.includes('class="warehouse-transfer-pallet-sku"'))
|
||
assert.doesNotMatch(section, /打印箱唛/)
|
||
const receipt = view.slice(view.indexOf('warehouse-transfer-received-card', start)).split('<el-dialog')[0]
|
||
assert.ok(view.includes('打印预报箱唛')); assert.ok(view.includes('增加预报箱数'))
|
||
assert.ok(receipt.includes('查看箱号明细'))
|
||
assert.match(view, /warehouse-section-heading h3\{flex:0 0 auto/)
|
||
})
|