Files
admin-web/src/modules/trucking/components/TruckAttachmentDialog.vue
T

34 lines
3.8 KiB
Vue
Raw Normal View History

2026-08-08 13:32:27 +08:00
<script setup lang="ts">
2026-08-08 15:57:07 +08:00
import { ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
2026-08-14 14:27:03 +08:00
import { FileUp, Trash2 } from '@lucide/vue'
import { deleteTruckAppointmentAttachment, uploadTruckAppointmentAttachment } from '../api/platformTrucking'
2026-08-08 13:32:27 +08:00
import type { TruckAttachmentReference } from '../types'
2026-08-08 15:57:07 +08:00
const props = defineProps<{ modelValue: boolean; appointmentId?: string; attachments: TruckAttachmentReference[]; canManage?: boolean }>()
const emit = defineEmits<{ 'update:modelValue': [boolean]; changed: [] }>()
2026-08-11 19:59:15 +08:00
const busy = ref(false)
2026-08-14 14:27:03 +08:00
const selectedFile = ref<File | null>(null)
const selectedType = ref('OTHER')
2026-08-18 16:09:43 +08:00
const attachmentTypeLabels: Record<string, string> = { BILL_OF_LADING: '提单文件', DISPATCH_ORDER: '派车单', DRIVER_DOCUMENT: '司机证件', VEHICLE_DOCUMENT: '车辆证件', OTHER: '其他附件' }
2026-08-11 19:59:15 +08:00
function attachmentTypeLabel(value: string | null | undefined) { return value ? attachmentTypeLabels[value] || '业务附件' : '业务附件' }
2026-08-14 14:27:03 +08:00
function selectFile(upload: { raw?: File }) { selectedFile.value = upload.raw || null }
async function upload() { if (!props.appointmentId || !selectedFile.value) return; busy.value = true; try { await uploadTruckAppointmentAttachment(props.appointmentId, selectedFile.value, selectedType.value); selectedFile.value = null; emit('changed'); ElMessage.success('附件上传成功') } catch { ElMessage.error('上传失败') } finally { busy.value = false } }
async function remove(item: TruckAttachmentReference) { if (!props.appointmentId || !item.id) return; await ElMessageBox.confirm('确认删除该附件引用?', '删除确认', { confirmButtonText: '确认', cancelButtonText: '取消', type: 'warning' }); busy.value = true; try { await deleteTruckAppointmentAttachment(props.appointmentId, item.id); emit('changed'); ElMessage.success('附件引用已删除') } catch { ElMessage.error('删除失败') } finally { busy.value = false } }
2026-08-08 13:32:27 +08:00
</script>
<template>
2026-08-11 19:59:15 +08:00
<el-dialog :model-value="props.modelValue" title="预约附件" width="min(640px, 94vw)" @update:model-value="emit('update:modelValue', $event)">
2026-08-14 14:27:03 +08:00
<div v-if="props.canManage" class="upload-panel"><el-select v-model="selectedType" aria-label="附件类型" style="width:160px"><el-option v-for="(label, type) in attachmentTypeLabels" :key="type" :label="label" :value="type" /></el-select><el-upload :auto-upload="false" :limit="1" :show-file-list="true" :on-change="selectFile" :on-remove="() => { selectedFile = null }"><el-button><FileUp :size="15" />选择附件</el-button></el-upload><el-button type="primary" :loading="busy" :disabled="!selectedFile" @click="upload">上传并关联</el-button></div>
2026-08-11 19:59:15 +08:00
<el-empty v-if="attachments.length === 0" description="暂无预约附件" :image-size="72" />
2026-08-08 14:13:32 +08:00
<div v-for="item in attachments" :key="item.fileId" class="attachment-row">
2026-08-11 19:59:15 +08:00
<div><strong>{{ item.fileName || '未命名文件' }}</strong><small>{{ attachmentTypeLabel(item.attachmentType) }}{{ item.uploadedAt ? ` · ${item.uploadedAt}` : '' }}</small></div>
2026-08-12 18:16:44 +08:00
<el-button v-if="props.appointmentId && props.canManage && item.id" size="small" type="danger" plain :loading="busy" @click="remove(item)"><Trash2 :size="15" />删除</el-button>
2026-08-08 13:32:27 +08:00
</div>
2026-08-08 14:13:32 +08:00
<template #footer><el-button type="primary" @click="emit('update:modelValue', false)">关闭</el-button></template>
2026-08-08 13:32:27 +08:00
</el-dialog>
</template>
<style scoped>
2026-08-14 14:27:03 +08:00
.upload-panel { display:flex; align-items:center; flex-wrap:wrap; gap:8px; margin-bottom:16px; }
2026-08-11 19:59:15 +08:00
.attachment-row { display:flex; justify-content:space-between; gap:12px; margin:14px 0; padding:12px; border:1px solid var(--el-border-color-lighter); border-radius:6px; overflow-wrap:anywhere; }.attachment-row small { display:block; margin-top:4px; color:var(--el-text-color-secondary); }
2026-08-08 14:13:32 +08:00
@media (max-width: 560px) { .attachment-row { flex-direction:column; } }
2026-08-08 13:32:27 +08:00
</style>