Files
admin-web/src/modules/loading-lists/components/PalletLabelPrintDialog.vue
T
2026-09-14 17:54:21 +08:00

67 lines
4.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 '@/styles/adminDensity.css'
import { computed, ref } from 'vue'
import { Printer } from '@lucide/vue'
import { ElMessage } from 'element-plus'
import AppDialog from '@/shared/components/AppDialog.vue'
import LoadErrorState from '@/shared/components/LoadErrorState.vue'
import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
import { preparePalletLabels, printPalletLabels, type PalletLabelManifest } from '../api/platformLoadingLists'
const props = defineProps<{ planId: string; warehouseId: string; disabled?: boolean; dense?: boolean }>()
const open = ref(false)
const loading = ref(false)
const printing = ref(false)
const error = ref<ApiErrorDetails | null>(null)
const manifest = ref<PalletLabelManifest | null>(null)
const scope = ref<'ALL' | 'WAREHOUSE'>('ALL')
const warehouseCode = ref('')
const count = ref(1)
const selectedGroup = computed(() => manifest.value?.groups.find((group) => group.destinationWarehouseCode === warehouseCode.value) || null)
const disabledConfirm = computed(() => !manifest.value?.totalCount || (scope.value === 'WAREHOUSE' && (!selectedGroup.value || count.value < 1 || count.value > selectedGroup.value.totalCount)))
async function show() {
open.value = true; loading.value = true; error.value = null; manifest.value = null
try {
manifest.value = await preparePalletLabels(props.planId, props.warehouseId)
warehouseCode.value = manifest.value.groups[0]?.destinationWarehouseCode || ''
count.value = manifest.value.groups[0]?.totalCount || 1
} catch (cause) { error.value = getApiErrorDetails(cause, '托盘码清单加载失败') }
finally { loading.value = false }
}
function onWarehouseChange() { count.value = selectedGroup.value?.totalCount || 1 }
async function print() {
if (!manifest.value) return
printing.value = true; error.value = null
try {
const blob = await printPalletLabels(props.planId, props.warehouseId,
scope.value === 'WAREHOUSE' ? warehouseCode.value : undefined,
scope.value === 'WAREHOUSE' ? count.value : undefined)
const url = URL.createObjectURL(blob); const anchor = document.createElement('a')
anchor.href = url; anchor.download = `${manifest.value.containerNo}-托盘码.pdf`; anchor.click(); URL.revokeObjectURL(url)
ElMessage.success(`已生成 ${scope.value === 'ALL' ? manifest.value.totalCount : count.value} 张托盘码`)
} catch (cause) { error.value = getApiErrorDetails(cause, '托盘码打印失败') }
finally { printing.value = false }
}
</script>
<template>
<el-button :disabled="disabled" @click="show"><Printer :size="16" />打印托盘码</el-button>
<AppDialog :class="{ 'admin-density-dialog': dense }" v-model="open" title="散货托盘码" width="min(760px, calc(100vw - 28px))" confirm-text="生成 PDF" :loading="loading" :confirm-loading="printing" :confirm-disabled="disabledConfirm" @confirm="print">
<LoadErrorState v-if="error" compact title="托盘码操作失败" :message="error.message" :show-retry="false" />
<template v-if="manifest">
<el-alert type="info" :closable="false" :title="`编号规则:${manifest.containerNo}-FBA地址内部编号-三位序号;一件代发托盘不在此清单。`" />
<el-radio-group v-model="scope" class="print-scope"><el-radio value="ALL">全部打印({{ manifest.totalCount }} 张)</el-radio><el-radio value="WAREHOUSE">按 FBA 仓补打</el-radio></el-radio-group>
<div v-if="scope === 'WAREHOUSE'" class="print-options"><el-select v-model="warehouseCode" placeholder="选择 FBA 仓" @change="onWarehouseChange"><el-option v-for="group in manifest.groups" :key="group.destinationWarehouseCode" :label="`${group.destinationWarehouseCode} · ${group.totalCount} 张`" :value="group.destinationWarehouseCode" /></el-select><el-input-number v-model="count" placeholder="打印张数" :min="1" :max="selectedGroup?.totalCount || 1" /><span>张(从该仓第 1 张起)</span></div>
<el-table :data="manifest.groups" border max-height="300"><el-table-column label="FBA 仓编码" prop="destinationWarehouseCode" width="140" /><el-table-column label="内部编号" prop="destinationWarehouseInternalCode" width="120" /><el-table-column label="FBA 仓名称" prop="destinationWarehouseName" min-width="160"><template #default="{ row }">{{ row.destinationWarehouseName || '—' }}</template></el-table-column><el-table-column label="托盘数" prop="totalCount" width="90" align="right" /><el-table-column label="编号范围" min-width="230"><template #default="{ row }">{{ row.labels[0]?.palletCode || '—' }}<template v-if="row.labels.length > 1"> ~ {{ row.labels[row.labels.length - 1]?.palletCode }}</template></template></el-table-column></el-table>
</template>
</AppDialog>
</template>
<style scoped>
.print-scope { display:flex; margin:18px 0 var(--admin-space-5, 12px); }
.print-options { display:flex; align-items:center; gap:var(--admin-space-5, 12px); margin-bottom:var(--admin-space-6, 16px); }
.print-options .el-select { width:240px; }
</style>