refactor(transportCapacity): 使用 section-card 重构司机管理弹窗布局

- 将司机管理页面新增/编辑弹窗中四个分组改为使用标准 section-card 组件包裹
- 删除手写的扁平样式和红色竖条,统一使用全局 element-ui 样式维护弹窗视觉风格
- 调整司机证件上传区尺寸为 240x151 px,保持身份证比例并左对齐显示
- 优化弹窗中各表单项布局,提高视觉层次与一致性
- 更新 scoped 样式,移除无用的 section-title 样式,保持代码清洁
This commit is contained in:
2026-08-06 16:53:23 +08:00
parent 53676a1150
commit 02b2e3b673
9 changed files with 1920 additions and 1621 deletions

View File

@@ -92,21 +92,13 @@
</span>
</template>
<template #menu="{ row }">
<el-link
type="primary"
v-if="hasPermission('driver_view')"
@click="openDriver(row, true)"
>
<el-link type="primary" v-if="hasPermission('driver_view')" @click="openDriver(row, true)">
查看
</el-link>
<el-link type="primary" v-if="hasPermission('driver_edit')" @click="openDriver(row)">
修改
</el-link>
<el-link
type="primary"
v-if="hasPermission('driver_status')"
@click="handleStatus(row)"
>
<el-link type="primary" v-if="hasPermission('driver_status')" @click="handleStatus(row)">
{{ row.status === 1 ? '停用' : '启用' }}
</el-link>
</template>
@@ -129,349 +121,361 @@
:disabled="readonly"
class="driver-form"
>
<div class="section-title">基础身份信息</div>
<el-row :gutter="18">
<el-col :span="8">
<el-form-item label="司机姓名" prop="driverName">
<el-input v-model="driverForm.driverName" maxlength="20" show-word-limit />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="身份证号" prop="idCardNo">
<el-input
v-model="driverForm.idCardNo"
maxlength="18"
show-word-limit
@input="driverForm.idCardNo = String(driverForm.idCardNo || '').toUpperCase()"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="出生年月" prop="birthday">
<el-date-picker v-model="driverForm.birthday" type="date" value-format="YYYY-MM-DD" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="18">
<el-col :span="8">
<el-form-item label="性别" prop="gender">
<el-select v-model="driverForm.gender" clearable>
<el-option label="男" value="男" />
<el-option label="女" value="女" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="民族" prop="nation">
<el-select v-model="driverForm.nation" clearable filterable>
<el-option v-for="item in nationOptions" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="学历" prop="education">
<el-select v-model="driverForm.education" clearable filterable>
<el-option
v-for="item in educationOptions"
:key="item"
:label="item"
:value="item"
<section-card title="基础身份信息">
<el-row :gutter="18">
<el-col :span="8">
<el-form-item label="司机姓名" prop="driverName">
<el-input v-model="driverForm.driverName" maxlength="20" show-word-limit />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="身份证号" prop="idCardNo">
<el-input
v-model="driverForm.idCardNo"
maxlength="18"
show-word-limit
@input="driverForm.idCardNo = String(driverForm.idCardNo || '').toUpperCase()"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="18">
<el-col :span="8">
<el-form-item label="住址" prop="addressRegion">
<el-cascader
ref="addressRegionCascader"
v-model="driverForm.addressRegionPath"
:options="regionOptions"
:props="regionCascaderProps"
:placeholder="driverForm.addressRegion || '请选择省市区'"
clearable
filterable
@change="handleAddressRegionChange"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="详细地址" prop="address">
<el-input v-model="driverForm.address" maxlength="200" show-word-limit />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="岗位" prop="postList">
<el-checkbox-group v-model="driverForm.postList">
<el-checkbox label="司机" />
<el-checkbox label="押运员" />
<el-checkbox label="装卸管理员" />
</el-checkbox-group>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="18">
<el-col :span="8">
<image-upload-field
label="身份证正面照"
prop="idCardFront"
:value="driverForm.idCardFront"
:readonly="readonly"
:headers="uploadHeaders"
large
@success="url => handleIdCardUploadSuccess('idCardFront', url)"
/>
</el-col>
<el-col :span="8">
<image-upload-field
label="身份证反面照"
prop="idCardBack"
:value="driverForm.idCardBack"
:readonly="readonly"
:headers="uploadHeaders"
large
@success="url => handleIdCardUploadSuccess('idCardBack', url)"
/>
</el-col>
<el-col :span="8">
<image-upload-field
label="大头照"
prop="headPhoto"
:value="driverForm.headPhoto"
:readonly="readonly"
:headers="uploadHeaders"
large
@success="url => setImage('headPhoto', url)"
/>
</el-col>
</el-row>
<div class="section-title">驾驶证信息</div>
<el-row :gutter="18">
<el-col :span="6">
<el-form-item label="准驾车型" prop="drivingType">
<el-select
v-model="driverForm.drivingType"
clearable
filterable
allow-create
default-first-option
>
<el-option
v-for="item in drivingTypeOptions"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="档案编号" prop="drivingLicenseNo">
<el-input v-model="driverForm.drivingLicenseNo" maxlength="50" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="有效期" prop="drivingLicenseEndDate">
<div class="date-range">
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="出生年月" prop="birthday">
<el-date-picker
v-model="driverForm.drivingLicenseStartDate"
v-model="driverForm.birthday"
type="date"
value-format="YYYY-MM-DD"
placeholder="起"
@change="validateFormField('drivingLicenseEndDate')"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="18">
<el-col :span="8">
<el-form-item label="性别" prop="gender">
<el-select v-model="driverForm.gender" clearable>
<el-option label="男" value="男" />
<el-option label="女" value="女" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="民族" prop="nation">
<el-select v-model="driverForm.nation" clearable filterable>
<el-option
v-for="item in nationOptions"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="学历" prop="education">
<el-select v-model="driverForm.education" clearable filterable>
<el-option
v-for="item in educationOptions"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="18">
<el-col :span="8">
<el-form-item label="住址" prop="addressRegion">
<el-cascader
ref="addressRegionCascader"
v-model="driverForm.addressRegionPath"
:options="regionOptions"
:props="regionCascaderProps"
:placeholder="driverForm.addressRegion || '请选择省市区'"
clearable
filterable
@change="handleAddressRegionChange"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="详细地址" prop="address">
<el-input v-model="driverForm.address" maxlength="200" show-word-limit />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="岗位" prop="postList">
<el-checkbox-group v-model="driverForm.postList">
<el-checkbox label="司机" />
<el-checkbox label="押运员" />
<el-checkbox label="装卸管理员" />
</el-checkbox-group>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="18">
<el-col :span="8">
<image-upload-field
label="身份证正面照"
prop="idCardFront"
:value="driverForm.idCardFront"
:readonly="readonly"
:headers="uploadHeaders"
large
@success="url => handleIdCardUploadSuccess('idCardFront', url)"
/>
</el-col>
<el-col :span="8">
<image-upload-field
label="身份证反面照"
prop="idCardBack"
:value="driverForm.idCardBack"
:readonly="readonly"
:headers="uploadHeaders"
large
@success="url => handleIdCardUploadSuccess('idCardBack', url)"
/>
</el-col>
<el-col :span="8">
<image-upload-field
label="大头照"
prop="headPhoto"
:value="driverForm.headPhoto"
:readonly="readonly"
:headers="uploadHeaders"
large
@success="url => setImage('headPhoto', url)"
/>
</el-col>
</el-row>
</section-card>
<section-card title="驾驶证信息">
<el-row :gutter="18">
<el-col :span="6">
<el-form-item label="准驾车型" prop="drivingType">
<el-select
v-model="driverForm.drivingType"
clearable
filterable
allow-create
default-first-option
>
<el-option
v-for="item in drivingTypeOptions"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="档案编号" prop="drivingLicenseNo">
<el-input v-model="driverForm.drivingLicenseNo" maxlength="50" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="有效期" prop="drivingLicenseEndDate">
<div class="date-range">
<el-date-picker
v-model="driverForm.drivingLicenseStartDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="起"
@change="validateFormField('drivingLicenseEndDate')"
/>
<el-date-picker
v-model="driverForm.drivingLicenseEndDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="止"
:disabled="driverForm.drivingLicenseLongTerm === 1"
@change="validateFormField('drivingLicenseEndDate')"
/>
</div>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="长期有效" prop="drivingLicenseLongTerm">
<el-checkbox
v-model="driverForm.drivingLicenseLongTerm"
:true-label="1"
:false-label="0"
@change="validateFormField('drivingLicenseEndDate')"
>
</el-checkbox>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="18">
<el-col :span="12">
<image-upload-field
label="驾驶证主页"
prop="drivingLicenseFront"
:value="driverForm.drivingLicenseFront"
:readonly="readonly"
:headers="uploadHeaders"
large
@success="
(url, file) => handleDrivingLicenseUploadSuccess('drivingLicenseFront', url, file)
"
/>
</el-col>
<el-col :span="12">
<image-upload-field
label="驾驶证副页"
prop="drivingLicenseBack"
:value="driverForm.drivingLicenseBack"
:readonly="readonly"
:headers="uploadHeaders"
large
@success="
(url, file) => handleDrivingLicenseUploadSuccess('drivingLicenseBack', url, file)
"
/>
</el-col>
</el-row>
</section-card>
<section-card title="从业资格证信息">
<el-row :gutter="18">
<el-col :span="6">
<el-form-item label="从业资格认证类型" prop="qualificationType">
<el-select
v-model="driverForm.qualificationType"
clearable
filterable
allow-create
default-first-option
>
<el-option
v-for="item in qualificationTypeOptions"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="资格证号" prop="qualificationNo">
<el-input
v-model="driverForm.qualificationNo"
maxlength="50"
placeholder="默认身份证号"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="有效期" prop="qualificationEndDate">
<el-date-picker
v-model="driverForm.drivingLicenseEndDate"
v-model="driverForm.qualificationEndDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="止"
:disabled="driverForm.drivingLicenseLongTerm === 1"
@change="validateFormField('drivingLicenseEndDate')"
:disabled="driverForm.qualificationLongTerm === 1"
@change="validateFormField('qualificationEndDate')"
/>
</div>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="长期有效" prop="drivingLicenseLongTerm">
<el-checkbox
v-model="driverForm.drivingLicenseLongTerm"
:true-label="1"
:false-label="0"
@change="validateFormField('drivingLicenseEndDate')"
>
</el-checkbox>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="18">
<el-col :span="12">
<image-upload-field
label="驾驶证主页"
prop="drivingLicenseFront"
:value="driverForm.drivingLicenseFront"
:readonly="readonly"
:headers="uploadHeaders"
large
@success="
(url, file) =>
handleDrivingLicenseUploadSuccess('drivingLicenseFront', url, file)
"
/>
</el-col>
<el-col :span="12">
<image-upload-field
label="驾驶证副页"
prop="drivingLicenseBack"
:value="driverForm.drivingLicenseBack"
:readonly="readonly"
:headers="uploadHeaders"
large
@success="
(url, file) => handleDrivingLicenseUploadSuccess('drivingLicenseBack', url, file)
"
/>
</el-col>
</el-row>
<div class="section-title">从业资格证信息</div>
<el-row :gutter="18">
<el-col :span="6">
<el-form-item label="从业资格认证类型" prop="qualificationType">
<el-select
v-model="driverForm.qualificationType"
clearable
filterable
allow-create
default-first-option
>
<el-option
v-for="item in qualificationTypeOptions"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="资格证号" prop="qualificationNo">
<el-input
v-model="driverForm.qualificationNo"
maxlength="50"
placeholder="默认身份证号"
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="长期有效" prop="qualificationLongTerm">
<el-checkbox
v-model="driverForm.qualificationLongTerm"
:true-label="1"
:false-label="0"
@change="validateFormField('qualificationEndDate')"
>
</el-checkbox>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="18">
<el-col :span="12">
<image-upload-field
label="封面页"
prop="qualificationFront"
:value="driverForm.qualificationFront"
:readonly="readonly"
:headers="uploadHeaders"
large
@success="url => setImage('qualificationFront', url)"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="有效期" prop="qualificationEndDate">
<el-date-picker
v-model="driverForm.qualificationEndDate"
type="date"
value-format="YYYY-MM-DD"
:disabled="driverForm.qualificationLongTerm === 1"
@change="validateFormField('qualificationEndDate')"
</el-col>
<el-col :span="12">
<image-upload-field
label="内容页"
prop="qualificationBack"
:value="driverForm.qualificationBack"
:readonly="readonly"
:headers="uploadHeaders"
large
@success="url => setImage('qualificationBack', url)"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="长期有效" prop="qualificationLongTerm">
<el-checkbox
v-model="driverForm.qualificationLongTerm"
:true-label="1"
:false-label="0"
@change="validateFormField('qualificationEndDate')"
>
</el-checkbox>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="18">
<el-col :span="12">
<image-upload-field
label="封面页"
prop="qualificationFront"
:value="driverForm.qualificationFront"
:readonly="readonly"
:headers="uploadHeaders"
large
@success="url => setImage('qualificationFront', url)"
/>
</el-col>
<el-col :span="12">
<image-upload-field
label="内容页"
prop="qualificationBack"
:value="driverForm.qualificationBack"
:readonly="readonly"
:headers="uploadHeaders"
large
@success="url => setImage('qualificationBack', url)"
/>
</el-col>
</el-row>
</el-col>
</el-row>
</section-card>
<div class="section-title">司机联系信息</div>
<el-row :gutter="18">
<el-col :span="8">
<el-form-item label="司机类型" prop="driverType">
<el-select v-model="driverForm.driverType" filterable>
<el-option label="自有" value="自有" />
<el-option label="外协" value="外协" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="手机号" prop="mobile">
<el-input v-model="driverForm.mobile" maxlength="20" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="紧急联系人姓名" prop="emergencyContactName">
<el-input v-model="driverForm.emergencyContactName" maxlength="20" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="18">
<el-col :span="8">
<el-form-item label="紧急联系人手机号" prop="emergencyContactMobile">
<el-input v-model="driverForm.emergencyContactMobile" maxlength="20" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="与联系人关系" prop="contactRelation">
<el-select
v-model="driverForm.contactRelation"
clearable
filterable
allow-create
default-first-option
>
<el-option
v-for="item in relationOptions"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="所属组织" prop="organizationName">
<el-select v-model="driverForm.organizationName" clearable filterable>
<el-option
v-for="item in organizationOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<section-card title="司机联系信息">
<el-row :gutter="18">
<el-col :span="8">
<el-form-item label="司机类型" prop="driverType">
<el-select v-model="driverForm.driverType" filterable>
<el-option label="自有" value="自有" />
<el-option label="外协" value="外协" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="手机号" prop="mobile">
<el-input v-model="driverForm.mobile" maxlength="20" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="紧急联系人姓名" prop="emergencyContactName">
<el-input v-model="driverForm.emergencyContactName" maxlength="20" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="18">
<el-col :span="8">
<el-form-item label="紧急联系人手机号" prop="emergencyContactMobile">
<el-input v-model="driverForm.emergencyContactMobile" maxlength="20" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="与联系人关系" prop="contactRelation">
<el-select
v-model="driverForm.contactRelation"
clearable
filterable
allow-create
default-first-option
>
<el-option
v-for="item in relationOptions"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="所属组织" prop="organizationName">
<el-select v-model="driverForm.organizationName" clearable filterable>
<el-option
v-for="item in organizationOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</section-card>
</el-form>
<template #footer>
<el-button @click="driverBox = false">取消</el-button>
@@ -1330,19 +1334,6 @@ export default {
}
.driver-form {
.section-title {
margin: 18px 0 14px;
padding-left: 10px;
border-left: 3px solid #e74b5f;
color: #303133;
font-weight: 600;
line-height: 18px;
}
.section-title:first-child {
margin-top: 0;
}
:deep(.el-date-editor.el-input),
:deep(.el-date-editor.el-input__wrapper),
:deep(.el-cascader),
@@ -1358,9 +1349,9 @@ export default {
}
}
// 大尺寸证件照:按身份证 1.586:1 比例缩放(约真实尺寸 75%240×151左对齐显示
:deep(.driver-uploader) {
display: block;
width: 100%;
}
:deep(.driver-uploader .el-upload),
@@ -1375,9 +1366,17 @@ export default {
overflow: hidden;
}
// 大尺寸模式:缩成 1.586:1 比例,左对齐(不再 100% 占栏)
:deep(.driver-uploader--large) {
display: block;
width: 240px;
margin: 0;
}
:deep(.driver-uploader--large .el-upload),
:deep(.driver-uploader--large.el-upload) {
height: 260px;
width: 100%;
height: 151px;
}
:deep(.driver-uploader__image) {
@@ -1396,6 +1395,7 @@ export default {
color: #606266;
}
// 弹窗内可滚动(弹窗 body 灰底已由全局 .el-dialog__body 规则生效)
.driver-dialog {
:deep(.el-dialog__body) {
max-height: 72vh;