@@ -15,22 +15,37 @@
< view > < strong > { { task . boundCartons || 0 } } < / strong > < text > 已归托 < / text > < / view >
< view > < strong > { { task . unboundCartons || 0 } } < / strong > < text > 待归托 < / text > < / view >
< / view >
< view class = "pallet-readiness" : class = "{ invalid: !palletSetupReady }" >
< text > 预计 { { task . expectedPalletCount || 0 } } 托 < / text >
< text > 已生成 { { task . generatedPalletCount || 0 } } 托 < / text >
< / view >
< view v-if = "!palletSetupReady" class="message error pallet-setup-error" role="alert" > {{ palletSetupMessage }} < / view >
< button v-if = "task.taskStatus === 'PENDING'" class="primary-button" :disabled="submitting" @tap="claimTask" > 领取并开始入库 < / button >
< / view >
< view v-if = "task.taskStatus === 'CLAIMED'" class="section-card" >
< text class = "section-title" > 1. 扫托盘或扫 箱< / text >
< text class = "section-desc" > 顺序不限 : 先扫托盘后扫箱会 直接归托; 先扫箱后扫托会把待归托箱绑定到该托盘 。 < / text >
< ScanTargetInput v-model = "palletCode" name="palletCode" label="托盘码" placeholder="扫描或输入已生成的 DP 托盘码" :active="activeScan === 'palletCode'" @activate="activeScan = 'palletCode'" @submit="selectPallet" / >
< text class = "section-title" > 1. 箱码清点与归托 < / text >
< text class = "section-desc" > 先扫箱 : 核对实际件数并确认清点 ; 已选择托盘时本箱 直接归托。 也可先扫托盘 , 再连续扫箱清点归托 。 < / text >
< template v-if = "palletSetupReady" >
< ScanTargetInput v-model = "boxCode" name="boxCode" label="箱码" placeholder="扫描或输入箱唛箱码" :active="activeScan === 'boxCode'" @activate="activeScan = 'boxCode'" @submit="resolveCarton" / >
< view v-if = "!carton" class="count-entry" >
< text > 扫描箱码后核对计划件数与实际件数 , 再确认完成本箱清点 。 < / text >
< button class = "primary-button count-button" :disabled = "!canResolveCarton" @tap ="resolveCarton()" > 开始清点 < / button >
< / view >
< view v-if = "carton" class="carton-card" >
< view class = "carton-head" > < text > { { carton . boxCode } } < / text > < text > { { carton . countStatus === 'UNCOUNTED' ? '待清点' : '已处理' } } < / text > < / view >
< text class = "carton-line" > { { carton . skuCode || 'SKU —' } } · { { carton . cargoName || '品名 —' } } < / text >
< text class = "carton-line" > 计划 { { carton . expectedSkuQuantity || 0 } } 件 < / text >
< view class = "field" > < text > 实际件数 < / text > < input v-model = "actualQuantity" type="number" aria-label="本箱实际件数" / > < / view >
< view v-if = "quantityDiffers" class="field stacked"><text>差异说明</text><textarea v-model="discrepancyRemark" maxlength="500" placeholder="数量不一致时必填" / > < / view >
< button class = "primary-button" : disabled = "!canCount || submitting" @tap ="countCarton" > {{ currentPallet ? ` 确认并归入 $ { currentPallet.palletNo } ` : ' 确认本箱 并进入待归托区 ' }} < / button >
< button class = "primary-button" : disabled = "!canCount || submitting" @tap ="countCarton" > {{ currentPallet ? ` 确认清点 并归入 $ { currentPallet.palletNo } ` : ' 确认清点 并进入待归托区 ' }} < / button >
< / view >
< view class = "pallet-scan-block" >
< text class = "field-label" > 托盘归托 ( 可先扫或后扫 ) < / text >
< ScanTargetInput v-model = "palletCode" name="palletCode" label="托盘码" placeholder="扫描或输入已生成的 DP 托盘码" :active="activeScan === 'palletCode'" @activate="activeScan = 'palletCode'" @submit="selectPallet" / >
< / view >
< / template >
< view v-else class = "count-unavailable" > 托盘码未准备完成 , 当前不能开始箱码清点 。 < / view >
< / view >
< view class = "section-card" >
@@ -62,7 +77,10 @@
data ( ) { return { user : session . currentUser , taskId : '' , warehouseId : '' , task : null , palletCode : '' , selectedPalletId : '' , boxCode : '' , carton : null , actualQuantity : '' , discrepancyRemark : '' , activeScan : 'boxCode' , loading : false , submitting : false , printing : false , error : '' , notice : '' } } ,
computed : {
statusLabel ( ) { return this . task ? . taskStatus === 'COMPLETED' ? '已完成' : ( this . task ? . taskStatus === 'CLAIMED' ? '作业中' : '待领取' ) } ,
palletSetupReady ( ) { return this . task ? . palletSetupReady === true } ,
palletSetupMessage ( ) { return this . task ? . palletSetupMessage || ` 预计 ${ this . task ? . expectedPalletCount || 0 } 托,当前仅生成 ${ this . task ? . generatedPalletCount || 0 } 个托盘码,请联系后台处理后刷新 ` } ,
quantityDiffers ( ) { return this . carton && Number ( this . actualQuantity ) !== Number ( this . carton . expectedSkuQuantity ) } ,
canResolveCarton ( ) { return Boolean ( this . palletSetupReady && this . task ? . taskStatus === 'CLAIMED' && String ( this . boxCode || '' ) . trim ( ) && ! this . loading && ! this . submitting ) } ,
canCount ( ) { return Boolean ( this . carton ? . canCount && Number ( this . actualQuantity ) > 0 && ( ! this . quantityDiffers || this . discrepancyRemark . trim ( ) ) ) } ,
currentPallet ( ) { return ( this . task ? . pallets || [ ] ) . find ( ( item ) => String ( item . palletId ) === String ( this . selectedPalletId ) && item . status === 'OPEN' ) || null }
} ,
@@ -72,7 +90,7 @@
methods : {
startScanner ( ) { this . stopScanner ( ) ; this . _stopScanner = startScanBroadcast ( { onScan : ( value ) => this . handleScan ( value ) , onError : ( ) => { this . error = '扫码头连接失败,可使用输入框继续作业' } } ) } ,
stopScanner ( ) { if ( this . _stopScanner ) this . _stopScanner ( ) ; this . _stopScanner = null } ,
handleScan ( value ) { const code = String ( value ) . trim ( ) . toUpperCase ( ) ; if ( code . startsWith ( 'DP-' ) ) { this . palletCode = code ; this . selectPallet ( code ) } else { this . boxCode = code ; this . resolveCarton ( ) } } ,
handleScan ( value ) { if ( ! this . palletSetupReady ) { this . error = this . palletSetupMessage ; return } const code = String ( value ) . trim ( ) . toUpperCase ( ) ; if ( code . startsWith ( 'DP-' ) ) { this . palletCode = code ; this . selectPallet ( code ) } else { this . boxCode = code ; this . resolveCarton ( ) } } ,
resetMessages ( ) { this . error = '' ; this . notice = '' } ,
async loadTask ( ) {
if ( ! this . taskId || ! this . warehouseId ) { this . error = '缺少合托任务或仓库信息,请返回任务列表' ; return }
@@ -83,6 +101,7 @@
} ,
async claimTask ( ) { await this . runMutation ( ( ) => claimDropshipPalletizationTask ( this . taskId , this . warehouseId ) , '任务领取成功' ) } ,
async resolveCarton ( value ) {
if ( ! this . palletSetupReady ) { this . error = this . palletSetupMessage ; return }
const code = String ( value || this . boxCode || '' ) . trim ( ) . toUpperCase ( ) ; if ( ! code || this . loading ) return
this . boxCode = code ; this . loading = true ; this . resetMessages ( ) ; this . carton = null
try { this . carton = await resolveDropshipCarton ( this . taskId , this . warehouseId , code ) ; this . actualQuantity = String ( this . carton . expectedSkuQuantity || '' ) }
@@ -94,6 +113,7 @@
if ( result ) { this . boxCode = '' ; this . carton = null ; this . actualQuantity = '' ; this . discrepancyRemark = '' }
} ,
async selectPallet ( value ) {
if ( ! this . palletSetupReady ) { this . error = this . palletSetupMessage ; return }
const code = String ( value || this . palletCode || '' ) . trim ( ) . toUpperCase ( ) ; const pallet = ( this . task ? . pallets || [ ] ) . find ( ( item ) => item . palletNo === code )
if ( ! pallet ) { this . error = '托盘码不属于当前一件代发任务' ; return }
if ( pallet . status !== 'OPEN' ) { this . error = '托盘已封托,不能继续归托' ; return }
@@ -146,8 +166,10 @@
. status , . pallet - status { flex - shrink : 0 ; padding : 4 px 8 px ; border - radius : 99 px ; color : # 155 eef ; font - size : 10 px ; background : # eff4ff ; } . pallet - status . sealed { color : # 067647 ; background : # ecfdf3 ; }
. customer { display : block ; margin - top : 6 px ; color : # 667085 ; font - size : 11 px ; }
. metrics { display : grid ; grid - template - columns : repeat ( 4 , 1 fr ) ; margin : 12 px 0 ; padding : 10 px 0 ; border - top : 1 px solid # edf1f5 ; border - bottom : 1 px solid # edf1f5 ; } . metrics view { display : flex ; flex - direction : column ; align - items : center ; border - right : 1 px solid # edf1f5 ; } . metrics view : last - child { border : 0 ; } . metrics strong { font - size : 17 px ; } . metrics text { margin - top : 2 px ; color : # 667085 ; font - size : 10 px ; }
. pallet - readiness { display : flex ; justify - content : center ; gap : 18 px ; margin - top : - 2 px ; color : # 067647 ; font - size : 11 px ; font - weight : 700 ; } . pallet - readiness . invalid { color : # b42318 ; } . pallet - setup - error { margin - top : 10 px ; margin - bottom : 0 ; text - align : left ; }
. section - title { display : block ; color : # 12233 f ; font - size : 16 px ; font - weight : 700 ; } . section - desc { display : block ; margin : 3 px 0 11 px ; color : # 667085 ; font - size : 11 px ; line - height : 17 px ; } . section - heading > view { min - width : 0 ; }
. primary - button , . secondary - button { box - sizing : border - box ; width : 100 % ; height : 46 px ; margin - top : 10 px ; border - radius : 9 px ; font - size : 14 px ; font - weight : 700 ; line - height : 44 px ; } . primary - button { border : 0 ; color : # fff ; background : # 1 a73e8 ; } . secondary - button { border : 1 px solid # 8 ab8ef ; color : # 155 eef ; background : # f6f9ff ; } . primary - button [ disabled ] , . secondary - button [ disabled ] { opacity : .45 ; }
. count - entry { margin - top : 9 px ; padding : 10 px ; border : 1 px solid # dbe8f8 ; border - radius : 9 px ; color : # 52657 a ; font - size : 11 px ; line - height : 17 px ; background : # f6f9ff ; } . count - button { margin - top : 8 px ; } . count - unavailable { padding : 18 px 10 px ; border - radius : 9 px ; color : # b42318 ; font - size : 12 px ; line - height : 18 px ; text - align : center ; background : # fff1f0 ; } . pallet - scan - block { margin - top : 13 px ; padding - top : 12 px ; border - top : 1 px solid # e6edf5 ; } . field - label { display : block ; margin - bottom : 7 px ; color : # 344054 ; font - size : 12 px ; font - weight : 700 ; }
. carton - card , . pallet - card { margin - top : 11 px ; padding : 11 px ; border : 1 px solid # e3eaf2 ; border - radius : 9 px ; background : # f8fbff ; } . carton - head { color : # 12233 f ; font - size : 13 px ; font - weight : 700 ; } . carton - line , . pallet - meta { display : block ; margin - top : 5 px ; color : # 667085 ; font - size : 11 px ; line - height : 17 px ; }
. field { display : flex ; align - items : center ; justify - content : space - between ; gap : 12 px ; margin - top : 10 px ; color : # 344054 ; font - size : 12 px ; } . field input { box - sizing : border - box ; width : 120 px ; height : 42 px ; padding : 0 10 px ; border : 1 px solid # cfd8e3 ; border - radius : 8 px ; background : # fff ; } . field . stacked { align - items : stretch ; flex - direction : column ; gap : 6 px ; } . field textarea { box - sizing : border - box ; width : 100 % ; height : 70 px ; padding : 9 px ; border : 1 px solid # cfd8e3 ; border - radius : 8 px ; background : # fff ; }
. pallet - card { background : # fff ; } . pallet - code { color : # 12233 f ; font - size : 15 px ; font - weight : 700 ; overflow - wrap : anywhere ; } . text - button { min - width : 58 px ; height : 40 px ; border : 0 ; color : # 155 eef ; font - size : 12 px ; line - height : 40 px ; background : transparent ; } . empty { padding : 18 px 0 8 px ; color : # 98 a2b3 ; font - size : 12 px ; text - align : center ; }