优化样式
This commit is contained in:
@@ -31,6 +31,14 @@ function harness(kind = 'disposal', overrides = {}) {
|
||||
return { ...state, props, calls, events, revoked }
|
||||
}
|
||||
|
||||
test('仓储转运客户确认测量弹窗不展示箱子明细和托盘尺寸', () => {
|
||||
assert.doesNotMatch(source, /<el-table :data="measurement\.cartons\?\.filter\(carton => carton\.status === 'COUNTED'\)/)
|
||||
assert.doesNotMatch(source, /<el-table-column label="尺寸\(cm\)"/)
|
||||
assert.doesNotMatch(source, /箱数、尺寸、重量/)
|
||||
assert.match(source, /<el-table-column prop="grossWeightKg" label="毛重\(kg\)"/)
|
||||
assert.match(source, /<el-table-column prop="volumeCbm" label="体积\(m³\)"/)
|
||||
})
|
||||
|
||||
for (const kind of ['disposal', 'labeling', 'transfer']) {
|
||||
test(`${kind}: opening loads photos without confirming; only reviewed evidence can be submitted`, async () => {
|
||||
const state = harness(kind)
|
||||
|
||||
@@ -96,21 +96,15 @@ onBeforeUnmount(clear)
|
||||
<template>
|
||||
<el-dialog :model-value="modelValue" :title="title" width="760px" :close-on-click-modal="false" :close-on-press-escape="!busy" :show-close="!busy" @update:model-value="!busy && emit('update:modelValue', $event)">
|
||||
<p>单号:{{ documentNo }}</p>
|
||||
<p>{{ kind === 'transfer' ? '请核对 PDA 回传的箱数、尺寸、重量、打托数据及现场照片,确认无误后再提交。' : '请核对以下 PDA 作业照片,确认作业结果无误后再提交。' }}</p>
|
||||
<p>{{ kind === 'transfer' ? '请核对 PDA 回传的箱数、重量、打托数据及现场照片,确认无误后再提交。' : '请核对以下 PDA 作业照片,确认作业结果无误后再提交。' }}</p>
|
||||
<template v-if="kind === 'transfer' && measurement">
|
||||
<p>实际签收箱数:{{ measurement.cartons?.filter(carton => carton.status === 'COUNTED').length ?? 0 }} 箱;托盘数:{{ measurement.pallets?.length ?? 0 }} 托</p>
|
||||
<el-table :data="measurement.pallets || []" max-height="220" size="small" border empty-text="暂无 PDA 打托测量数据">
|
||||
<el-table-column label="托盘号" min-width="180"><template #default="{ row }">{{ row.palletNo || `第${row.sequenceNo || '—'}托` }}</template></el-table-column>
|
||||
<el-table-column prop="cartonCount" label="箱数" width="65" />
|
||||
<el-table-column label="尺寸(cm)" min-width="130"><template #default="{ row }">{{ row.lengthCm ?? '—' }} × {{ row.widthCm ?? '—' }} × {{ row.heightCm ?? '—' }}</template></el-table-column>
|
||||
<el-table-column prop="grossWeightKg" label="毛重(kg)" width="95" />
|
||||
<el-table-column prop="volumeCbm" label="体积(m³)" width="95" />
|
||||
</el-table>
|
||||
<el-table :data="measurement.cartons?.filter(carton => carton.status === 'COUNTED') || []" max-height="220" size="small" border empty-text="暂无已签收箱子">
|
||||
<el-table-column prop="cartonMark" label="箱唛" min-width="200" />
|
||||
<el-table-column label="尺寸(cm)" min-width="180"><template #default="{ row }">{{ row.length ?? '—' }} × {{ row.width ?? '—' }} × {{ row.height ?? '—' }}</template></el-table-column>
|
||||
<el-table-column prop="weight" label="重量(kg)" width="110" />
|
||||
</el-table>
|
||||
</template>
|
||||
<p v-if="loading">正在读取作业照片…</p>
|
||||
<el-alert v-if="error" :title="error" type="error" :closable="false" />
|
||||
|
||||
@@ -334,6 +334,9 @@ const relabelCandidatesLoading = ref(false)
|
||||
const transferInventoryCandidates = ref<RelabelInventoryCandidate[]>([])
|
||||
const selectedTransferInventory = ref('')
|
||||
const inventoryTransfer = computed(() => props.service === 'transfer' && Boolean(selectedTransferInventory.value))
|
||||
// 来源库存发往FBA时默认贴标,私人仓和外来货保留原有选择。
|
||||
const transferRelabelRequired = computed(() => inventoryTransfer.value && transferDestinationType.value === 'FBA')
|
||||
watch(transferRelabelRequired, (required) => { if (required) form.relabel = true }, { flush: 'sync' })
|
||||
const transferSourceCartons = ref<TransferSourceCarton[]>([])
|
||||
const transferSourceLoading = ref(false)
|
||||
const transferSourceError = ref('')
|
||||
@@ -348,6 +351,8 @@ async function loadTransferSourceCartons() {
|
||||
if (selectedTransferInventory.value.startsWith('RETURN_ORDER:')) {
|
||||
const returnNo = selectedTransferInventory.value.slice('RETURN_ORDER:'.length)
|
||||
transferSourceCartons.value = transferInventoryCandidates.value
|
||||
.filter(item => !['COMPLETED', 'PARTIALLY_COMPLETED'].includes(item.relabelStatus || '')
|
||||
&& Number(item.relabelledQuantity || item.relabelledPackages || 0) === 0)
|
||||
.filter(item => (item.sourceType === 'RETURN_CARTON' || item.sourceType === 'RETURN_PARCEL')
|
||||
&& String(item.inboundOrderNo || '').trim() === returnNo && Number(item.cartonAvailablePackages || 0) > 0)
|
||||
.filter(item => Boolean(item.cartonMark))
|
||||
@@ -1174,6 +1179,7 @@ function printForecastCartons() {
|
||||
}
|
||||
async function submit(action: 'draft' | 'submit' = 'submit') {
|
||||
if (saving.value) return
|
||||
if (transferRelabelRequired.value) form.relabel = true
|
||||
const primaryWarehouse = props.service === 'relabel' ? form.sourceWarehouse : form.warehouse
|
||||
const relabelRows = labelingMode.value === 'carton' ? cartonDetailRows.value : skuRelabelRows.value
|
||||
const invalidCargo = props.service === 'disposal'
|
||||
@@ -1473,7 +1479,7 @@ async function loadTransferInventoryCandidates(warehouseId: string) {
|
||||
relabelCandidatesLoading.value = true
|
||||
try {
|
||||
// 共用接口包含退货历史及占用中的箱子,转运只展示当前可整箱使用的来源。
|
||||
transferInventoryCandidates.value = (await listRelabelInventoryCandidates(warehouseId)).filter(item =>
|
||||
transferInventoryCandidates.value = (await listRelabelInventoryCandidates(warehouseId)).filter(isUnlabelledTransferCandidate).filter(item =>
|
||||
item.sourceType === 'RETURN_CARTON' || item.sourceType === 'RETURN_PARCEL'
|
||||
? Number(item.cartonAvailablePackages || 0) > 0
|
||||
: Number(item.availablePackages || 0) > 0)
|
||||
@@ -1542,6 +1548,12 @@ const transferInventoryOptions = computed(() => {
|
||||
}
|
||||
return [...grouped.values()]
|
||||
})
|
||||
/** 已完成或部分完成换标的退货实物箱不再作为原箱来源;普通来源由逐箱接口过滤。 */
|
||||
function isUnlabelledTransferCandidate(item: RelabelInventoryCandidate) {
|
||||
if (item.sourceType !== 'RETURN_CARTON' && item.sourceType !== 'RETURN_PARCEL') return true
|
||||
return !['COMPLETED', 'PARTIALLY_COMPLETED'].includes(item.relabelStatus || '')
|
||||
&& inventoryQuantity(item.relabelledQuantity || item.relabelledPackages) === 0
|
||||
}
|
||||
async function selectTransferInventory(value: string) {
|
||||
selectedTransferInventory.value = value || ''
|
||||
selectedTransferSourceOrderIds.value = []
|
||||
@@ -1730,7 +1742,7 @@ function addReturnBoxBinding(source: RelabelInventoryCandidate) {
|
||||
<label v-if="props.service === 'labeling'"><span>贴标要求</span><el-input v-model="form.requirement" placeholder="请输入贴标要求" /></label>
|
||||
<label v-else-if="props.service === 'relabel' || (props.service === 'transfer' && form.deliveryMethod === 'CUSTOMER_DELIVERY')"><span>物流跟踪号</span><el-input v-model="form.trackingNo" placeholder="请输入物流跟踪号(选填)" /></label>
|
||||
<label class="warehouse-span-2"><span>备注</span><el-input v-model="form.remark" type="textarea" :rows="2" placeholder="选填" /></label>
|
||||
<div v-if="props.service === 'transfer'" class="warehouse-choice-field warehouse-choice-field--relabel warehouse-span-2"><span><i>*</i>是否贴标</span><el-radio-group v-model="form.relabel"><el-radio-button :value="false">不需要贴标</el-radio-button><el-radio-button :value="true">需要贴标</el-radio-button></el-radio-group><small>{{ form.relabel ? '已开启贴标,请在右侧填写贴标资料' : 'FBA 仓和私人仓均可选择是否贴标' }}</small></div>
|
||||
<div v-if="props.service === 'transfer'" class="warehouse-choice-field warehouse-choice-field--relabel warehouse-span-2"><span><i>*</i>是否贴标</span><el-radio-group v-model="form.relabel"><el-radio-button v-if="!transferRelabelRequired" :value="false">不需要贴标</el-radio-button><el-radio-button :value="true">需要贴标</el-radio-button></el-radio-group><small>{{ form.relabel ? '已开启贴标,请在右侧填写贴标资料' : 'FBA 仓和私人仓均可选择是否贴标' }}</small></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="warehouse-card warehouse-form-section warehouse-transfer-cargo-card">
|
||||
@@ -1805,7 +1817,7 @@ function addReturnBoxBinding(source: RelabelInventoryCandidate) {
|
||||
<el-alert v-if="transferSourceError" :title="transferSourceError" type="error" :closable="false"><el-button link @click="loadTransferSourceCartons">重新加载</el-button></el-alert>
|
||||
<div class="warehouse-table-scroll"><table class="warehouse-edit-table"><thead><tr><th>箱号</th><th>商品 SKU</th><th>中文品名</th><th>箱内数量(件)</th><th>原目的仓</th></tr></thead><tbody>
|
||||
<tr v-for="box in transferSourceCartons" :key="box.cartonMark"><td>{{ box.cartonMark }}</td><td>{{ box.items.map(item => item.skuCode || '—').join(' / ') }}</td><td>{{ box.productNameZh || '—' }}</td><td>{{ box.quantity ?? '未记录' }}</td><td>{{ [box.destinationWarehouseCode, box.destinationWarehouseName].filter(Boolean).join(' · ') || '未指定' }}</td></tr>
|
||||
<tr v-if="!transferSourceLoading && !transferSourceCartons.length"><td colspan="5"><div class="warehouse-empty">{{ transferSourceError ? '加载失败,请重试' : '原库存单据未记录逐箱明细,不虚构箱号;按原库存汇总转运' }}</div></td></tr>
|
||||
<tr v-if="!transferSourceLoading && !transferSourceCartons.length"><td colspan="5"><div class="warehouse-empty">{{ transferSourceError ? '加载失败,请重试' : '当前来源单暂无未换标的箱明细' }}</div></td></tr>
|
||||
</tbody></table></div>
|
||||
<div v-if="!transferSourceLoading && !transferSourceError && !transferSourceCartons.length" class="warehouse-table-scroll"><table class="warehouse-edit-table"><thead><tr><th>商品 SKU</th><th>中文品名</th><th>库存箱数</th><th>原目的仓</th></tr></thead><tbody><tr v-for="row in cargoRows" :key="row.id"><td>{{ row.sku || '—' }}</td><td>{{ row.name || '—' }}</td><td>{{ row.expectedPackageCount }}</td><td>{{ transferInventoryCandidates.filter(item => item.inboundCode === selectedTransferInventory && item.skuCode === row.sku).map(item => item.destinationFbaWarehouseCode || item.destinationFbaWarehouseName).filter(Boolean).join(' / ') || '未指定' }}</td></tr></tbody></table></div>
|
||||
</section>
|
||||
|
||||
@@ -2,6 +2,7 @@ import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { transpileModule, ScriptTarget } from 'typescript'
|
||||
import { computed, ref, reactive, watch } from 'vue'
|
||||
|
||||
const view = readFileSync(new URL('./WarehouseServiceView.vue', import.meta.url), 'utf8')
|
||||
|
||||
@@ -18,6 +19,8 @@ test('退货箱明细与来源下拉使用同一份逐箱库存,不请求普
|
||||
cartonSkuItems: [{ skuCode: 'A', quantity: 1 }] },
|
||||
{ sourceType: 'RETURN_CARTON', inboundOrderNo: 'OTHER', cartonMark: 'FOREIGN', cartonAvailablePackages: 1 },
|
||||
{ sourceType: 'RETURN_CARTON', inboundOrderNo: 'RET-1', cartonMark: 'OCCUPIED', cartonAvailablePackages: 0 },
|
||||
{ sourceType: 'RETURN_CARTON', inboundOrderNo: 'RET-1', cartonMark: 'LABELLED', cartonAvailablePackages: 1, relabelStatus: 'COMPLETED' },
|
||||
{ sourceType: 'RETURN_CARTON', inboundOrderNo: 'RET-1', cartonMark: 'PARTIAL', cartonAvailablePackages: 1, relabelledQuantity: 2 },
|
||||
] }, getTransferSourceCartons: () => { throw Error('不应调用普通来源箱查询') } }
|
||||
const load = new Function(...Object.keys(ctx), 'let transferSourceRequest=0;' + code + ';return loadTransferSourceCartons')(...Object.values(ctx))
|
||||
await load()
|
||||
@@ -28,6 +31,27 @@ test('退货箱明细与来源下拉使用同一份逐箱库存,不请求普
|
||||
assert.equal(ctx.transferSourceLoading.value, false)
|
||||
})
|
||||
|
||||
test('来源库存发往FBA默认开启贴标,清除来源或切换私人仓后恢复选项', () => {
|
||||
const source = ref(''), destination = ref('NONE'), form = reactive({ relabel: false })
|
||||
const inventoryTransfer = computed(() => Boolean(source.value))
|
||||
const body = view.slice(view.indexOf('const transferRelabelRequired ='), view.indexOf('const transferSourceCartons ='))
|
||||
const required = new Function('computed', 'watch', 'inventoryTransfer', 'transferDestinationType', 'form', body + ';return transferRelabelRequired')(
|
||||
computed, watch, inventoryTransfer, destination, form)
|
||||
destination.value = 'FBA'
|
||||
assert.equal(form.relabel, false)
|
||||
source.value = 'IN-1'
|
||||
assert.equal(required.value, true)
|
||||
assert.equal(form.relabel, true)
|
||||
destination.value = 'PRIVATE'
|
||||
assert.equal(required.value, false)
|
||||
form.relabel = false
|
||||
destination.value = 'FBA'
|
||||
assert.equal(form.relabel, true)
|
||||
source.value = ''
|
||||
assert.equal(required.value, false)
|
||||
assert.match(view, /<el-radio-button v-if="!transferRelabelRequired" :value="false">不需要贴标/)
|
||||
})
|
||||
|
||||
function setup() {
|
||||
const body = view.slice(view.indexOf('async function selectTransferInventory('), view.indexOf('function selectTransferInboundMethod('))
|
||||
const code = transpileModule(body, { compilerOptions: { target: ScriptTarget.ES2022 } }).outputText
|
||||
|
||||
Reference in New Issue
Block a user