优化
This commit is contained in:
@@ -13,7 +13,7 @@ const props = defineProps<{ dispatchNo: string }>()
|
||||
const auth = useAuthStore(), access = useAccessPreviewStore()
|
||||
const emit = defineEmits<{ saved: [] }>()
|
||||
const snapshot = ref<VehicleDocuments | null>(null), busy = ref(false), error = ref<ApiErrorDetails | null>(null)
|
||||
interface Pending { slot: FuelSlot; key: string; photo?: VehiclePhoto; binding?: BindVehiclePhoto }
|
||||
interface Pending { slot: FuelSlot; key: string; photo?: VehiclePhoto; binding?: BindVehiclePhoto; versionConflict?: boolean }
|
||||
const pending = ref<Pending | null>(null), preview = ref(''), corrupted = ref(false)
|
||||
const actor = auth.user?.id || '', number = props.dispatchNo
|
||||
const storageKey = `dispatch-vehicle-documents:${actor}:${number}`
|
||||
@@ -33,7 +33,13 @@ async function bind() {
|
||||
if (!item?.photo || !snapshot.value) return
|
||||
if (item.photo.slot !== item.slot) throw new Error('上传结果与图片分类不一致')
|
||||
if (!item.binding) { item.binding = { recordVersion: snapshot.value.recordVersion, idempotencyKey: crypto.randomUUID(), fileId: item.photo.fileId }; persist() }
|
||||
const result = await bindVehiclePhoto(number, item.slot, item.binding)
|
||||
let result: VehicleDocuments
|
||||
try { result = await bindVehiclePhoto(number, item.slot, item.binding) }
|
||||
catch (cause) {
|
||||
const details = getApiErrorDetails(cause, '图片保存失败')
|
||||
if (details.code === 'A0409' && /记录版本已变化|记录版本竞争失败/.test(details.message)) { item.versionConflict = true; persist() }
|
||||
throw cause
|
||||
}
|
||||
ensureScope(); snapshot.value = result; pending.value = null; persist(); emit('saved'); ElMessage.success('油耗图片已保存')
|
||||
}
|
||||
async function recover() {
|
||||
@@ -43,6 +49,13 @@ async function recover() {
|
||||
catch (cause) { if (active) error.value = getApiErrorDetails(cause, '原上传或保存结果尚未确认') }
|
||||
finally { if (active) busy.value = false }
|
||||
}
|
||||
async function refreshBinding() {
|
||||
if (busy.value || !editable.value || !pending.value?.versionConflict) return
|
||||
await load()
|
||||
if (error.value || !pending.value) return
|
||||
pending.value.binding = undefined; pending.value.versionConflict = false; persist()
|
||||
await recover()
|
||||
}
|
||||
async function upload(slot: FuelSlot, event: Event) {
|
||||
const input = event.target as HTMLInputElement, file = input.files?.[0]; input.value = ''
|
||||
if (!file || busy.value || pending.value || !editable.value) return
|
||||
@@ -51,7 +64,12 @@ async function upload(slot: FuelSlot, event: Event) {
|
||||
try {
|
||||
ensureScope(); pending.value = { slot, key: crypto.randomUUID() }; persist()
|
||||
pending.value.photo = await uploadVehiclePhoto(number, slot, file, pending.value.key); ensureScope(); persist(); await bind()
|
||||
} catch (cause) { if (active) error.value = getApiErrorDetails(cause, '图片上传或保存失败,请核对原请求') }
|
||||
} catch (cause) {
|
||||
if (active) {
|
||||
error.value = getApiErrorDetails(cause, '图片上传或保存失败,请核对原请求')
|
||||
if (!pending.value?.photo && ['A0400', 'A0403'].includes(error.value.code || '')) { pending.value = null; persist() }
|
||||
}
|
||||
}
|
||||
finally { if (active) busy.value = false }
|
||||
}
|
||||
async function view(photo: VehiclePhoto) {
|
||||
@@ -74,7 +92,7 @@ defineExpose({ busy })
|
||||
<template>
|
||||
<div v-loading="busy" class="density-dialog-sections">
|
||||
<LoadErrorState v-if="error" compact title="车辆资料操作失败" :message="error.message" :show-retry="!pending && !corrupted" @retry="load"><template #details><ApiErrorMeta :details="error" /></template></LoadErrorState>
|
||||
<div v-if="pending" role="status">有图片尚未确认保存。<el-button :disabled="busy || !editable" @click="recover">核对原请求并继续保存</el-button></div>
|
||||
<div v-if="pending" role="status">有图片尚未确认保存。<el-button v-if="pending.versionConflict" :disabled="busy || !editable" @click="refreshBinding">刷新版本并保存已上传图片</el-button><el-button v-else :disabled="busy || !editable" @click="recover">核对原请求并继续保存</el-button></div>
|
||||
<section v-for="role in roles" :key="role.slot" class="density-dialog-section">
|
||||
<h3 class="density-dialog-section__title">{{ role.label }}</h3>
|
||||
<div v-for="photo in snapshot?.photos.filter(item => item.slot === role.slot) || []" :key="photo.fileId"><el-button link :disabled="busy" @click="view(photo)">{{ photo.fileName }}</el-button></div>
|
||||
|
||||
Reference in New Issue
Block a user