This commit is contained in:
zlwu committed 2026-06-21 12:56:33 +08:00
1 parent e46c0480d4
commit cedb7ee681
12 files changed
+2677 -2680

No files matched your search

@@ -15,36 +15,7 @@
<div class="carrier-view-body" v-loading="loading">
<section class="carrier-view-top">
<h3 class="carrier-view-block-title">承运商信息</h3>
<dl v-if="carrier" class="carrier-view-kv-grid">
<div class="carrier-view-kv">
<dt>承运商名称</dt>
<dd>{{ carrier.carrierName || '—' }}</dd>
</div>
<div class="carrier-view-kv">
<dt>联系人</dt>
<dd>{{ carrier.contactName || '—' }}</dd>
</div>
<div class="carrier-view-kv">
<dt>联系电话</dt>
<dd>{{ carrier.contactPhone || '—' }}</dd>
</div>
<div class="carrier-view-kv">
<dt>合作状态</dt>
<dd>
<el-tag :type="getPlCarrierStatusTagType(carrier.status)" size="small">
{{ getPlCarrierStatusLabel(carrier.status) }}
</el-tag>
</dd>
</div>
<div class="carrier-view-kv">
<dt>创建时间</dt>
<dd>{{ formatDateTime(carrier.createTime) }}</dd>
</div>
<div class="carrier-view-kv carrier-view-kv-span">
<dt>备注</dt>
<dd>{{ carrier.remark || '—' }}</dd>
</div>
</dl>
<ViewKvTable v-if="carrier" :fields="carrierViewFields" mode="triple" />
</section>
<section class="carrier-view-bottom">
@@ -80,6 +51,8 @@
import { Close } from '@element-plus/icons-vue'
import { carrierApi, vehicleApi, type Carrier } from '@/api/pl'
import PlVehicleViewPanel from '@/components/business/pl-vehicle-view-panel/index.vue'
import ViewKvTable from '@/components/business/system-view-dialog/ViewKvTable.vue'
import type { ViewField } from '@/components/business/system-view-dialog/types'
import {
loadVehicleViewBundles,
type VehicleViewBundle
@@ -106,6 +79,24 @@ const carrier = ref<Carrier | null>(null)
const vehicleBundles = ref<VehicleViewBundle[]>([])
const activeTab = ref('')
const carrierViewFields = computed<ViewField[]>(() => {
const c = carrier.value
if (!c) return []
return [
{ label: '承运商名称', value: c.carrierName },
{ label: '联系人', value: c.contactName || '—' },
{ label: '联系电话', value: c.contactPhone || '—' },
{
label: '合作状态',
value: getPlCarrierStatusLabel(c.status),
tagType: getPlCarrierStatusTagType(c.status)
},
{ label: '创建时间', value: formatDateTime(c.createTime) },
{ label: '备注', value: c.remark || '—', span: 'full' }
]
})
watch(
() => [props.visible, props.carrierId] as const,
async ([visible, carrierId]) => {
@@ -164,20 +155,6 @@ function handleClosed() {
border-bottom: 1px solid #e2e8f0;
}
.carrier-view-kv-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px 20px;
}
.carrier-view-kv {
min-width: 0;
}
.carrier-view-kv-span {
grid-column: 1 / -1;
}
.carrier-view-empty {
margin: 0;
font-size: 13px;
@@ -193,16 +170,4 @@ function handleClosed() {
padding-top: 4px;
}
}
@media (max-width: 900px) {
.carrier-view-kv-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 640px) {
.carrier-view-kv-grid {
grid-template-columns: 1fr;
}
}
</style>
@@ -10,40 +10,25 @@
>
<h4 class="cert-view-card-title">证书 {{ index + 1 }}</h4>
<dl class="cert-view-kv-grid">
<div class="cert-view-kv">
<dt>证书名称</dt>
<dd>{{ cert.certName || '—' }}</dd>
</div>
<div class="cert-view-kv">
<dt>证号</dt>
<dd>{{ cert.certNo || '—' }}</dd>
</div>
<div class="cert-view-kv">
<dt>有效期</dt>
<dd>
<el-tag v-if="cert.expireDate" :type="getExpireTagType(cert.expireDate)" size="small">
{{ cert.expireDate }}
</el-tag>
<span v-else>—</span>
</dd>
</div>
<div class="cert-view-kv">
<dt>提醒天数</dt>
<dd>{{ cert.remindDays ?? 30 }} 天</dd>
</div>
<div class="cert-view-kv cert-view-kv-span">
<dt>附件</dt>
<dd>
<AttachmentUploadField
v-if="cert.attachmentUrls"
:model-value="cert.attachmentUrls"
disabled
/>
<span v-else class="view-empty-inline">—</span>
</dd>
</div>
</dl>
<div class="cert-view-kv-table-group">
<ViewKvTable :fields="buildCertViewFields(cert)" mode="triple" />
<table
v-if="cert.attachmentUrls"
class="cert-view-attachment-table view-kv-table view-kv-table--triple"
>
<tbody>
<tr class="row-long">
<th>附件</th>
<td colspan="5">
<AttachmentUploadField
:model-value="cert.attachmentUrls"
disabled
/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
@@ -51,6 +36,8 @@
<script setup lang="ts">
import AttachmentUploadField from '@/components/business/attachment-upload-field/index.vue'
import ViewKvTable from '@/components/business/system-view-dialog/ViewKvTable.vue'
import type { ViewField } from '@/components/business/system-view-dialog/types'
import type { CertRead } from '@/api/pl'
withDefaults(
@@ -71,6 +58,19 @@ function getExpireTagType(dateStr: string | undefined) {
if (diffDays <= 30) return 'warning'
return 'success'
}
function buildCertViewFields(cert: CertRead): ViewField[] {
return [
{ label: '证书名称', value: cert.certName || '—' },
{ label: '证号', value: cert.certNo || '—' },
{
label: '有效期',
value: cert.expireDate || '—',
tagType: cert.expireDate ? getExpireTagType(cert.expireDate) : undefined
},
{ label: '提醒天数', value: `${cert.remindDays ?? 30} 天` }
]
}
</script>
<style scoped lang="scss">
@@ -109,33 +109,47 @@ function getExpireTagType(dateStr: string | undefined) {
line-height: 1;
}
.cert-view-kv-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 12px 20px;
}
.cert-view-kv-table-group {
border: 1px solid var(--border, #d9e8e2);
border-radius: 8px;
overflow: hidden;
background: #fff;
.cert-view-kv {
min-width: 0;
}
.cert-view-kv-span {
grid-column: 1 / -1;
}
.view-empty-inline {
color: #000;
}
@media (max-width: 1200px) {
.cert-view-kv-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
:deep(.view-kv-table-wrap) {
border: none;
border-radius: 0;
}
}
@media (max-width: 640px) {
.cert-view-kv-grid {
grid-template-columns: 1fr;
.cert-view-attachment-table {
width: 100%;
border-collapse: collapse;
font-size: 14px;
table-layout: fixed;
border-top: 1px solid #eef2f6;
th {
width: 10%;
padding: 10px 12px;
background: var(--table-head, #f8fafc);
color: var(--text-muted, #64748b);
font-size: 13px;
font-weight: 500;
text-align: left;
vertical-align: top;
border-right: 1px solid #eef2f6;
white-space: normal;
word-break: break-word;
line-height: 1.4;
}
td {
padding: 10px 14px;
font-weight: 600;
color: var(--text, #1e293b);
vertical-align: top;
word-break: break-word;
line-height: 1.45;
}
}
</style>
@@ -10,20 +10,7 @@
</el-tag>
</h4>
<dl class="personnel-view-kv-grid">
<div class="personnel-view-kv">
<dt>手机号</dt>
<dd>{{ person.phoneNo || '—' }}</dd>
</div>
<div class="personnel-view-kv">
<dt>年龄</dt>
<dd>{{ person.age ?? '—' }}</dd>
</div>
<div class="personnel-view-kv personnel-view-kv-span">
<dt>备注</dt>
<dd>{{ person.remark || '—' }}</dd>
</div>
</dl>
<ViewKvTable :fields="personnelViewFields" mode="triple" />
<div class="personnel-certs-block">
<p class="personnel-certs-title">人员证书</p>
@@ -34,11 +21,13 @@
<script setup lang="ts">
import PlCertViewList from '@/components/business/pl-cert-view-list/index.vue'
import ViewKvTable from '@/components/business/system-view-dialog/ViewKvTable.vue'
import type { ViewField } from '@/components/business/system-view-dialog/types'
import type { CertRead, VehiclePersonnelRow } from '@/api/pl'
type VehiclePersonnelViewRow = VehiclePersonnelRow & { certList?: CertRead[] }
withDefaults(
const props = withDefaults(
defineProps<{
person: VehiclePersonnelViewRow
showTitle?: boolean
@@ -48,6 +37,32 @@ withDefaults(
}
)
const personnelViewFields = computed<ViewField[]>(() => {
const person = props.person
const fields: ViewField[] = [
{ label: '姓名', value: person.personnelName || '—' },
{ label: '手机号', value: person.phoneNo || '—' },
{ label: '年龄', value: person.age ?? '—' },
{
label: '角色',
value: getRoleLabel(person.role),
tagType: getRoleTagType(person.role)
}
]
if (person.role === 'driver') {
fields.push({
label: '默认司机',
value: person.isDefault === 1 ? '是' : '否',
tagType: person.isDefault === 1 ? 'success' : 'info'
})
}
fields.push({ label: '备注', value: person.remark || '—', span: 'full' })
return fields
})
function getRoleLabel(role: string) {
const map: Record<string, string> = {
driver: '司机',
@@ -76,22 +91,8 @@ function getRoleTagType(role: string) {
line-height: 1.4;
}
.personnel-view-kv-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px 20px;
margin: 0 0 12px;
}
.personnel-view-kv {
min-width: 0;
}
.personnel-view-kv-span {
grid-column: 1 / -1;
}
.personnel-certs-block {
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid #e2e8f0;
}
@@ -102,10 +103,4 @@ function getRoleTagType(role: string) {
font-weight: 600;
color: #1e293b;
}
@media (max-width: 640px) {
.personnel-view-kv-grid {
grid-template-columns: 1fr;
}
}
</style>
@@ -19,48 +19,7 @@
<div v-show="!collapsible || expanded" class="vehicle-view-panel-body">
<section class="vehicle-view-section">
<h4 v-if="!collapsible" class="vehicle-view-section-title">车辆信息</h4>
<dl class="vehicle-view-kv-grid">
<div class="vehicle-view-kv">
<dt>车牌号</dt>
<dd>{{ detail.licensePlate || '—' }}</dd>
</div>
<div class="vehicle-view-kv">
<dt>车辆类型</dt>
<dd>
<el-tag :type="getPlVehicleTypeTagType(detail.vehicleType)" size="small">
{{ getPlVehicleTypeLabel(detail.vehicleType) }}
</el-tag>
</dd>
</div>
<div class="vehicle-view-kv">
<dt>承运商</dt>
<dd>{{ detail.carrierName || '—' }}</dd>
</div>
<div class="vehicle-view-kv">
<dt>载重(吨)</dt>
<dd>{{ detail.loadCapacity ?? '—' }}</dd>
</div>
<div class="vehicle-view-kv">
<dt>车辆状态</dt>
<dd>
<el-tag :type="getPlVehicleStatusTagType(detail.vehicleStatus)" size="small">
{{ getPlVehicleStatusLabel(detail.vehicleStatus) }}
</el-tag>
</dd>
</div>
<div class="vehicle-view-kv">
<dt>关联人员摘要</dt>
<dd>{{ detail.personnelSummary || '—' }}</dd>
</div>
<div class="vehicle-view-kv vehicle-view-kv-span">
<dt>备注</dt>
<dd>{{ detail.remark || '—' }}</dd>
</div>
<div class="vehicle-view-kv">
<dt>创建时间</dt>
<dd>{{ formatDateTime(detail.createTime) }}</dd>
</div>
</dl>
<ViewKvTable :fields="vehicleViewFields" mode="triple" />
</section>
<section class="vehicle-view-section">
@@ -76,6 +35,8 @@
<script setup lang="ts">
import { ArrowDown } from '@element-plus/icons-vue'
import PlVehicleCertPersonnelTabs from '@/components/business/pl-vehicle-cert-personnel-tabs/index.vue'
import ViewKvTable from '@/components/business/system-view-dialog/ViewKvTable.vue'
import type { ViewField } from '@/components/business/system-view-dialog/types'
import type { VehiclePersonnelViewRow } from '@/components/business/pl-vehicle-personnel-view-list/index.vue'
import type { VehicleDetail } from '@/api/pl'
import { formatDateTime } from '@/utils/format'
@@ -102,6 +63,28 @@ const props = withDefaults(
const expanded = ref(props.defaultExpanded)
const vehicleViewFields = computed<ViewField[]>(() => {
const d = props.detail
return [
{ label: '车牌号', value: d.licensePlate },
{
label: '车辆类型',
value: getPlVehicleTypeLabel(d.vehicleType),
tagType: getPlVehicleTypeTagType(d.vehicleType)
},
{ label: '承运商', value: d.carrierName || '—' },
{ label: '载重(吨)', value: d.loadCapacity ?? '—' },
{
label: '车辆状态',
value: getPlVehicleStatusLabel(d.vehicleStatus),
tagType: getPlVehicleStatusTagType(d.vehicleStatus)
},
{ label: '关联人员摘要', value: d.personnelSummary || '—', span: true },
{ label: '创建时间', value: formatDateTime(d.createTime) },
{ label: '备注', value: d.remark || '—', span: 'full' }
]
})
watch(
() => props.defaultExpanded,
value => {
@@ -170,30 +153,4 @@ watch(
border-left: 3px solid #10b981;
line-height: 1;
}
.vehicle-view-kv-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 12px 20px;
}
.vehicle-view-kv {
min-width: 0;
}
.vehicle-view-kv-span {
grid-column: 1 / -1;
}
@media (max-width: 1200px) {
.vehicle-view-kv-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 640px) {
.vehicle-view-kv-grid {
grid-template-columns: 1fr;
}
}
</style>