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

Also include cert attachment list cell already wired in this page WIP.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-08-02 10:34:41 +08:00
1 parent e2f087e6b9
commit a552049de4
2 files changed
+278 -5

No files matched your search

+95 -5
View File
@@ -112,6 +112,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="车牌号"
@@ -132,6 +149,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="100" align="center" header-align="center" v-if="isColumnVisible('vehicleType')">
<template #default="{ row }">
<el-tag :type="getVehicleTypeTagType(row.vehicleType)" size="small">
@@ -257,6 +285,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>
<!-- 关联人员子表 -->
@@ -375,6 +412,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 || []"
@@ -401,6 +448,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, DocumentCopy, Edit, Plus, RefreshLeft, Search, Van } from '@element-plus/icons-vue'
import {
@@ -417,6 +465,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 PlPasteRecognizeDialog from '@/components/business/pl-paste-recognize-dialog/index.vue'
import type { VehiclePersonnelViewRow } from '@/components/business/pl-vehicle-personnel-view-list/index.vue'
import SystemViewDialog, {
@@ -427,6 +476,7 @@ import { pickBxList, pickBxPageResult } from '@/utils/http/bx'
import { DEFAULT_LIST_PAGE_SIZE } from '@/utils/table/tableConfig'
import { formatDateTime } from '@/utils/format'
import { formatPlVehiclePlateDisplay, normalizePlPersonnelSummaryDisplay } from '@/utils/pl-display'
import { firstPhotoUrl, resolvePhotoDisplayUrl } from '@/utils/pl-photo'
import { ensureVehicleCertSlots } from '@/utils/pl-cert-slots'
import {
PL_VEHICLE_CERT_NAME_OPTIONS,
@@ -452,6 +502,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: '载重(吨)' },
@@ -466,7 +518,7 @@ const {
isIndeterminate,
isColumnVisible,
resetToDefault
} = usePersistedListColumns('pl-vehicle-list-columns', listColumnDefs)
} = usePersistedListColumns('pl-vehicle-list-columns-v3', listColumnDefs)
const personnelOptions = ref<Personnel[]>([])
const selectedRows = ref<Vehicle[]>([])
@@ -474,6 +526,7 @@ const dialogVisible = ref(false)
const pasteVisible = ref(false)
const dialogTitle = ref('')
const formRef = ref()
const photoUploadRef = ref<InstanceType<typeof AttachmentUploadField>>()
const isEdit = ref(false)
const personnelList = ref<VehiclePersonnelRow[]>([])
@@ -508,7 +561,8 @@ const formData = reactive({
carrierName: '',
loadCapacity: null as number | null,
vehicleStatus: 'available',
remark: ''
remark: '',
photoUrls: ''
})
const formRules = {
@@ -586,7 +640,16 @@ const viewSections = computed<ViewSection[]>(() => {
},
{ label: '备注', value: d.remark || '—', span: true },
{ label: '创建时间', value: formatDateTime(d.createTime) }
],
]
},
{
title: '车辆照片',
fields: [],
slot: 'photo'
},
{
title: '',
fields: [],
slot: 'vehicleDetailTabs'
}
]
@@ -884,7 +947,8 @@ function handleAdd() {
carrierName: '',
loadCapacity: null,
vehicleStatus: 'available',
remark: ''
remark: '',
photoUrls: ''
})
resetSubTables()
certList.value = ensureVehicleCertSlots([], formData.trailerNo, VEHICLE_TYPE_LOCK)
@@ -928,7 +992,8 @@ async function handleEdit(row: Vehicle) {
carrierName: detail.carrierName,
loadCapacity: detail.loadCapacity ?? null,
vehicleStatus: detail.vehicleStatus,
remark: detail.remark
remark: detail.remark,
photoUrls: detail.photoUrls || ''
})
personnelList.value = resolvePersonnelRows(
(detail.personnelList || []).map(p => ({
@@ -960,6 +1025,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)
@@ -979,6 +1048,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(),
@@ -1095,4 +1165,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>