@@ -29,17 +29,15 @@
< button class = "compact-action" :disabled = "!canResolveCarton" @tap ="resolveCarton()" > 读取 SKU < / button >
< / view >
< view v-if = "carton" class="carton-card" >
< text class = "sku-label" > SKU < / text >
< text class = "sku-code" > { { carton . skuCode || '—' } } < / text >
< view class = "quantity-row" >
< text > 清点数量 < / text >
< view v-for = "(line, index) in skuCounts" :key="line.inboundDetailId" class="sku-count-row" >
< view class = "sku-copy" > < text class = "sku-label" > SKU { { index + 1 } } < / text > < text class = "sku-code" > { { line . skuCode || '—' } } < / text > < / view >
< view class = "quantity-stepper" >
< button aria -label = " 减少 清点数量" @tap ="adjustQuantity(-1)" > − < / button >
< input v-model = "actualQuantity" type="number" aria-label="清点数量" / >
< button aria -label = " 增加 清点数量" @tap ="adjustQuantity(1)" > + < / button >
< button : aria -label = " ` 减少 $ { line.skuCode } 清点数量 ` " @tap ="adjustQuantity(index, -1)" > − < / button >
< input v-model = "line. actualQuantity" type="number" : aria-label="`${line.skuCode} 清点数量` " / >
< button : aria -label = " ` 增加 $ { line.skuCode } 清点数量 ` " @tap ="adjustQuantity(index, 1)" > + < / button >
< / view >
< view v-if = "lineDiffers(line)" class="field stacked difference-field"><text>差异说明</text><textarea v-model="line.discrepancyRemark" maxlength="500" placeholder="数量不一致时必填" / > < / view >
< / view >
< view v-if = "quantityDiffers" class="field stacked"><text>差异说明</text><textarea v-model="discrepancyRemark" maxlength="500" placeholder="数量不一致时必填" / > < / view >
< text v-if = "currentPallet" class="pallet-hint" > 归入 {{ currentPallet.palletNo }} < / text >
< button class = "primary-button" : disabled = "!canCount || submitting" @tap ="countCarton" > 确认清点 < / button >
< / view >
@@ -52,13 +50,13 @@
< / view >
< view class = "section-card" >
< view class = "section-heading" > < view > < text class = "section-title" > 2. 托盘码 < / text > < text class = "section-desc" > 打印贴码 , 装完后封托 < / text > < / view > < button class = "text-button" :disabled = "loading" @tap ="loadTask" > 刷新 < / button > < / view >
< view class = "section-heading" > < view > < text class = "section-title" > 2. 托盘码 < / text > < text class = "section-desc" > 打开 A4 托盘信息单 , 装完后封托 < / text > < / view > < button class = "text-button" :disabled = "loading" @tap ="loadTask" > 刷新 < / button > < / view >
< view v-if = "!task.pallets || !task.pallets.length" class="empty" > 暂无托盘 < / view >
< view v-for = "pallet in task.pallets" :key="pallet.palletId" class="pallet-card" >
< view class = "pallet-head" > < text class = "pallet-code" > { { pallet . palletNo } } < / text > < text class = "pallet-status" : class = "pallet.status === 'SEALED' ? 'sealed' : ''" > { { pallet . status === 'SEALED' ? '已封托' : '待封托' } } < / text > < / view >
< text class = "pallet-meta" > { { pallet . cartonCount || 0 } } 箱 · { { pallet . skuCount || 0 } } SKU · { { pallet . weightKg || 0 } } kg · { { pallet . volumeCbm || 0 } } m³ < / text >
< button v-if = "pallet.status === 'OPEN'" class="secondary-button" :disabled="submitting" @tap="selectPallet(pallet.palletNo)" > {{ currentPallet ? .palletId = = = pallet.palletId ? ' 当前托盘 ' : ' 设为当前托盘 ' }} < / button >
< button class = "secondary-button" :disabled = "printing" @tap ="printPallet(pallet)" > {{ printing ? ' 正在生成打印 文件 … ' : ' 打印 托盘码 ' }} < / button >
< button class = "secondary-button" :disabled = "printing" @tap ="printPallet(pallet)" > {{ printing ? ' 正在生成 A4 文件 … ' : ' 打开 A4 托盘单 ' }} < / button >
< button v-if = "pallet.status === 'OPEN'" class="primary-button" :disabled="!pallet.cartonCount || submitting" @tap="sealPallet(pallet)" > 封托 < / button >
< / view >
< / view >
@@ -77,14 +75,13 @@
export default {
components : { PortalHeader , ScanTargetInput } ,
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 : '' } } ,
data ( ) { return { user : session . currentUser , taskId : '' , warehouseId : '' , task : null , palletCode : '' , selectedPalletId : '' , boxCode : '' , carton : null , skuCounts : [ ] , 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 ( ) ) ) } ,
canCount ( ) { return Boolean ( this . carton ? . canCount && this . skuCounts . length && this . skuCounts . every ( ( line ) => Number . isInteger ( Number ( line . actualQuantity ) ) && Number ( line . actualQuantity ) >= 0 && ( ! this . lineDiffers ( line ) || String ( line . discrepancyRemark || '' ) . trim ( ) ) ) ) } ,
currentPallet ( ) { return ( this . task ? . pallets || [ ] ) . find ( ( item ) => String ( item . palletId ) === String ( this . selectedPalletId ) && item . status === 'OPEN' ) || null }
} ,
onLoad ( options ) { this . taskId = String ( options . taskId || '' ) ; this . warehouseId = String ( options . warehouseId || '' ) } ,
@@ -107,15 +104,17 @@
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 || '' ) }
try { this . carton = await resolveDropshipCarton ( this . taskId , this . warehouseId , code ) ; this . skuCounts = ( this . carton . skuLines || [ ] ) . map ( ( line ) => ( { ... line , actualQuantity : String ( line . expectedQuantity || '' ) , discrepancyRemark : '' } ) ) }
catch ( error ) { this . error = formatApiError ( error , '箱码解析失败' ) }
finally { this . loading = false }
} ,
async countCarton ( ) {
const result = await this . runMutation ( ( ) => countDropshipCarton ( this . taskId , { warehouseId : this . warehouseId , boxCode : this . carton . boxCode , palletNo : this . currentPallet ? . palletNo || null , actualSkuQuantity : Number ( this . actualQuantity ) , discrepancyAction : this . quantityDiffers ? 'ACCEPT_VARIANCE' : 'MATCH' , discrepancyRemark : this . quantityDiffers ? this . discrepancyRemark . trim ( ) : null } ) , this . currentPallet ? '本箱已清点并归托' : '本箱已完成入库清点' )
if ( result ) { this . boxCode = '' ; this . carton = null ; this . actualQuantity = '' ; this . discrepancyRemark = '' }
const skuLines = this . skuCounts . map ( ( line ) => ( { inboundDetailId : line . inboundDetailId , skuCode : line . skuCode , actualQuantity : Number ( line . actualQuantity ) , discrepancyAction : this . lineDiffers ( line ) ? 'ACCEPT_VARIANCE' : 'MATCH' , discrepancyRemark : this . lineDiffers ( line ) ? String ( line . discrepancyRemark || '' ) . trim ( ) : null } ) )
const result = await this . runMutation ( ( ) => countDropshipCarton ( this . taskId , { warehouseId : this . warehouseId , boxCode : this . carton . boxCode , palletNo : this . currentPallet ? . palletNo || null , skuLines } ) , this . currentPallet ? '本箱已清点并归托 ' : '本箱已完成入库清点' )
if ( result ) { this . boxCode = '' ; this . carton = null ; this . skuCounts = [ ] }
} ,
adjustQuantity ( step ) { this . actualQuantity = String ( Math . max ( 1 , Number ( this . actualQuantity || 0 ) + step ) ) } ,
lineDiffers ( line ) { return Number ( line . actualQuantity ) !== Number ( line . expectedQuantity ) } ,
adjustQuantity ( index , step ) { const line = this . skuCounts [ index ] ; if ( line ) line . actualQuantity = String ( Math . max ( 0 , Number ( line . actualQuantity || 0 ) + step ) ) } ,
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 )
@@ -137,7 +136,7 @@
// #ifndef H5
await new Promise ( ( resolve , reject ) => uni . openDocument ( { filePath , fileType : 'pdf' , showMenu : true , success : resolve , fail : reject } ) )
// #endif
this . notice = ` ${ pallet . palletNo } 打印文件 已打开 `
this . notice = ` ${ pallet . palletNo } A4 托盘信息单 已打开 `
} catch ( error ) { this . error = formatApiError ( error , '托盘码打印失败' ) }
finally { this . printing = false }
} ,
@@ -173,8 +172,8 @@
. section - title { display : block ; color : # 12233 f ; font - size : 18 px ; font - weight : 700 ; } . section - desc { display : block ; margin : 2 px 0 8 px ; color : # 667085 ; font - size : 13 px ; line - height : 18 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 { display : flex ; align - items : center ; justify - content : space - between ; gap : 8 px ; margin - top : 6 px ; padding : 5 px 7 px ; border : 0 ; border - radius : 0 ; color : # 667085 ; font - size : 13 px ; background : # f6f9ff ; } . compact - action { width : 86 px ; height : 34 px ; margin : 0 ; border : 0 ; border - radius : 6 px ; color : # fff ; font - size : 13 px ; line - height : 34 px ; background : # 1 a73e8 ; } . compact - action [ disabled ] { opacity : .35 ; } . count - unavailable { padding : 12 px 8 px ; color : # b42318 ; font - size : 13 px ; line - height : 18 px ; text - align : center ; background : # fff1f0 ; } . pallet - scan - block { margin - top : 8 px ; padding - top : 8 px ; border - top : 1 px solid # e6edf5 ; } . field - label { display : block ; margin - bottom : 5 px ; color : # 344054 ; font - size : 15 px ; font - weight : 700 ; } . field - label text { margin - left : 3 px ; color : # 98 a2b3 ; font - size : 12 px ; font - weight : 400 ; }
. carton - card , . pallet - card { margin - top : 8 px ; padding : 10 px 0 0 ; border : 0 ; border - top : 1 px solid # e3eaf2 ; border - radius : 0 ; background : transparent ; } . sku - label { display : block ; color : # 667085 ; font - size : 12 px ; } . sku - code { display : block ; margin - top : 3 px ; color : # 12233 f ; font - size : 19 px ; font - weight : 700 ; overflow - wrap : anywhere ; } . pallet - meta { display : block ; margin - top : 5 px ; color : # 667085 ; font - size : 14 px ; line - height : 20 px ; }
. quantity - row { display : flex ; align - items : center ; justify - content : space - between ; gap : 12 px ; margin - top : 14 px ; color : # 344054 ; font - size : 13 px ; font - weight : 700 ; } . quantity - stepper { display : grid ; grid - template - columns : 44 px 72 px 44 px ; overflow : hidden ; border : 1 px solid # b8c6d8 ; border - radius : 9 px ; background : # fff ; } . quantity - stepper button , . quantity - stepper input { box - sizing : border - box ; height : 44 px ; margin : 0 ; border : 0 ; border - radius : 0 ; text - align : center ; background : # fff ; } . quantity - stepper button { color : # 155 eef ; font - size : 21 px ; line - height : 44 px ; } . quantity - stepper input { width : 72 px ; border - right : 1 px solid # dce4ed ; border - left : 1 px solid # dce4ed ; color : # 12233 f ; font - size : 16 px ; } . pallet - hint { display : block ; margin - top : 10 px ; color : # 155 eef ; font - size : 11 px ; text - align : center ; }
. carton - card , . pallet - card { margin - top : 8 px ; padding : 8 px 0 0 ; border : 0 ; border - top : 1 px solid # e3eaf2 ; border - radius : 0 ; background : transparent ; } . sku - count - row { display : grid ; grid - template - columns : minmax ( 0 , 1 fr ) auto ; align - items : center ; gap : 8 px ; padding : 8 px 0 ; border - bottom : 1 px solid # edf1f5 ; } . sku - copy { min - width : 0 ; } . sku - label { display : block ; color : # 667085 ; font - size : 11 px ; } . sku - code { display : block ; margin - top : 2 px ; color : # 12233 f ; font - size : 16 px ; font - weight : 700 ; overflow - wrap : anywhere ; } . pallet - meta { display : block ; margin - top : 5 px ; color : # 667085 ; font - size : 14 px ; line - height : 20 px ; }
. quantity - stepper { display : grid ; grid - template - columns : 38 px 56 px 38 px ; overflow : hidden ; border : 1 px solid # b8c6d8 ; border - radius : 8 px ; background : # fff ; } . quantity - stepper button , . quantity - stepper input { box - sizing : border - box ; height : 40 px ; margin : 0 ; border : 0 ; border - radius : 0 ; text - align : center ; background : # fff ; } . quantity - stepper button { color : # 155 eef ; font - size : 20 px ; line - height : 40 px ; } . quantity - stepper input { width : 56 px ; border - right : 1 px solid # dce4ed ; border - left : 1 px solid # dce4ed ; color : # 12233 f ; font - size : 15 px ; } . difference - field { grid - column : 1 / - 1 ; margin - top : 0 ; } . pallet - hint { display : block ; margin - top : 10 px ; color : # 155 eef ; font - size : 11 px ; text - align : center ; }
. 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 - code { color : # 12233 f ; font - size : 19 px ; font - weight : 700 ; overflow - wrap : anywhere ; } . text - button { min - width : 58 px ; height : 40 px ; border : 0 ; color : # 155 eef ; font - size : 14 px ; line - height : 40 px ; background : transparent ; } . empty { padding : 18 px 0 8 px ; color : # 98 a2b3 ; font - size : 14 px ; text - align : center ; }
. palletization - page : deep ( . scan - target - value ) { font - size : 17 px ; }