49 lines
2.5 KiB
Vue
49 lines
2.5 KiB
Vue
<script setup lang="ts">
|
|
import '@/styles/adminWorkbench.css'
|
|
import { onBeforeUnmount, ref, watch } from 'vue'
|
|
import AppDialog from '@/shared/components/AppDialog.vue'
|
|
import LoadErrorState from '@/shared/components/LoadErrorState.vue'
|
|
import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'
|
|
import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
|
|
import { downloadDriverLicense } from '../api/drivers'
|
|
|
|
const open = defineModel<boolean>({ default: false })
|
|
const props = defineProps<{ driverId: string; fileId: string; driverName: string }>()
|
|
const url = ref(''), contentType = ref(''), loading = ref(false), error = ref<ApiErrorDetails | null>(null)
|
|
let request = 0
|
|
function release() { if (url.value) URL.revokeObjectURL(url.value); url.value = '' }
|
|
async function load() {
|
|
const current = ++request
|
|
release(); error.value = null; loading.value = true
|
|
try {
|
|
const blob = await downloadDriverLicense(props.driverId, props.fileId)
|
|
if (current !== request || !open.value) return
|
|
contentType.value = blob.type; url.value = URL.createObjectURL(blob)
|
|
} catch (cause) { if (current === request) error.value = getApiErrorDetails(cause, '驾驶证读取失败') }
|
|
finally { if (current === request) loading.value = false }
|
|
}
|
|
watch([open, () => props.driverId, () => props.fileId], () => {
|
|
if (open.value && props.driverId && props.fileId) void load()
|
|
else { request++; release(); loading.value = false }
|
|
})
|
|
onBeforeUnmount(() => { request++; release() })
|
|
</script>
|
|
|
|
<template>
|
|
<AppDialog v-model="open" class="admin-density-dialog admin-workbench is-dialog" title="驾驶证附件" width="620px" :show-confirm="false" cancel-text="关闭">
|
|
<p>{{ driverName }} · 驾驶证附件</p>
|
|
<LoadErrorState v-if="error" title="驾驶证读取失败" :message="error.message" @retry="load" ><template #details><ApiErrorMeta :details="error" /></template></LoadErrorState>
|
|
<div v-loading="loading" class="license-preview">
|
|
<iframe v-if="url && contentType === 'application/pdf'" :src="url" title="驾驶证 PDF 预览" />
|
|
<img v-else-if="url" :src="url" :alt="`${driverName}的驾驶证`" />
|
|
</div>
|
|
<a v-if="url" :href="url" :download="`驾驶证.${contentType === 'application/pdf' ? 'pdf' : contentType === 'image/png' ? 'png' : 'jpg'}`">下载驾驶证</a>
|
|
</AppDialog>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.license-preview { min-height: 160px; }
|
|
.license-preview iframe { width: 100%; height: 560px; border: 0; }
|
|
.license-preview img { display: block; max-width: 100%; max-height: 560px; margin: auto; object-fit: contain; }
|
|
</style>
|