@@ -44,17 +44,16 @@
< template v-else-if = "discardCurrent" >
< template v-else-if = "discardCurrent" >
< view class = "detail-toolbar" > < view > < text class = "detail-kicker" > 废弃订单 < / text > < text class = "detail-title" > { { discardCurrent . discardNo } } < / text > < text v-if = "discardCurrent.outboundNo" class="task-meta">出库单 {{ discardCurrent.outboundNo }}</text></view><button :disabled="discardBusy" @tap="closeDiscard" > ‹ 返回列表 < / button > < / view >
< view class = "detail-toolbar" > < view > < text class = "detail-kicker" > 废弃订单 < / text > < text class = "detail-title" > { { discardCurrent . discardNo } } < / text > < text v-if = "discardCurrent.outboundNo" class="task-meta">出库单 {{ discardCurrent.outboundNo }}</text></view><button :disabled="discardBusy" @tap="closeDiscard" > ‹ 返回列表 < / button > < / view >
< view v-if = "successMessage " class="fulfillment-success" role="status" > < text > { { successMessage } } < / text > < / view >
< view v-if = "discardOrderRemark " class="fulfillment-card discard-remark"><text class="card-title">废弃备注</text><text class="task-meta" > { { discardOrderRemark }} < / text > < / view >
< view v-if = "! discardTask && discardPendingTasks.length" class="fulfillment-card"><text class="card-title">本单待废弃托盘</text><view v-for="task in discardPendingTasks" :key="task.palletNo" class="outbound-line"><view class="task-head"><text class="business-code" > {{ task.palletNo = = = ' 散箱 ' ? ' 散箱 ' : task.palletNo }} < / text > < text > 待废弃 < / text > < / view > < / view > < / view >
< view v-if = "discardOrderRemaining != null" class="fulfillment-card" > < text > 申请废弃 { { discardCurrentTasks [ 0 ] ? . requestedPackages ? ? discardTask ? . requestedPackages } } 箱 · 剩余 { { discardOrderRemaining } } 箱 < / text > < / view >
< view v-if = "successMessage" class="fulfillment-success" role="status" > < text > { { successMessage } } < / text > < / view >
< view v-if = "!discardTask && discardPendingTasks.length" class="fulfillment-card"><text class="card-title">废弃箱关联托盘</text><view v-for="task in discardPendingTasks" :key="task.palletNo" class="outbound-line"><view class="task-head"><text class="business-code" > {{ task.palletNo = = = ' 散箱 ' ? ' 散箱 ' : task.palletNo }} < / text > < text > 待废弃 < / text > < / view > < / view > < / view >
< view v-if = "!discardTask && discardPendingTasks.length" class="fulfillment-card"><ScanTargetInput name="cargo-discard" :model-value="discardPalletCode" label="废弃托盘码" placeholder="扫描对应托盘码" :active="discardTask?.scanMode !== 'CARTON'" @update:modelValue="updateDiscardPalletCode" @submit="resolveDiscardPallet" / > < / view >
< view v-if = "!discardTask && discardPendingTasks.length" class="fulfillment-card"><ScanTargetInput name="cargo-discard" :model-value="discardPalletCode" label="废弃托盘码" placeholder="扫描对应托盘码" :active="discardTask?.scanMode !== 'CARTON'" @update:modelValue="updateDiscardPalletCode" @submit="resolveDiscardPallet" / > < / view >
< view v-if = "discardTask" class="fulfillment-card"><ScanTargetInput v-if="discardNeedsRefresh" name="cargo-discard-retry" :model-value="discardPalletCode" label="重新扫描废弃托盘" placeholder="重新扫描当前托盘码" :active="true" @update:modelValue="updateDiscardPalletCode" @submit="resolveDiscardPallet" /><view v-else class="task-head"><text class="business-code" > {{ discardTask.palletNo }} < / text > < text > { { discardTask . status === 'COMPLETED' ? '已完成' : '待废弃' } } < / text > < / view > < / view >
< view v-if = "discardTask" class="fulfillment-card"><ScanTargetInput v-if="discardNeedsRefresh" name="cargo-discard-retry" :model-value="discardPalletCode" label="重新扫描废弃托盘" placeholder="重新扫描当前托盘码" :active="true" @update:modelValue="updateDiscardPalletCode" @submit="resolveDiscardPallet" /><view v-else class="task-head"><text class="business-code" > {{ discardTask.palletNo }} < / text > < text > { { discardTask . status === 'COMPLETED' ? '已完成' : '待废弃' } } < / text > < / view > < / view >
< view v-if = "discardTask" class="fulfillment-card item-card" >
< view v-if = "discardTask" class="fulfillment-card item-card" >
< view v-for = "sku in discardQuantityLines" :key="sku.itemId" class="outbound-line" >
< text v-if = "discardQuantityLines.length" class="discard-scanned-count" > 已扫描 {{ discardUnboundScans.length }} 箱 < / text >
< text class = "line-code " > { { sku . skuCode || '—' } } < / text >
< view v-if = "discardQuantityLines.length > 1" class="quantity-row"><button v-for="sku in discardQuantityLines" :key="sku.itemId" class="secondary-button" :disabled="discardBusy" @tap="discardScanItemId = sku.itemId " > {{ sku.skuCode | | ' — ' }}{{ discardScanItemId = = = sku.itemId ? ' ( 当前扫描 ) ' : ' ' }} < / button > < / view >
< view class = "quantity-row" > < text > 实际废弃箱数 < / text > < input type = "number" placeholder = "请输入实际箱数" : value = "discardActuals[sku.itemId] ?? ''" : disabled = "discardTask.status === 'COMPLETED' || discardBusy || discardLoading || discardPhotoBusy" @input ="updateDiscardActual(sku.itemId, $event)" / > < text > 箱 ( 0 – { { sku . plannedPackages } } ) < / text > < / view >
< view v-if = "discardQuantityLines.length"><text class="business-code">扫描箱号出库</text><ScanTargetInput name="cargo-discard-count" :model-value="discardCartonCode" label="废弃箱唛" placeholder="扫描现场已有箱唛" :active="true" @update:modelValue="discardCartonCode = $event" @submit="scanDiscardCarton" /><view v-if="discardUnboundScans.length" class="discard-carton-heading" role="button" :aria-expanded="discardScannedExpanded" :aria-label="discardScannedExpanded ? '收起已扫描箱唛' : '展开已扫描箱唛'" @tap="discardScannedExpanded = !discardScannedExpanded"><text class="scan-help">已扫描 {{ discardUnboundScans.length }} 箱</text><view class="discard-carton-chevron" :class="{ expanded: discardScannedExpanded }" aria-hidden="true"></view></view><view v-if="discardScannedExpanded"><view v-for="scan in discardUnboundScans" :key="scan.mark" class="outbound-line"><text>{{ scan.mark }}</text><button class="discard-scan-remove" :disabled="discardBusy || discardPhotoBusy" :aria-label="`移除箱唛 ${scan.mark}`" @tap="removeDiscardScan(scan.mark)">移除</button></view></view></view><view v-if="discardTask.scanMode === 'CARTON'"><view class="discard-carton-heading" role="button" :aria-expanded="discardCartonsExpanded" :aria-label="discardCartonsExpanded ? '收起箱号核对' : '展开箱号核对'" @tap="discardCartonsExpanded = !discardCartonsExpanded"><text class="business-code">箱号核对</text><view class="discard-carton-heading-end"><text class="scan-help">待扫描 {{ discardPendingMarks.length }} 箱</text><view class="discard-carton-chevron" :class="{ expanded: discardCartonsExpanded }" aria-hidden="true" > < / view > < / view > < / view >
< text class = "scan-help" > 按现场实点填写 , 未废弃的预留库存将释放 。 < / text >
< / view >
< view v-if = "discardTask.scanMode === 'CARTON'"><view class="discard-carton-heading" role="button" :aria-expanded="discardCartonsExpanded" :aria-label="discardCartonsExpanded ? '收起箱号核对' : '展开箱号核对'" @tap="discardCartonsExpanded = !discardCartonsExpanded"><text class="business-code">箱号核对</text><view class="discard-carton-heading-end"><text class="scan-help">待扫描 {{ discardPendingMarks.length }} 箱</text><view class="discard-carton-chevron" :class="{ expanded: discardCartonsExpanded }" aria-hidden="true" > < / view > < / view > < / view >
< text class = "scan-help" > 已核对 { { discardScannedMarks . length } } / { { discardTask . cartonMarks . length } } 箱 < / text >
< text class = "scan-help" > 已核对 { { discardScannedMarks . length } } / { { discardTask . cartonMarks . length } } 箱 < / text >
< view v-if = "discardCartonsExpanded" >
< view v-if = "discardCartonsExpanded" >
< view v-for = "mark in discardPendingMarks" :key="mark" class="outbound-line" > < text > { { mark } } < / text > < / view >
< view v-for = "mark in discardPendingMarks" :key="mark" class="outbound-line" > < text > { { mark } } < / text > < / view >
@@ -79,10 +78,12 @@
export default {
export default {
components : { PortalHeader , ScanTargetInput } ,
components : { PortalHeader , ScanTargetInput } ,
data ( ) { return { user : session . currentUser , tasks : [ ] , discardTasks : [ ] , current : null , discardCurrent : null , discardTask : null , discardActuals : { } , discardScannedMarks : [ ] , discardCartonsExpanded : true , discardCartonCode : '' , discardPhotos : [ ] , discardPhotoUrls : { } , discardPhotoErrors : { } , discardPhotoBusy : false , discardPhotoReady : false , discardPalletCode : '' , discardLoading : false , discardBusy : false , discardNeedsRefresh : false , selectedItem : null , selectedPosition : null , selectedScanCode : '' , scanCode : '' , loading : false , busy : false , busyAction : '' , error : null , successMessage : '' , bootstrapped : false } } ,
data ( ) { return { user : session . currentUser , tasks : [ ] , discardTasks : [ ] , current : null , discardCurrent : null , discardTask : null , discardScannedExpanded : false , discardUnboundScans : [ ] , discardScanItemId : '' , discardActuals : { } , discardScannedMarks : [ ] , discardCartonsExpanded : true , discardCartonCode : '' , discardPhotos : [ ] , discardPhotoUrls : { } , discardPhotoErrors : { } , discardPhotoBusy : false , discardPhotoReady : false , discardPalletCode : '' , discardLoading : false , discardBusy : false , discardNeedsRefresh : false , selectedItem : null , selectedPosition : null , selectedScanCode : '' , scanCode : '' , loading : false , busy : false , busyAction : '' , error : null , successMessage : '' , bootstrapped : false } } ,
computed : {
computed : {
// 已扫描箱号保留提交凭据,列表只显示尚未核对的箱子。
// 已扫描箱号保留提交凭据,列表只显示尚未核对的箱子。
discardPendingMarks ( ) { return ( this . discardTask ? . cartonMarks || [ ] ) . filter ( mark => ! this . discardScannedMarks . includes ( mark ) ) } ,
discardOrderRemark ( ) { return this . discardTask ? . remark || this . discardCurrentTasks . find ( task => task . remark ) ? . remark || '' } ,
discardOrderRemaining ( ) { return this . discardTask ? . remainingPackages ? ? this . discardCurrentTasks [ 0 ] ? . remainingPackages ? ? null } ,
discardPendingMarks ( ) { return ( this . discardTask ? . cartonMarks || [ ] ) . filter ( mark => ! this . discardScannedMarks . includes ( mark ) ) } ,
discardQuantityLines ( ) { return ( this . discardTask ? . skus || [ ] ) . filter ( sku => sku . actualQuantityEditable ) } ,
discardQuantityLines ( ) { return ( this . discardTask ? . skus || [ ] ) . filter ( sku => sku . actualQuantityEditable ) } ,
displayItems ( ) {
displayItems ( ) {
const items = this . current ? . items || [ ]
const items = this . current ? . items || [ ]
@@ -126,7 +127,7 @@
const boxes = new Set ( task . cartonMarks || [ ] ) . size || task . skus . filter ( sku => sku . quantityUnit !== '件' ) . reduce ( ( total , sku ) => total + sku . plannedPackages , 0 )
const boxes = new Set ( task . cartonMarks || [ ] ) . size || task . skus . filter ( sku => sku . quantityUnit !== '件' ) . reduce ( ( total , sku ) => total + sku . plannedPackages , 0 )
return ` ${ boxes } 箱 ${ pieces ? ` · ${ pieces } 件 ` : '' } `
return ` ${ boxes } 箱 ${ pieces ? ` · ${ pieces } 件 ` : '' } `
} ,
} ,
canConfirmDiscard ( ) { const task = this . discardTask ; return Boolean ( this . discardPhotoReady && this . discardPhotos . length > 0 && ! this . discardPhotoBusy && ! this . discardLoading && ! this . discardBusy && task && task . status !== 'COMPLETED' && task . skus . length && task . skus . every ( sku => this . validDiscardActual ( sku ) ) && ( task . scanMode !== 'CARTON' || ( task . cartonMarks ? . length && task . cartonMarks . every ( mark => this . discardScannedMarks . includes ( mark ) ) ) ) ) }
canConfirmDiscard ( ) { const task = this . discardTask ; return Boolean ( this . discardPhotoReady && this . discardPhotos . length > 0 && ! this . discardPhotoBusy && ! this . discardLoading && ! this . discardBusy && task && task . status !== 'COMPLETED' && ( task . remainingPackages == null || task . scanMode === 'CARTON' || task . skus . reduce ( ( sum , sku ) => sum + Number ( this . discardActuals [ sku . itemId ] || 0 ) , 0 ) <= task . remainingPackages ) && task . skus . length && task . skus . every ( sku => this . validDiscardActual ( sku ) ) && ( task . scanMode !== 'CARTON' || ( task . cartonMarks ? . length && task . cartonMarks . every ( mark => this . discardScannedMarks . includes ( mark ) ) ) ) ) }
} ,
} ,
onShow ( ) { if ( ! requireSession ( ) ) return ; this . user = session . currentUser ; restoreFulfillmentDraft ( ` ${ this . user ? . id || '' } : ${ this . user ? . warehouseId || '' } ` ) ; this . startScanner ( ) ; if ( this . discardPhotoBusy || this . discardBusy ) return ; if ( this . discardCurrent ) { if ( this . discardTask ) this . restoreDiscardPhotos ( ) ; return } if ( ! this . bootstrapped ) { this . bootstrapped = true ; this . scanCode = '' ; this . loadTasks ( ) ; return } if ( this . current ? . taskNo ) this . openTask ( this . current . taskNo ) ; else this . loadTasks ( ) } ,
onShow ( ) { if ( ! requireSession ( ) ) return ; this . user = session . currentUser ; restoreFulfillmentDraft ( ` ${ this . user ? . id || '' } : ${ this . user ? . warehouseId || '' } ` ) ; this . startScanner ( ) ; if ( this . discardPhotoBusy || this . discardBusy ) return ; if ( this . discardCurrent ) { if ( this . discardTask ) this . restoreDiscardPhotos ( ) ; return } if ( ! this . bootstrapped ) { this . bootstrapped = true ; this . scanCode = '' ; this . loadTasks ( ) ; return } if ( this . current ? . taskNo ) this . openTask ( this . current . taskNo ) ; else this . loadTasks ( ) } ,
onHide ( ) { this . stopScanner ( ) } ,
onHide ( ) { this . stopScanner ( ) } ,
@@ -154,7 +155,7 @@
} , true )
} , true )
} ,
} ,
closeTask ( ) { this . current = null ; this . selectedItem = null ; this . selectedPosition = null ; this . error = null ; this . successMessage = '' ; updateFulfillmentDraft ( 'outbound' , { currentTaskNo : '' , scanCode : '' , packages : 1 } ) ; this . loadTasks ( ) } ,
closeTask ( ) { this . current = null ; this . selectedItem = null ; this . selectedPosition = null ; this . error = null ; this . successMessage = '' ; updateFulfillmentDraft ( 'outbound' , { currentTaskNo : '' , scanCode : '' , packages : 1 } ) ; this . loadTasks ( ) } ,
openDiscardOrder ( discardNo ) { if ( this . discardPhotoBusy ) return ; this . resetDiscardPhotos ( ) ; const code = String ( discardNo || '' ) . trim ( ) ; if ( ! code || this . discardBusy || this . busy || this . loading ) return ; this . current = null ; this . discardLoading = false ; this . discardCurrent = { discardNo : code , outboundNo : this . discardOrders . find ( order => order . discardNo === code ) ? . outboundNo || '' } ; this . discardTask = null ; this . discardPalletCode = '' ; this . discardActuals = { } ; this . discardScannedMarks = [ ] ; this . discardCartonsExpanded = true ; this . discardCartonCode = '' ; this . discardNeedsRefresh = false ; this . error = null ; this . successMessage = '' ; } ,
openDiscardOrder ( discardNo ) { if ( this . discardPhotoBusy ) return ; this . resetDiscardPhotos ( ) ; const code = String ( discardNo || '' ) . trim ( ) ; if ( ! code || this . discardBusy || this . busy || this . loading ) return ; this . current = null ; this . discardLoading = false ; this . discardCurrent = { discardNo : code , outboundNo : this . discardOrders . find ( order => order . discardNo === code ) ? . outboundNo || '' } ; this . discardTask = null ; this . discardPalletCode = '' ; this . discardActuals = { } ; this . discardUnboundScans = [ ] ; this . discardScannedExpanded = false ; this . discardScanItemId = '' ; this . discardScannedMarks = [ ] ; this . discardCartonsExpanded = true ; this . discardCartonCode = '' ; this . discardNeedsRefresh = false ; this . error = null ; this . successMessage = '' ; } ,
closeDiscard ( ) { if ( this . discardBusy || this . discardPhotoBusy ) return ; this . resetDiscardPhotos ( ) ; this . discardLoading = false ; this . discardCurrent = null ; this . discardTask = null ; this . discardPalletCode = '' ; this . discardActuals = { } ; this . loadTasks ( ) } ,
closeDiscard ( ) { if ( this . discardBusy || this . discardPhotoBusy ) return ; this . resetDiscardPhotos ( ) ; this . discardLoading = false ; this . discardCurrent = null ; this . discardTask = null ; this . discardPalletCode = '' ; this . discardActuals = { } ; this . loadTasks ( ) } ,
updateDiscardPalletCode ( value ) { this . discardPalletCode = value } ,
updateDiscardPalletCode ( value ) { this . discardPalletCode = value } ,
// 下方扫描框只核对当前任务的真实箱号,不切换托盘或清空照片。
// 下方扫描框只核对当前任务的真实箱号,不切换托盘或清空照片。
@@ -164,14 +165,33 @@
if ( ! code ) return
if ( ! code ) return
if ( this . discardNeedsRefresh && ! await this . refreshDiscardTask ( ) ) return
if ( this . discardNeedsRefresh && ! await this . refreshDiscardTask ( ) ) return
if ( this . discardTask . status === 'COMPLETED' ) return
if ( this . discardTask . status === 'COMPLETED' ) return
if ( this . discardQuantityLines . length ) {
if ( ( this . discardCurrentTasks || [ ] ) . some ( task => task . palletNo === code ) ) { this . setError ( new Error ( '请扫描箱唛,不能把托盘码作为箱唛' ) , '箱唛核对失败' ) ; return }
const sku = this . discardQuantityLines . length === 1 ? this . discardQuantityLines [ 0 ] : this . discardQuantityLines . find ( line => line . itemId === this . discardScanItemId )
if ( ! sku ) { this . setError ( new Error ( '请先选择当前扫描的货物' ) , '箱唛核对失败' ) ; return }
if ( this . discardUnboundScans . some ( scan => scan . mark === code ) ) { this . discardCartonCode = '' ; return }
if ( code . length > 128 || this . discardUnboundScans . filter ( scan => scan . itemId === sku . itemId ) . length >= sku . plannedPackages || this . discardUnboundScans . length >= ( this . discardTask . remainingPackages ? ? Infinity ) ) { this . setError ( new Error ( '扫描箱数不能超过本托预留或申请剩余箱数' ) , '箱唛核对失败' ) ; return }
this . discardUnboundScans = [ ... this . discardUnboundScans , { itemId : sku . itemId , mark : code } ]
this . discardActuals = { ... this . discardActuals , [ sku . itemId ] : this . discardUnboundScans . filter ( scan => scan . itemId === sku . itemId ) . length }
this . discardCartonCode = '' ; this . error = null ; playSuccessSound ( ) ; return
}
if ( ! this . discardTask . cartonMarks . includes ( code ) ) { this . setError ( new Error ( '箱号不属于当前废弃任务' ) , '箱号核对失败' ) ; return }
if ( ! this . discardTask . cartonMarks . includes ( code ) ) { this . setError ( new Error ( '箱号不属于当前废弃任务' ) , '箱号核对失败' ) ; return }
if ( ! this . discardScannedMarks . includes ( code ) ) this . discardScannedMarks = [ ... this . discardScannedMarks , code ]
if ( ! this . discardScannedMarks . includes ( code ) ) this . discardScannedMarks = [ ... this . discardScannedMarks , code ]
this . discardCartonCode = '' ; this . error = null ; playSuccessSound ( )
this . discardCartonCode = '' ; this . error = null ; playSuccessSound ( )
} ,
} ,
/** 删除误扫的现场箱唛,并同步扣回对应明细实扫数量。 */
removeDiscardScan ( mark ) {
if ( this . discardBusy || this . discardPhotoBusy ) return
const removed = this . discardUnboundScans . find ( scan => scan . mark === mark )
if ( ! removed ) return
this . discardUnboundScans = this . discardUnboundScans . filter ( scan => scan . mark !== mark )
this . discardActuals = { ... this . discardActuals , [ removed . itemId ] : this . discardUnboundScans . filter ( scan => scan . itemId === removed . itemId ) . length }
this . error = null ; this . successMessage = ''
} ,
async resolveDiscardPallet ( raw ) {
async resolveDiscardPallet ( raw ) {
const code = String ( typeof raw === 'string' ? raw : raw ? . detail ? . value ? ? this . discardPalletCode ) . trim ( )
const code = String ( typeof raw === 'string' ? raw : raw ? . detail ? . value ? ? this . discardPalletCode ) . trim ( )
if ( ! code || ! this . discardCurrent || this . discardBusy || this . discardLoading || this . discardPhotoBusy ) return
if ( ! code || ! this . discardCurrent || this . discardBusy || this . discardLoading || this . discardPhotoBusy ) return
if ( this . discardTask ? . scanMode === 'CARTON' && this . discardTask . cartonMarks . includes ( code ) ) { await this . scanDiscardCarton ( code ) ; return }
if ( ( this . discardQuantityLines . length && ! this . discardCurrentTasks . some ( task => task . palletNo === code ) && this . discardTask ? . palletNo !== code ) || ( this . discardTask ? . scanMode === 'CARTON' && this . discardTask . cartonMarks . includes ( code ) ) ) { await this . scanDiscardCarton ( code ) ; return }
if ( this . discardTask ? . palletNo === code ) { await this . refreshDiscardTask ( ) ; return }
if ( this . discardTask ? . palletNo === code ) { await this . refreshDiscardTask ( ) ; return }
// 当前托盘可重扫,同一废弃单内也可通过托盘或所选箱唛切换任务。
// 当前托盘可重扫,同一废弃单内也可通过托盘或所选箱唛切换任务。
if ( this . discardTask ? . scanMode === 'CARTON' && ! this . discardTasks . some ( task => task . discardNo === this . discardCurrent . discardNo && ( task . palletNo === code || ( task . cartonMarks || [ ] ) . includes ( code ) ) ) ) { this . setError ( new Error ( '托盘或箱唛不属于当前废弃单所选货物' ) , '箱唛核对失败' ) ; return }
if ( this . discardTask ? . scanMode === 'CARTON' && ! this . discardTasks . some ( task => task . discardNo === this . discardCurrent . discardNo && ( task . palletNo === code || ( task . cartonMarks || [ ] ) . includes ( code ) ) ) ) { this . setError ( new Error ( '托盘或箱唛不属于当前废弃单所选货物' ) , '箱唛核对失败' ) ; return }
@@ -179,14 +199,14 @@
const selectedTasks = this . discardTasks . filter ( task => task . discardNo === this . discardCurrent . discardNo )
const selectedTasks = this . discardTasks . filter ( task => task . discardNo === this . discardCurrent . discardNo )
if ( selectedTasks . length && ! selectedTasks . some ( task => task . palletNo !== '散箱' ? task . palletNo === code : ( task . cartonMarks || [ ] ) . includes ( code ) ) ) { this . setError ( new Error ( '请先扫描当前废弃单对应的托盘码' ) , '托盘核对失败' ) ; return }
if ( selectedTasks . length && ! selectedTasks . some ( task => task . palletNo !== '散箱' ? task . palletNo === code : ( task . cartonMarks || [ ] ) . includes ( code ) ) ) { this . setError ( new Error ( '请先扫描当前废弃单对应的托盘码' ) , '托盘核对失败' ) ; return }
const order = this . discardCurrent
const order = this . discardCurrent
this . resetDiscardPhotos ( ) ; this . discardScannedMarks = [ ] ; this . discardCartonsExpanded = true ; this . discardCartonCode = '' ; this . discardPalletCode = code ; this . discardLoading = true ; this . discardNeedsRefresh = false ; this . discardTask = null ; this . discardActuals = { } ; this . error = null ; this . successMessage = ''
this . resetDiscardPhotos ( ) ; this . discardScannedMarks = [ ] ; this . discardCartonsExpanded = true ; this . discardCartonCode = '' ; this . discardPalletCode = code ; this . discardLoading = true ; this . discardNeedsRefresh = false ; this . discardTask = null ; this . discardUnboundScans = [ ] ; this . discardScannedExpanded = false ; this . discardScanItemId = '' ; this . discardActuals = { } ; this . error = null ; this . successMessage = ''
try {
try {
const task = await resolveCargoDiscardPallet ( code , order . discardNo )
const task = await resolveCargoDiscardPallet ( code , order . discardNo )
if ( this . discardCurrent !== order ) return
if ( this . discardCurrent !== order ) return
if ( task . discardNo !== order . discardNo ) throw new Error ( '扫描的托盘不属于当前废弃订单' )
if ( task . discardNo !== order . discardNo ) throw new Error ( '扫描的托盘不属于当前废弃订单' )
this . discardTask = normalizeCargoDiscardTask ( task )
this . discardTask = normalizeCargoDiscardTask ( task )
if ( this . discardTask . scanMode === 'CARTON' && this . discardTask . cartonMarks . includes ( code ) ) this . discardScannedMarks = [ code ]
if ( this . discardTask . scanMode === 'CARTON' && this . discardTask . cartonMarks . includes ( code ) ) this . discardScannedMarks = [ code ]
this . discardActuals = Object . fromEntries ( this . discardTask . skus . map ( ( sku ) => [ sku . itemId , sku . actualPackages == null ? ( sku . actualQuantityEditable ? '' : sku . plannedPackages ) : sku . actualPackages ] ) ) ; await this . restoreDiscardPhotos ( )
this . discardActuals = Object . fromEntries ( this . discardTask . skus . map ( ( sku ) => [ sku . itemId , sku . actualPackages == null ? ( sku . actualQuantityEditable ? 0 : sku . plannedPackages ) : sku . actualPackages ] ) ) ; await this . restoreDiscardPhotos ( )
} catch ( error ) { if ( this . discardCurrent === order ) this . setError ( error , '废弃托盘读取失败' ) }
} catch ( error ) { if ( this . discardCurrent === order ) this . setError ( error , '废弃托盘读取失败' ) }
finally { if ( this . discardCurrent === order ) this . discardLoading = false }
finally { if ( this . discardCurrent === order ) this . discardLoading = false }
} ,
} ,
@@ -201,10 +221,11 @@
if ( latest . discardNo !== order . discardNo || latest . palletNo !== previous . palletNo ) throw new Error ( '刷新结果不属于当前废弃托盘' )
if ( latest . discardNo !== order . discardNo || latest . palletNo !== previous . palletNo ) throw new Error ( '刷新结果不属于当前废弃托盘' )
this . discardTask = normalizeCargoDiscardTask ( latest )
this . discardTask = normalizeCargoDiscardTask ( latest )
this . discardScannedMarks = this . discardScannedMarks . filter ( mark => ( this . discardTask . cartonMarks || [ ] ) . includes ( mark ) )
this . discardScannedMarks = this . discardScannedMarks . filter ( mark => ( this . discardTask . cartonMarks || [ ] ) . includes ( mark ) )
this . discardUnboundScans = this . discardUnboundScans . filter ( scan => this . discardTask . skus . some ( sku => sku . actualQuantityEditable && sku . itemId === scan . itemId ) )
this . discardActuals = Object . fromEntries ( this . discardTask . skus . map ( sku => {
this . discardActuals = Object . fromEntries ( this . discardTask . skus . map ( sku => {
const old = previous . skus . find ( line => line . itemId === sku . itemId )
const old = previous . skus . find ( line => line . itemId === sku . itemId )
const unchanged = old && old . plannedPackages === sku . plannedPackages && old . actualQuantityEditable === sku . actualQuantityEditable
const unchanged = old && old . plannedPackages === sku . plannedPackages && old . actualQuantityEditable === sku . actualQuantityEditable
return [ sku . itemId , sku . actualPackages ? ? ( unchanged ? this . discardActuals [ sku . itemId ] : sku . actualQuantityEditable ? '' : sku . plannedPackages ) ]
return [ sku . itemId , sku . actualPackages ? ? ( unchanged ? this . discardActuals [ sku . itemId ] : sku . actualQuantityEditable ? 0 : sku . plannedPackages ) ]
} ) )
} ) )
this . discardPalletCode = latest . palletNo ; this . discardNeedsRefresh = false ; this . error = null
this . discardPalletCode = latest . palletNo ; this . discardNeedsRefresh = false ; this . error = null
if ( ! this . discardPhotoReady ) await this . restoreDiscardPhotos ( )
if ( ! this . discardPhotoReady ) await this . restoreDiscardPhotos ( )
@@ -248,7 +269,7 @@
} , fail : ( ) => { this . discardPhotoBusy = false } } )
} , fail : ( ) => { this . discardPhotoBusy = false } } )
} ,
} ,
// 未填写、负数、小数或超出预留数均阻止提交,保留输入供仓库修正。
// 未填写、负数、小数或超出预留数均阻止提交,保留输入供仓库修正。
validDiscardActual ( sku ) { const raw = this . discardActuals [ sku . itemId ] ; if ( raw == null || String ( raw ) . trim ( ) === '' ) return false ; const actual = Number ( raw ) ; return Number . isSafeInteger ( actual ) && actual >= 0 && ( sku . actualQuantityEditable === true ? actual <= sku . plannedPackages : actual === sku . plannedPackages ) } ,
validDiscardActual ( sku ) { const raw = this . discardActuals [ sku . itemId ] ; if ( raw == null || String ( raw ) . trim ( ) === '' ) return false ; if ( sku . actualQuantityEditable && Number ( raw ) !== this . discardUnboundScans . filter ( scan => scan . itemId === sku . itemId ) . length ) return false ; const actual = Number ( raw ) ; return Number . isSafeInteger ( actual ) && actual >= 0 && ( sku . actualQuantityEditable === true ? actual <= sku . plannedPackages : actual === sku . plannedPackages ) } ,
updateDiscardActual ( itemId , event ) { this . discardActuals = { ... this . discardActuals , [ itemId ] : event . detail . value } } ,
updateDiscardActual ( itemId , event ) { this . discardActuals = { ... this . discardActuals , [ itemId ] : event . detail . value } } ,
/** 单托完成后刷新同单待办,仍有托盘时明确提示继续扫码。 */
/** 单托完成后刷新同单待办,仍有托盘时明确提示继续扫码。 */
async confirmDiscard ( ) {
async confirmDiscard ( ) {
@@ -259,7 +280,7 @@
if ( this . discardNeedsRefresh ) {
if ( this . discardNeedsRefresh ) {
if ( ! await this . refreshDiscardTask ( ) || this . discardTask . status === 'COMPLETED' || ! this . discardPhotoReady || ! this . discardTask . skus . every ( sku => this . validDiscardActual ( sku ) ) || ( this . discardTask . scanMode === 'CARTON' && ! this . discardTask . cartonMarks . every ( mark => this . discardScannedMarks . includes ( mark ) ) ) ) return
if ( ! await this . refreshDiscardTask ( ) || this . discardTask . status === 'COMPLETED' || ! this . discardPhotoReady || ! this . discardTask . skus . every ( sku => this . validDiscardActual ( sku ) ) || ( this . discardTask . scanMode === 'CARTON' && ! this . discardTask . cartonMarks . every ( mark => this . discardScannedMarks . includes ( mark ) ) ) ) return
}
}
const lines = this . discardTask . skus . map ( sku => ( { itemId : sku . itemId , actualPackages : Number ( this . discardActuals [ sku . itemId ] ) } ) )
const lines = this . discardTask . skus . map ( sku => ( { itemId : sku . itemId , actualPackages : Number ( this . discardActuals [ sku . itemId ] ) , ... ( sku . actualQuantityEditable ? { scannedCartonMarks : this . discardUnboundScans . filter ( scan => scan . itemId === sku . itemId ) . map ( scan => scan . mark ) } : { } ) } ) )
const photoFileIds = this . discardPhotos . map ( photo => String ( photo . fileId ) )
const photoFileIds = this . discardPhotos . map ( photo => String ( photo . fileId ) )
const key = fulfillmentIdempotencyKey ( 'outbound' , 'DISCARD' , { discardNo , palletNo , lines , photoFileIds , scannedCartonMarks : this . discardScannedMarks , confirmAllCartons : false } )
const key = fulfillmentIdempotencyKey ( 'outbound' , 'DISCARD' , { discardNo , palletNo , lines , photoFileIds , scannedCartonMarks : this . discardScannedMarks , confirmAllCartons : false } )
await confirmCargoDiscard ( discardNo , palletNo , lines , photoFileIds , this . discardScannedMarks , false , { idempotencyKey : key . value } )
await confirmCargoDiscard ( discardNo , palletNo , lines , photoFileIds , this . discardScannedMarks , false , { idempotencyKey : key . value } )
@@ -322,6 +343,7 @@
. discard - carton - heading - end . scan - help { margin : 0 ; }
. discard - carton - heading - end . scan - help { margin : 0 ; }
. discard - carton - chevron { flex - shrink : 0 ; width : 8 px ; height : 8 px ; margin - right : 3 px ; border - right : 2 px solid # 718095 ; border - bottom : 2 px solid # 718095 ; transform : rotate ( 45 deg ) ; }
. discard - carton - chevron { flex - shrink : 0 ; width : 8 px ; height : 8 px ; margin - right : 3 px ; border - right : 2 px solid # 718095 ; border - bottom : 2 px solid # 718095 ; transform : rotate ( 45 deg ) ; }
. discard - carton - chevron . expanded { transform : rotate ( 225 deg ) ; }
. discard - carton - chevron . expanded { transform : rotate ( 225 deg ) ; }
. discard - scan - remove { margin - left : auto ; padding : 4 px 10 px ; border : 0 ; border - radius : 4 px ; background : # fef2f2 ; color : # dc2626 ; font - size : 12 px ; }
. discard - photo - section { margin : 14 px 0 ; padding - top : 12 px ; border - top : 1 px solid # d9e3ee } . discard - photo - grid { display : grid ; grid - template - columns : repeat ( 2 , minmax ( 0 , 1 fr ) ) ; gap : 10 px ; margin : 12 px 0 } . discard - photo - tile image { display : block ; width : 100 % ; height : 120 px ; border - radius : 8 px }
. discard - photo - section { margin : 14 px 0 ; padding - top : 12 px ; border - top : 1 px solid # d9e3ee } . discard - photo - grid { display : grid ; grid - template - columns : repeat ( 2 , minmax ( 0 , 1 fr ) ) ; gap : 10 px ; margin : 12 px 0 } . discard - photo - tile image { display : block ; width : 100 % ; height : 120 px ; border - radius : 8 px }
. outbound - line { margin - top : 9 px ; padding : 10 px ; border : 1 px solid # e0e7ef ; border - radius : 8 px ; background : # f8fafc ; }
. outbound - line { margin - top : 9 px ; padding : 10 px ; border : 1 px solid # e0e7ef ; border - radius : 8 px ; background : # f8fafc ; }
. outbound - line . selected { border : 2 px solid # 135 ee8 ; background : # edf5ff ; }
. outbound - line . selected { border : 2 px solid # 135 ee8 ; background : # edf5ff ; }
@@ -329,4 +351,6 @@
. line - code { color : # 263 b55 ; font - size : 12 px ; font - weight : 800 ; overflow - wrap : anywhere ; }
. line - code { color : # 263 b55 ; font - size : 12 px ; font - weight : 800 ; overflow - wrap : anywhere ; }
. line - meta { margin - top : 4 px ; color : # 718095 ; font - size : 10 px ; }
. line - meta { margin - top : 4 px ; color : # 718095 ; font - size : 10 px ; }
. missing - scan - contract { display : block ; margin - top : 9 px ; padding : 9 px ; border - radius : 7 px ; color : # a56800 ; font - size : 10 px ; line - height : 16 px ; background : # fff6df ; }
. missing - scan - contract { display : block ; margin - top : 9 px ; padding : 9 px ; border - radius : 7 px ; color : # a56800 ; font - size : 10 px ; line - height : 16 px ; background : # fff6df ; }
. discard - remark . card - title , . discard - remark . task - meta { color : # dc2626 ; }
. discard - scanned - count { display : block ; margin - bottom : 8 px ; color : # dc2626 ; font - size : 15 px ; font - weight : 700 ; }
< / style >
< / style >