This commit is contained in:
2026-09-11 17:27:33 +08:00
parent 88a1601814
commit 22fcaba78d
3 changed files with 44 additions and 11 deletions
@@ -54,14 +54,13 @@
</view>
<view class="section-card">
<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 ? '正在生成 A4 文件…' : '打开 A4 托盘单' }}</button>
<button v-if="pallet.status === 'OPEN'" class="primary-button" :disabled="!pallet.cartonCount || submitting" @tap="sealPallet(pallet)">封托</button>
<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="batch-print-row"><text>已生成 {{ task.generatedPalletCount || 0 }} 个托盘码</text><button class="text-button batch-print" :disabled="printing || !task.generatedPalletCount" @tap="printAllPallets">打开全部 A4 托盘单</button></view>
<view v-if="currentPalletDetails" class="pallet-card">
<view class="pallet-head"><text class="pallet-code">{{ currentPalletDetails.palletNo }}</text><text class="pallet-status" :class="currentPalletDetails.status === 'SEALED' ? 'sealed' : ''">{{ currentPalletDetails.status === 'SEALED' ? '已封托' : '待封托' }}</text></view>
<text class="pallet-meta">{{ currentPalletDetails.cartonCount || 0 }} 箱 · {{ currentPalletDetails.skuCount || 0 }} SKU · {{ currentPalletDetails.weightKg || 0 }} kg · {{ currentPalletDetails.volumeCbm || 0 }} m³</text>
<button class="secondary-button" :disabled="printing" @tap="printPallet(currentPalletDetails)">{{ printing ? '正在生成 A4 文件…' : '打开当前托盘 A4 单' }}</button>
<button v-if="currentPalletDetails.status === 'OPEN'" class="primary-button" :disabled="!currentPalletDetails.cartonCount || submitting" @tap="sealPallet(currentPalletDetails)">封托</button>
</view>
</view>
</template>
@@ -72,7 +71,7 @@
<script>
import PortalHeader from '@/components/PortalHeader.vue'
import ScanTargetInput from '@/components/ScanTargetInput.vue'
import { bindDropshipPendingCartons, claimDropshipPalletizationTask, countDropshipCarton, downloadDropshipPalletLabel, getDropshipPalletizationTask, resolveDropshipCarton, sealDropshipPallet } from '@/api/pda-dropship.js'
import { bindDropshipPendingCartons, claimDropshipPalletizationTask, countDropshipCarton, downloadAllDropshipPalletLabels, downloadDropshipPalletLabel, getDropshipPalletizationTask, resolveDropshipCarton, sealDropshipPallet } from '@/api/pda-dropship.js'
import { session, requireSession } from '@/stores/session.js'
import { formatApiError } from '@/utils/user-facing.js'
import { startScanBroadcast } from '@/utils/scan-broadcast.js'
@@ -86,7 +85,8 @@
palletSetupMessage() { return this.task?.palletSetupMessage || `预计 ${this.task?.expectedPalletCount || 0} 托,当前仅生成 ${this.task?.generatedPalletCount || 0} 个托盘码,请联系后台处理后刷新` },
canResolveCarton() { return Boolean(this.palletSetupReady && this.task?.taskStatus === 'CLAIMED' && String(this.boxCode || '').trim() && !this.loading && !this.submitting) },
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) => item.palletNo === this.selectedPalletNo && item.status === 'OPEN') || (this.selectedPalletNo ? { palletNo: this.selectedPalletNo, status: 'OPEN' } : null) }
currentPalletDetails() { return (this.task?.pallets || []).find((item) => item.palletNo === this.selectedPalletNo) || null },
currentPallet() { return this.currentPalletDetails?.status === 'OPEN' ? this.currentPalletDetails : (this.selectedPalletNo ? { palletNo: this.selectedPalletNo, status: 'OPEN' } : null) }
},
onLoad(options) { this.taskId = String(options.taskId || ''); this.warehouseId = String(options.warehouseId || '') },
onShow() { if (!requireSession()) return; this.user = session.currentUser; this.startScanner(); this.loadTask() },
@@ -144,6 +144,21 @@
} catch (error) { this.error = formatApiError(error, '托盘码打印失败') }
finally { this.printing = false }
},
async printAllPallets() {
if (this.printing) return
this.printing = true; this.resetMessages()
try {
const filePath = await downloadAllDropshipPalletLabels(this.taskId, this.warehouseId)
// #ifdef H5
const link = document.createElement('a'); link.href = filePath; link.download = `${this.task.inboundCode}-全部托盘码.pdf`; link.click()
// #endif
// #ifndef H5
await new Promise((resolve, reject) => uni.openDocument({ filePath, fileType: 'pdf', showMenu: true, success: resolve, fail: reject }))
// #endif
this.notice = `已打开 ${this.task.generatedPalletCount || 0} 个托盘码的 A4 文件`
} catch (error) { this.error = formatApiError(error, '全部托盘码打印失败') }
finally { this.printing = false }
},
async runMutation(action, message) {
if (this.submitting) return null
this.submitting = true; this.resetMessages()
@@ -181,5 +196,6 @@
.quantity-stepper { display: grid; grid-template-columns: 38px 56px 38px; overflow: hidden; border: 1px solid #b8c6d8; border-radius: 8px; background: #fff; }.quantity-stepper button,.quantity-stepper input { box-sizing: border-box; height: 40px; margin: 0; border: 0; border-radius: 0; text-align: center; background: #fff; }.quantity-stepper button { color: #155eef; font-size: 20px; line-height: 40px; }.quantity-stepper input { width: 56px; border-right: 1px solid #dce4ed; border-left: 1px solid #dce4ed; color: #12233f; font-size: 15px; }.difference-field { grid-column: 1 / -1; margin-top: 0; }.pallet-hint { display: block; margin-top: 10px; color: #155eef; font-size: 11px; text-align: center; }
.field { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 10px; color: #344054; font-size: 12px; }.field input { box-sizing: border-box; width: 120px; height: 42px; padding: 0 10px; border: 1px solid #cfd8e3; border-radius: 8px; background: #fff; }.field.stacked { align-items: stretch; flex-direction: column; gap: 6px; }.field textarea { box-sizing: border-box; width: 100%; height: 70px; padding: 9px; border: 1px solid #cfd8e3; border-radius: 8px; background: #fff; }
.pallet-code { color: #12233f; font-size: 19px; font-weight: 700; overflow-wrap: anywhere; }.text-button { min-width: 58px; height: 40px; border: 0; color: #155eef; font-size: 14px; line-height: 40px; background: transparent; }.empty { padding: 18px 0 8px; color: #98a2b3; font-size: 14px; text-align: center; }
.batch-print-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 7px 0; border-top: 1px solid #edf1f5; color: #667085; font-size: 13px; }.batch-print { min-width: 148px; padding: 0 4px; font-weight: 700; }
.palletization-page :deep(.scan-target-value) { font-size: 17px; }
</style>