Files
admin-web/src/modules/inbounds/core/DropshipPalletPrintPanel.vue
T

129 lines
5.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { onBeforeUnmount, ref, watch } from 'vue'
import { Printer, RefreshCw } from '@lucide/vue'
import { ElMessage } from 'element-plus'
import '@/styles/adminDensity.css'
import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'
import LoadErrorState from '@/shared/components/LoadErrorState.vue'
import { downloadAllDropshipPalletLabels, downloadDropshipPalletLabel, listPlatformInboundDropshipPallets } from './api'
import type { InboundDropshipPallet } from './types'
const props = defineProps<{
customerId: string
inboundId: string
inboundCode?: string | null
}>()
const pallets = ref<InboundDropshipPallet[]>([])
const loading = ref(false)
const loadError = ref<ApiErrorDetails | null>(null)
const printing = ref('')
let requestSerial = 0
let disposed = false
function statusLabel(status: InboundDropshipPallet['status']) {
return status === 'SEALED' ? '已封托' : '待封托'
}
function download(blob: Blob, fileName: string) {
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = fileName
link.click()
window.setTimeout(() => URL.revokeObjectURL(url), 0)
}
async function loadPallets() {
const serial = ++requestSerial
loading.value = true
loadError.value = null
try {
const response = await listPlatformInboundDropshipPallets(props.customerId, props.inboundId)
if (!disposed && serial === requestSerial) pallets.value = response
} catch (error) {
if (!disposed && serial === requestSerial) {
pallets.value = []
loadError.value = getApiErrorDetails(error, '一件代发托盘加载失败')
}
} finally {
if (!disposed && serial === requestSerial) loading.value = false
}
}
async function printAll() {
if (!pallets.value.length || printing.value) return
printing.value = 'all'
try {
const blob = await downloadAllDropshipPalletLabels(props.customerId, props.inboundId)
download(blob, `${props.inboundCode || '一件代发'}-全部托盘.pdf`)
ElMessage.success(`已生成 ${pallets.value.length} 个托盘的打印文件`)
} catch (error) {
ElMessage.error(getApiErrorDetails(error, '全部托盘打印文件生成失败').message)
} finally {
printing.value = ''
}
}
async function printOne(pallet: InboundDropshipPallet) {
if (!pallet.palletNo || printing.value) return
printing.value = pallet.palletId
try {
const blob = await downloadDropshipPalletLabel(props.customerId, props.inboundId, pallet.palletId)
download(blob, `${pallet.palletNo}-托盘.pdf`)
ElMessage.success(`${pallet.palletNo} 打印文件已生成`)
} catch (error) {
ElMessage.error(getApiErrorDetails(error, '单托打印文件生成失败').message)
} finally {
printing.value = ''
}
}
watch(() => [props.customerId, props.inboundId], loadPallets, { immediate: true })
onBeforeUnmount(() => { disposed = true; requestSerial += 1 })
</script>
<template>
<section class="dropship-print-panel admin-density" aria-labelledby="dropship-print-title">
<header class="print-heading">
<div>
<h3 id="dropship-print-title">一件代发托盘打印</h3>
<p>测量审核生成托盘码后,在电脑端打印并贴到空托盘,再交由 PDA 扫码组托。</p>
<p>箱数与 SKU 种类数按整托统计,包含合托的其他入仓码;相同 SKU 编码只计一种,不代表商品件数。</p>
</div>
<div class="print-actions">
<el-button :disabled="loading || Boolean(printing)" @click="loadPallets"><RefreshCw :size="15" />刷新</el-button>
<el-button type="primary" :disabled="!pallets.length" :loading="printing === 'all'" @click="printAll"><Printer :size="15" />打印全部托盘</el-button>
</div>
</header>
<LoadErrorState v-if="loadError" title="托盘数据暂时无法加载" :message="loadError.message" @retry="loadPallets">
<template #details><ApiErrorMeta :details="loadError" /></template>
</LoadErrorState>
<el-table v-else-if="pallets.length" v-loading="loading" :data="pallets" border stripe empty-text="暂无托盘码" aria-label="一件代发托盘打印列表">
<el-table-column label="操作" width="120" fixed="left">
<template #default="{ row }">
<el-button class="density-action" :loading="printing === row.palletId" :disabled="Boolean(printing) && printing !== row.palletId" @click="printOne(row as InboundDropshipPallet)">单托补打</el-button>
</template>
</el-table-column>
<el-table-column prop="palletNo" label="托盘码" min-width="210" />
<el-table-column label="状态" width="110"><template #default="{ row }"><el-tag size="small" :type="row.status === 'SEALED' ? 'success' : 'warning'" effect="plain">{{ statusLabel(row.status) }}</el-tag></template></el-table-column>
<el-table-column prop="cartonCount" label="整托箱数" width="120" align="right" />
<el-table-column prop="skuCount" label="SKU 种类数" width="120" align="right" />
</el-table>
<el-empty v-else-if="!loading" description="测量审核通过并生成托盘码后,可在这里打印" :image-size="64" />
<div v-else class="loading-state"><el-skeleton :rows="4" animated /></div>
</section>
</template>
<style scoped>
.dropship-print-panel { min-width: 0; }
.print-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--admin-space-5); margin-bottom: var(--admin-space-5); }
.print-heading h3 { margin: 0; color: var(--cc-text); font-size: var(--admin-font-section); }
.print-heading p { margin: var(--admin-space-1) 0 0; color: var(--cc-muted); font-size: var(--admin-font-caption); line-height: 1.5; }
.print-actions { display: flex; flex-shrink: 0; gap: var(--admin-space-2); }
.print-actions .el-button { margin-left: 0; }
.loading-state { padding: var(--admin-space-5) 0; }
</style>