79 lines
4.8 KiB
Vue
79 lines
4.8 KiB
Vue
<script setup lang="ts">
|
|
import { computed, ref, watch, onBeforeUnmount } from 'vue'
|
|
import { ElMessage } from 'element-plus'
|
|
import { getRelabel, downloadRelabelDocument, type RelabelDetail } from '../api/warehouseServices'
|
|
const props = defineProps<{ relabelNo: string; detail?: RelabelDetail | null; inline?: boolean }>()
|
|
const loaded = ref<RelabelDetail | null>(null)
|
|
const loading = ref(false)
|
|
const error = ref('')
|
|
const busy = ref(false)
|
|
let generation = 0
|
|
const current = computed(() => props.detail || loaded.value)
|
|
/** 各申请分别加载,失败只影响资料区,不阻断订单详情。 */
|
|
async function load() {
|
|
const ticket = ++generation
|
|
loaded.value = null; error.value = ''
|
|
if (props.detail || !props.relabelNo) { loading.value = false; return }
|
|
loading.value = true
|
|
try { const result = await getRelabel(props.relabelNo); if (ticket === generation) loaded.value = result }
|
|
catch (cause) { if (ticket === generation) error.value = cause instanceof Error ? cause.message : '贴标资料加载失败' }
|
|
finally { if (ticket === generation) loading.value = false }
|
|
}
|
|
watch(() => [props.relabelNo, props.detail], () => { void load() }, { immediate: true })
|
|
interface DocumentRow { key: string; kind: string; fileId: string; fileName: string; scope: string; itemId?: string }
|
|
const documents = computed<DocumentRow[]>(() => {
|
|
const result: DocumentRow[] = []
|
|
const application = current.value?.application
|
|
if (!application) return result
|
|
// 旧总文件仅作为兼容回显,避免与已分类型的总文件重复展示。
|
|
const add = (kind: string, id: string | null | undefined, name: string | null | undefined, scope: string, itemId?: string) => {
|
|
if (id) result.push({ key: scope + ':' + (itemId || '') + ':' + id, kind, fileId: id, fileName: name || '未命名文件', scope, itemId })
|
|
}
|
|
add('箱唛贴标文件', application.cartonTotalFileId, application.cartonTotalFileName, 'CARTON_TOTAL')
|
|
add('SKU 贴标文件', application.skuTotalFileId, application.skuTotalFileName, 'SKU_TOTAL')
|
|
if (application.totalFileId !== application.cartonTotalFileId && application.totalFileId !== application.skuTotalFileId)
|
|
add('贴标总文件', application.totalFileId, application.totalFileName, 'TOTAL')
|
|
add('面单文件', application.shippingLabelFileId, application.shippingLabelFileName, 'SHIPPING')
|
|
for (const item of current.value?.items || []) add('明细文件', item.relabelFileId, item.relabelFileName, 'ITEM', String(item.id))
|
|
return result
|
|
})
|
|
/** 使用带身份认证的下载接口,保留文件归属校验和原始文件名。 */
|
|
async function downloadFile(key: string) {
|
|
const row = documents.value.find(document => document.key === key)
|
|
if (!row || busy.value) return
|
|
busy.value = true
|
|
const ticket = generation
|
|
try {
|
|
const blob = await downloadRelabelDocument(props.relabelNo, row.fileId, row.scope, row.itemId)
|
|
if (ticket !== generation) return
|
|
const url = URL.createObjectURL(blob); const link = document.createElement('a')
|
|
link.href = url; link.download = row.fileName; link.click(); window.setTimeout(() => URL.revokeObjectURL(url), 1000)
|
|
} catch (cause) { ElMessage.error(cause instanceof Error ? cause.message : '文件读取失败,请重试') }
|
|
finally { busy.value = false }
|
|
}
|
|
onBeforeUnmount(() => { ++generation })
|
|
</script>
|
|
<template>
|
|
<section class="relabel-documents" :class="{ 'relabel-documents--inline': inline }" aria-label="客户上传的贴标文件">
|
|
<h3>贴标文件</h3>
|
|
<p v-if="loading">资料加载中…</p>
|
|
<p v-else-if="error" role="alert">{{ error }} <el-button link type="primary" @click="load">重试</el-button></p>
|
|
<div v-else-if="inline" class="relabel-document-links">
|
|
<div v-for="row in documents" :key="row.key" class="relabel-document-link"><span>{{ row.kind }}</span><el-button link type="primary" :disabled="busy" @click="downloadFile(row.key)">下载</el-button></div>
|
|
<span v-if="!documents.length">暂无上传的贴标文件</span>
|
|
</div>
|
|
<el-table v-else :data="documents" row-key="key" border empty-text="暂无上传的贴标文件">
|
|
<el-table-column prop="kind" label="文件类型" min-width="150" />
|
|
<el-table-column label="操作" width="90"><template #default="{ row }"><el-button link type="primary" :disabled="busy" @click="downloadFile(String(row.key))">下载</el-button></template></el-table-column>
|
|
</el-table>
|
|
</section>
|
|
</template>
|
|
<style scoped>
|
|
.relabel-documents { margin: 16px 0; }
|
|
.relabel-documents h3 { margin: 0 0 12px; font-size: 14px; }
|
|
.relabel-documents--inline { display: flex; align-items: center; gap: 12px; margin: 0; min-width: 0; }
|
|
.relabel-documents--inline h3 { flex-shrink: 0; margin: 0; color: var(--muted); font-size: 12px; font-weight: 400; }
|
|
.relabel-document-links { display: flex; flex-wrap: wrap; gap: 4px 12px; }
|
|
.relabel-document-link { display: flex; align-items: center; gap: 8px; }
|
|
</style>
|