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:
1 parent
e2f087e6b9
commit
a552049de4
2 files changed
+278
-5
No files matched your search
@@ -0,0 +1,183 @@
|
||||
<template>
|
||||
<div v-if="items.length" class="pl-cert-list-attachment-cell">
|
||||
<div
|
||||
v-for="item in items"
|
||||
:key="item.key"
|
||||
class="pl-cert-list-attachment-cell__item"
|
||||
:title="item.fullLabel"
|
||||
>
|
||||
<AttachmentUploadField
|
||||
v-if="item.url"
|
||||
:model-value="item.url"
|
||||
disabled
|
||||
:category-labels="item.categoryLabels"
|
||||
/>
|
||||
<div v-else class="pl-cert-list-attachment-cell__empty">
|
||||
<span class="pl-cert-list-attachment-cell__empty-text">未上传</span>
|
||||
<span class="pl-cert-list-attachment-cell__caption">{{ item.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span v-else class="pl-cert-list-attachment-cell__none">—</span>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import type { CertRead } from '@/api/pl'
|
||||
import AttachmentUploadField from '@/components/business/attachment-upload-field/index.vue'
|
||||
import { normalizeAttachmentUrls } from '@/utils/download-attachment'
|
||||
import {
|
||||
PL_VEHICLE_CERT_PART_TRAILER,
|
||||
normalizeVehicleCertPart
|
||||
} from '@/utils/pl-vehicle-cert'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
certList?: CertRead[] | null
|
||||
/** 车辆证书:按主车/挂车加前缀 */
|
||||
showVehiclePart?: boolean
|
||||
}>(),
|
||||
{
|
||||
certList: () => [],
|
||||
showVehiclePart: false
|
||||
}
|
||||
)
|
||||
|
||||
type ItemDef = {
|
||||
key: string
|
||||
label: string
|
||||
fullLabel: string
|
||||
url: string
|
||||
categoryLabels: Record<string, string>
|
||||
}
|
||||
|
||||
function parseUrls(raw?: string | null): string[] {
|
||||
const normalized = normalizeAttachmentUrls(raw)
|
||||
if (!normalized) return []
|
||||
return normalized
|
||||
.split(',')
|
||||
.map((item) => item.trim())
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
function partPrefix(cert: CertRead, enablePart: boolean): string {
|
||||
if (!enablePart) return ''
|
||||
return normalizeVehicleCertPart(cert.vehiclePart) === PL_VEHICLE_CERT_PART_TRAILER ? '挂·' : '主·'
|
||||
}
|
||||
|
||||
const items = computed<ItemDef[]>(() => {
|
||||
const certs = props.certList || []
|
||||
if (!certs.length) return []
|
||||
|
||||
const enablePart =
|
||||
props.showVehiclePart &&
|
||||
certs.some((cert) => normalizeVehicleCertPart(cert.vehiclePart) === PL_VEHICLE_CERT_PART_TRAILER)
|
||||
|
||||
const result: ItemDef[] = []
|
||||
certs.forEach((cert, certIndex) => {
|
||||
const certName = String(cert.certName || '').trim() || '证书'
|
||||
const prefix = partPrefix(cert, enablePart)
|
||||
const fullLabel = `${prefix}${certName}`
|
||||
const label = fullLabel.length > 6 ? `${fullLabel.slice(0, 5)}…` : fullLabel
|
||||
const urls = parseUrls(cert.attachmentUrls)
|
||||
|
||||
if (!urls.length) {
|
||||
result.push({
|
||||
key: `${cert.id || cert.certId || certIndex}-empty`,
|
||||
label,
|
||||
fullLabel,
|
||||
url: '',
|
||||
categoryLabels: {}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
urls.forEach((url, urlIndex) => {
|
||||
result.push({
|
||||
key: `${cert.id || cert.certId || certIndex}-${urlIndex}`,
|
||||
label,
|
||||
fullLabel,
|
||||
url,
|
||||
categoryLabels: { [url]: label }
|
||||
})
|
||||
})
|
||||
})
|
||||
return result
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.pl-cert-list-attachment-cell {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.pl-cert-list-attachment-cell__item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 96px;
|
||||
}
|
||||
|
||||
.pl-cert-list-attachment-cell__empty {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 96px;
|
||||
height: 56px;
|
||||
overflow: hidden;
|
||||
border: 1px dashed var(--border, #d9e8e2);
|
||||
border-radius: 8px;
|
||||
background: var(--table-head, #f8fafc);
|
||||
color: var(--mint-text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.pl-cert-list-attachment-cell__empty-text {
|
||||
margin-bottom: 14px;
|
||||
font-size: 11px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.pl-cert-list-attachment-cell__caption {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
padding: 2px 4px;
|
||||
background: rgba(15, 23, 42, 0.62);
|
||||
color: #fff;
|
||||
font-size: 11px;
|
||||
line-height: 1.3;
|
||||
text-align: center;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.pl-cert-list-attachment-cell__none {
|
||||
color: var(--mint-text);
|
||||
}
|
||||
|
||||
:deep(.attachment-upload) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.attachment-list) {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
:deep(.attachment-item) {
|
||||
width: 96px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
:deep(.attachment-preview) {
|
||||
height: 56px;
|
||||
}
|
||||
|
||||
:deep(.attachment-footer) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user