feat(web-admin): add vehicle photo on self-vehicle page

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-08-02 10:36:21 +08:00
1 parent a552049de4
commit 9089e455e9
1 file changed
+95 -5
+95 -5
View File
@@ -107,6 +107,23 @@
header-align="center"
:index="(index) => (pagination.page - 1) * pagination.pageSize + index + 1"
/>
<el-table-column
v-if="isColumnVisible('photoUrls')"
label="照片"
min-width="80"
align="center"
header-align="center"
>
<template #default="{ row }">
<img
v-if="firstPhotoUrl(row.photoUrls)"
class="pl-photo-thumb"
:src="resolvePhotoDisplayUrl(firstPhotoUrl(row.photoUrls))"
alt="车辆照片"
/>
<span v-else class="pl-photo-thumb pl-photo-thumb--empty">未上传</span>
</template>
</el-table-column>
<el-table-column
prop="licensePlate"
label="车牌号"
@@ -127,6 +144,17 @@
</div>
</template>
</el-table-column>
<el-table-column
v-if="isColumnVisible('certAttachments')"
label="证书附件"
min-width="340"
align="left"
header-align="left"
>
<template #default="{ row }">
<PlCertListAttachmentCell :cert-list="row.certList" show-vehicle-part />
</template>
</el-table-column>
<el-table-column label="车辆类型" min-width="90" align="center" header-align="center" v-if="isColumnVisible('vehicleType')">
<template #default>
<el-tag type="success" size="small">自有</el-tag>
@@ -249,6 +277,15 @@
maxlength="512"
/>
</el-form-item>
<el-form-item label="车辆照片" style="grid-column: 1 / -1">
<AttachmentUploadField
ref="photoUploadRef"
v-model="formData.photoUrls"
:limit="1"
accept="image/*"
upload-folder="pl/vehicle-photo"
/>
</el-form-item>
</div>
<div class="sub-table-section">
@@ -364,6 +401,16 @@
<el-icon><Delete /></el-icon>删除
</el-button>
</template>
<template #photo>
<AttachmentUploadField
v-if="viewDetail?.photoUrls"
:model-value="viewDetail.photoUrls"
disabled
:limit="1"
accept="image/*"
/>
<span v-else>—</span>
</template>
<template #vehicleDetailTabs>
<PlVehicleCertPersonnelTabs
:cert-list="viewDetail?.certList || []"
@@ -383,6 +430,7 @@
<script setup lang="ts">
import ListToolbarEndActions from '@/components/business/list-toolbar-end-actions/index.vue'
import ListQuickSearchInput from '@/components/business/list-quick-search-input/index.vue'
import AttachmentUploadField from '@/components/business/attachment-upload-field/index.vue'
import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
import { Check, Close, Delete, Edit, Plus, RefreshLeft, Search, Van } from '@element-plus/icons-vue'
import {
@@ -399,6 +447,7 @@ import {
import PlVehicleCertPartTabs from '@/components/business/pl-vehicle-cert-part-tabs/index.vue'
import PlVehicleCertPersonnelTabs from '@/components/business/pl-vehicle-cert-personnel-tabs/index.vue'
import PlVehicleCertBadges from '@/components/business/pl-vehicle-cert-badges/index.vue'
import PlCertListAttachmentCell from '@/components/business/pl-cert-list-attachment-cell/index.vue'
import type { VehiclePersonnelViewRow } from '@/components/business/pl-vehicle-personnel-view-list/index.vue'
import SystemViewDialog, {
type ViewSection
@@ -414,6 +463,7 @@ import {
getPlVehicleStatusTagType,
normalizePlPersonnelSummaryDisplay
} from '@/utils/pl-display'
import { firstPhotoUrl, resolvePhotoDisplayUrl } from '@/utils/pl-photo'
import {
collectSelfVehicleRequiredCertErrors,
ensureSelfVehicleCertSlots,
@@ -442,6 +492,8 @@ const vehicleList = ref<Vehicle[]>([])
const carrierList = ref<Carrier[]>([])
const listColumnDefs = [
{ prop: 'photoUrls', label: '照片' },
{ prop: 'certAttachments', label: '证书附件' },
{ prop: 'vehicleType', label: '车辆类型' },
{ prop: 'vehicleStatus', label: '车辆状态' },
{ prop: 'loadCapacity', label: '载重(吨)' },
@@ -456,13 +508,14 @@ const {
isIndeterminate,
isColumnVisible,
resetToDefault
} = usePersistedListColumns('pl-self-vehicle-list-columns', listColumnDefs)
} = usePersistedListColumns('pl-self-vehicle-list-columns-v3', listColumnDefs)
const personnelOptions = ref<Personnel[]>([])
const selectedRows = ref<Vehicle[]>([])
const dialogVisible = ref(false)
const dialogTitle = ref('')
const formRef = ref()
const photoUploadRef = ref<InstanceType<typeof AttachmentUploadField>>()
const isEdit = ref(false)
const personnelList = ref<VehiclePersonnelRow[]>([])
@@ -495,7 +548,8 @@ const formData = reactive({
carrierId: '',
carrierName: '',
vehicleStatus: 'available',
remark: ''
remark: '',
photoUrls: ''
})
const formRules = {
@@ -563,7 +617,16 @@ const viewSections = computed<ViewSection[]>(() => {
{ label: '备注', value: d.remark || '—', span: 'full' }
],
fieldLayout: 'table',
tableMode: 'triple',
tableMode: 'triple'
},
{
title: '车辆照片',
fields: [],
slot: 'photo'
},
{
title: '',
fields: [],
slot: 'vehicleDetailTabs'
}
]
@@ -833,7 +896,8 @@ function handleAdd() {
carrierId: '',
carrierName: '',
vehicleStatus: 'available',
remark: ''
remark: '',
photoUrls: ''
})
resetSubTables()
certList.value = ensureSelfVehicleCertSlots([], formData.trailerNo)
@@ -880,7 +944,8 @@ async function handleEdit(row: Vehicle) {
carrierId: detail.carrierId || '',
carrierName: detail.carrierName || '',
vehicleStatus: detail.vehicleStatus,
remark: detail.remark
remark: detail.remark,
photoUrls: detail.photoUrls || ''
})
personnelList.value = resolvePersonnelRows(
(detail.personnelList || []).map(p => ({
@@ -915,6 +980,10 @@ async function handleSubmit() {
ElMessage.warning('证书附件上传中,请稍候')
return
}
if (photoUploadRef.value?.hasUploading?.()) {
ElMessage.warning('附件上传中,请稍候')
return
}
if (formData.carrierId) {
const carrier = carrierList.value.find(c => c.id === formData.carrierId)
@@ -934,6 +1003,7 @@ async function handleSubmit() {
loadCapacity: formData.loadCapacity,
vehicleStatus: formData.vehicleStatus,
remark: formData.remark,
photoUrls: formData.photoUrls || undefined,
personnelList: personnelList.value.map(p => ({
personnelId: p.personnelId,
personnelName: p.personnelName.trim(),
@@ -1032,4 +1102,24 @@ onMounted(() => {
flex-wrap: nowrap;
gap: 6px;
}
.pl-photo-thumb {
width: 48px;
height: 48px;
border-radius: 8px;
object-fit: cover;
border: 1px solid var(--el-border-color, #d9e8e2);
display: inline-block;
vertical-align: middle;
background: #f8fafc;
}
.pl-photo-thumb--empty {
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 11px;
color: #94a3b8;
box-sizing: border-box;
}
</style>