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

+16 -16
View File
@@ -5905,8 +5905,8 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/vehicle/index.vue": {
"mtime": 1781966055.86601,
"ast_hash": "c5bd0a2aff42afffa4a95c047baa97d4",
"mtime": 1782017734.4540741,
"ast_hash": "c619257173d067e51e637694d427fb6e",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/driver/index.vue": {
@@ -5925,8 +5925,8 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/carrier/index.vue": {
"mtime": 1781949223.0486753,
"ast_hash": "7099bdc45d754c0087ecf33e625353db",
"mtime": 1782017734.0768383,
"ast_hash": "068a4a50111ac227345f263a36c8a080",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/router/modules/pl.ts": {
@@ -5965,8 +5965,8 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/personnel/index.vue": {
"mtime": 1781966055.2295575,
"ast_hash": "982c536d997007419942ba22748f2ab6",
"mtime": 1782017734.9490426,
"ast_hash": "9ca8b4c51107b5128f0b33ac32f99b53",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/pl/base_data.py": {
@@ -5990,8 +5990,8 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/pl-cert-view-list/index.vue": {
"mtime": 1781949997.043425,
"ast_hash": "f1b24be2137a383fc204ec4553d62f1a",
"mtime": 1782017369.1065211,
"ast_hash": "c9b021a9d8aa1fd8baed449716dc7047",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/pl-vehicle-personnel-view-list/index.vue": {
@@ -6010,23 +6010,23 @@
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/pl-vehicle-view-panel/index.vue": {
"mtime": 1781949995.629496,
"ast_hash": "45d7ac945c7948a0b543917a4eec3025",
"mtime": 1782017363.5142002,
"ast_hash": "5eefb28c2dde89df79a43a792722f07e",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/pl-carrier-view-dialog/index.vue": {
"mtime": 1781949994.7691498,
"ast_hash": "5e879c7fa06cfd490e6dae22c722b2a3",
"mtime": 1782017029.7709475,
"ast_hash": "445f743f6c6af15c0f9aaa8fc89ca7b7",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/pl/self-vehicle/index.vue": {
"mtime": 1781966055.7689826,
"ast_hash": "3cdef2b24f297e35428636347c61d8af",
"mtime": 1782017734.7090108,
"ast_hash": "83cc6f5ddac7d812014c180a017c4f97",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/pl-vehicle-personnel-view-list/PersonnelViewPanel.vue": {
"mtime": 1781949998.7342877,
"ast_hash": "21365a0199c5c22eb3519e44a88d6c37",
"mtime": 1782017371.946757,
"ast_hash": "fbb52644ee368d1b8e292cb426004814",
"semantic_hash": ""
},
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/business/pl-plan-form-dialog/index.vue": {
@@ -433,12 +433,10 @@
"431": "Community 431",
"432": "Community 432",
"433": "Community 433",
"434": "Community 434",
"435": "Community 435",
"436": "Community 436",
"437": "Community 437",
"438": "Community 438",
"439": "Community 439",
"440": "Community 440",
"441": "Community 441",
"442": "Community 442",
@@ -554,7 +552,6 @@
"552": "Community 552",
"553": "Community 553",
"554": "Community 554",
"555": "Community 555",
"556": "Community 556",
"557": "Community 557",
"558": "Community 558",
@@ -610,13 +607,11 @@
"608": "Community 608",
"609": "Community 609",
"610": "Community 610",
"611": "Community 611",
"612": "Community 612",
"613": "Community 613",
"614": "Community 614",
"615": "Community 615",
"616": "Community 616",
"617": "Community 617",
"618": "Community 618",
"619": "Community 619",
"620": "Community 620",
@@ -629,8 +624,6 @@
"627": "Community 627",
"628": "Community 628",
"629": "Community 629",
"630": "Community 630",
"631": "Community 631",
"632": "Community 632",
"633": "Community 633",
"634": "Community 634",
@@ -668,12 +661,9 @@
"666": "Community 666",
"667": "Community 667",
"669": "Community 669",
"670": "Community 670",
"671": "Community 671",
"672": "Community 672",
"673": "Community 673",
"674": "Community 674",
"675": "Community 675",
"676": "Community 676",
"678": "Community 678",
"679": "Community 679",
@@ -682,13 +672,11 @@
"684": "Community 684",
"685": "Community 685",
"686": "Community 686",
"687": "Community 687",
"688": "Community 688",
"690": "Community 690",
"691": "Community 691",
"692": "Community 692",
"694": "Community 694",
"696": "Community 696",
"700": "Community 700",
"704": "Community 704"
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -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>
+45 -8
View File
@@ -77,13 +77,15 @@
</div>
<dl class="carrier-card-kv">
<div class="carrier-card-kv-item">
<dt>联系人</dt>
<dd>{{ row.contactName || '—' }}</dd>
</div>
<div class="carrier-card-kv-item">
<dt>联系电话</dt>
<dd>{{ row.contactPhone || '—' }}</dd>
<div class="carrier-card-kv-item carrier-card-kv-contact-row">
<div class="carrier-card-contact-part">
<dt>联系人</dt>
<dd>{{ row.contactName || '—' }}</dd>
</div>
<div class="carrier-card-contact-part">
<dt>联系电话</dt>
<dd>{{ row.contactPhone || '—' }}</dd>
</div>
</div>
<div class="carrier-card-kv-item">
<dt>备注</dt>
@@ -360,7 +362,7 @@ onMounted(() => {
.carrier-card-head {
display: flex;
align-items: flex-start;
align-items: center;
gap: 10px;
}
@@ -394,6 +396,41 @@ onMounted(() => {
gap: 4px;
font-size: 13px;
&.carrier-card-kv-contact-row {
display: flex;
align-items: flex-start;
gap: 16px;
}
}
.carrier-card-contact-part {
display: grid;
gap: 4px;
flex: 1;
min-width: 0;
font-size: 13px;
dt {
margin: 0;
color: #1e293b;
font-weight: 500;
font-size: 11px;
line-height: 1.4;
}
dd {
margin: 0;
color: #1e293b;
word-break: break-word;
line-height: 1.5;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
}
.carrier-card-kv-item:not(.carrier-card-kv-contact-row) {
dt {
margin: 0;
color: #1e293b;
+6 -4
View File
@@ -311,10 +311,12 @@ const viewSections = computed<ViewSection[]>(() => {
value: d.nearestExpireDate || '—',
tagType: d.nearestExpireDate ? getExpireTagType(d.nearestExpireDate) : undefined
},
{ label: '备注', value: d.remark || '—', span: true },
{ label: '创建时间', value: formatDateTime(d.createTime) },
{ label: '更新时间', value: formatDateTime(d.updateTime) }
]
{ label: '更新时间', value: formatDateTime(d.updateTime) },
{ label: '备注', value: d.remark || '—', span: 'full' }
],
fieldLayout: 'table',
tableMode: 'triple'
},
{
title: '人员证书',
@@ -555,7 +557,7 @@ onMounted(() => {
.personnel-card-head {
display: flex;
align-items: flex-start;
align-items: center;
gap: 10px;
}
@@ -357,9 +357,11 @@ const viewSections = computed<ViewSection[]>(() => {
tagType: getStatusTagType(d.vehicleStatus)
},
{ label: '关联人员摘要', value: d.personnelSummary || '—', span: true },
{ label: '备注', value: d.remark || '—', span: true },
{ label: '创建时间', value: formatDateTime(d.createTime) }
{ label: '创建时间', value: formatDateTime(d.createTime) },
{ label: '备注', value: d.remark || '—', span: 'full' }
],
fieldLayout: 'table',
tableMode: 'triple',
slot: 'vehicleDetailTabs'
}
]
@@ -745,7 +747,7 @@ onMounted(() => {
.vehicle-card-head {
display: flex;
align-items: flex-start;
align-items: center;
gap: 10px;
}
+1 -1
View File
@@ -857,7 +857,7 @@ onMounted(() => {
.vehicle-card-head {
display: flex;
align-items: flex-start;
align-items: center;
gap: 10px;
}