This commit is contained in:
2026-10-26 18:52:21 +08:00
parent 22242701e4
commit a9dc19a86b
12 changed files with 88 additions and 25 deletions
@@ -35,17 +35,18 @@ async function previews() {
async function load() {
if (busy.value) return
busy.value = true; error.value = null
try { accept(await getLoadingDocuments(number)); await previews() }
try { accept(await getLoadingDocuments(number)); await previews(); return true }
catch (cause) { if (active) { needsRefresh.value = true; error.value = getApiErrorDetails(cause, '装车资料读取失败') } }
finally { if (active) busy.value = false }
}
async function refresh() { if (await load()) emit('saved') }
function photosFor(slot: LoadingPhotoSlot) { return snapshot.value?.photos.filter(photo => photo.slot === slot) || [] }
async function upload(slot: LoadingPhotoSlot, event: Event, replaceFileId?: string) {
const input = event.target as HTMLInputElement, files = Array.from(input.files || []); input.value = ''
if (!files.length || busy.value || !editable.value) return
const capacity = replaceFileId ? 1 : 5 - photosFor(slot).length
if (files.length > capacity) { ElMessage.warning(`本次最多可选择${capacity}张图片`); return }
if (files.some(file => !['image/jpeg','image/png'].includes(file.type) || !file.size || file.size > 10 * 1024 * 1024)) { ElMessage.warning('请选择不超过10MiB的JPG或PNG图片'); return }
if (files.some(file => !(['image/jpeg','image/png'].includes(file.type) || slot === 'LOADING_SCENE' && file.type === 'application/pdf') || !file.size || file.size > 10 * 1024 * 1024)) { ElMessage.warning('请选择不超过10MiB的JPG或PNG,司机驾驶证也支持PDF'); return }
busy.value = true; error.value = null
let saved = 0, reconciled = false, bindingFailed = false
try {
@@ -86,17 +87,20 @@ defineExpose({ busy })
<template>
<div v-loading="busy" class="density-dialog-sections">
<p>可边装车边上传五类装车资料,每类至少 1 张、最多 5 张;装车确认完成且五类齐全后自动进入派送中。</p>
<p>司机驾驶证、车牌照片在理货审核通过后从本趟资料自动带入,可补充或更换;驾驶证支持 PDF。</p>
<div><el-button :loading="busy" :disabled="busy" aria-label="刷新装车资料" @click="refresh">刷新</el-button></div>
<p v-if="needsRefresh">保存状态尚未核实,请先重新读取资料后再上传。</p>
<LoadErrorState v-if="error" compact title="装车资料操作失败" :message="error.message" :show-retry="true" @retry="load"><template #details><ApiErrorMeta :details="error" /></template></LoadErrorState>
<table class="density-table loading-documents-table" aria-label="装车照片"><thead><tr><th class="photo-actions">操作</th><th class="photo-category">照片类别</th><th>文件名称</th><th class="photo-preview">图片预览</th><th class="photo-time">保存时间</th></tr></thead><tbody>
<tr v-for="slot in loadingPhotoSlots" :key="slot">
<td><label v-if="editable" class="photo-upload" :class="{ 'is-disabled': busy || photosFor(slot).length >= 5 }">{{ photosFor(slot).length >= 5 ? '已满 5 张' : '上传图片' }}<input type="file" multiple accept="image/jpeg,image/png" :aria-label="`上传${loadingPhotoLabels[slot]}`" :disabled="busy || photosFor(slot).length >= 5" @change="upload(slot, $event)" /></label><span v-else>—</span></td>
<td><label v-if="editable" class="photo-upload" :class="{ 'is-disabled': busy || photosFor(slot).length >= 5 }">{{ photosFor(slot).length >= 5 ? '已满 5 张' : '上传资料' }}<input type="file" multiple :accept="slot === 'LOADING_SCENE' ? 'image/jpeg,image/png,application/pdf' : 'image/jpeg,image/png'" :aria-label="`上传${loadingPhotoLabels[slot]}`" :disabled="busy || photosFor(slot).length >= 5" @change="upload(slot, $event)" /></label><span v-else>—</span></td>
<td>{{ loadingPhotoLabels[slot] }}<div>{{ photosFor(slot).length }}/5 张</div></td>
<td><div v-for="photo in snapshot?.photos.filter(item => item.slot === slot) || []" :key="photo.fileId">{{ photo.fileName }}</div><span v-if="!snapshot?.photos.some(item => item.slot === slot)">未上传</span></td>
<td><template v-for="photo in snapshot?.photos.filter(item => item.slot === slot) || []" :key="photo.fileId">
<el-image v-if="images[photo.fileId]" :src="images[photo.fileId]" :preview-src-list="[images[photo.fileId]!]" fit="contain" class="loading-photo-image" preview-teleported />
<a v-if="images[photo.fileId] && photo.contentType === 'application/pdf'" :href="images[photo.fileId]" target="_blank" rel="noopener noreferrer">查看驾驶证 PDF</a>
<el-image v-else-if="images[photo.fileId]" :src="images[photo.fileId]" :preview-src-list="[images[photo.fileId]!]" fit="contain" class="loading-photo-image" preview-teleported />
<el-button v-else link :disabled="busy" @click="load">图片读取失败,点击重试</el-button>
<label v-if="editable" class="photo-upload">更换<input type="file" accept="image/jpeg,image/png" :aria-label="`更换${photo.fileName}`" :disabled="busy" @change="upload(slot, $event, photo.fileId)" /></label>
<label v-if="editable" class="photo-upload">更换<input type="file" :accept="slot === 'LOADING_SCENE' ? 'image/jpeg,image/png,application/pdf' : 'image/jpeg,image/png'" :aria-label="`更换${photo.fileName}`" :disabled="busy" @change="upload(slot, $event, photo.fileId)" /></label>
</template><span v-if="!snapshot?.photos.some(item => item.slot === slot)">—</span></td>
<td><div v-for="photo in snapshot?.photos.filter(item => item.slot === slot) || []" :key="photo.fileId">{{ photo.savedAt?.replace('T', ' ') || '—' }}</div><span v-if="!snapshot?.photos.some(item => item.slot === slot)">—</span></td>
</tr>