From d187da68d22efc8a51ee2818b9ddf8f82bb7d69c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Wed, 9 Sep 2026 15:11:53 +0800 Subject: [PATCH 1/6] =?UTF-8?q?fix(contract-manage):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=90=88=E5=90=8C=E7=AE=A1=E7=90=86=E9=A1=B5=E9=9D=A2=E5=B8=83?= =?UTF-8?q?=E5=B1=80=E5=8F=8A=E5=AD=97=E5=85=B8=E6=95=B0=E6=8D=AE=E8=AF=BB?= =?UTF-8?q?=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 合同文件「批量下载」按钮调整为与标题同排且垂直居中 - 修改内联组件render函数结构及相关样式,统一合同文件和其它附件布局 - 合同格式下拉改为动态读取业务字典contractFormat,保留静态兜底 - 合同类别contractCategory下拉改为业务字典读取,替代硬编码选项 - 表单增加所属组织、签订日期、回款账期、开票周期、结算币种等字段 - 调整字段顺序,完善表单输入限制和控件属性 - 替换部分按钮类型,优化用户交互体验 - 修复detailValue字典映射,显示合同格式标签 - 修正样式`:deep`选择器,解决scoped样式对子组件无效问题 --- .workbuddy/memory/2026-09-09.md | 28 +++++ src/views/business/contract-manage.vue | 140 +++++++++++++++---------- 2 files changed, 113 insertions(+), 55 deletions(-) diff --git a/.workbuddy/memory/2026-09-09.md b/.workbuddy/memory/2026-09-09.md index 5ab529a..05c0cec 100644 --- a/.workbuddy/memory/2026-09-09.md +++ b/.workbuddy/memory/2026-09-09.md @@ -55,3 +55,31 @@ - api 新增 `getFundRiskStats` → GET /blade-transport/project-apply/fund-risk-stats。 - 后端契约(未改,待确认数据来源):ProjectApplyVO 补齐 `fundUseRisk`(high/medium/none)、`fundUseRiskName`、`fundUseRate`、`usedFundLimit`/`remainingFundLimit`;列表 selectProjectApplyPage 填充每行风险 + buildQuery 支持 `fundUseRisk` 过滤;新增 `/fund-risk-stats` 返回 {high,medium,none}。 - ⚠️ 关键阻塞:系统里项目与任何费用表(运输计划/运单/账单/客商)均无关联字段,`usedFundLimit`(已使用资金) 无真实取数来源;临时额度模块的 project-apply/list 返回里 usedFundLimit 实际为空。需业务方确认「已使用资金」口径后才能算风险等级,否则列表风险列全空、统计为 0。 + +## 合同文件「批量下载」按钮与标题同排(contract-manage.vue 内联 AttachmentSection) +- 需求:编辑页「合同文件」分组里「批量下载」按钮目前独立一行、靠右偏上,高度与标题区错位;要放到「合同文件」标题右侧同排、垂直居中。 +- 修复:`const AttachmentSection = defineComponent(...)` 内联组件 render() —— 原结构是 `div.dialog-section-title`(标题) 与 `div.contract-manage-form__attachment-head`(批量下载按钮) 两个并列 div;改为把标题与按钮放进同一个 `contract-manage-form__attachment-head` flex 容器(标题左、按钮右)。 +- 样式:`:deep(.contract-manage-form__attachment-head)` 由 `justify-content:flex-end` 改为 `space-between` + `align-items:center`,并 `.dialog-section-title { margin-bottom:0 }` 抵消标题自身 20px 下边距(2674 行 `:deep(.dialog-section-title)` 会命中子组件渲染的标题)。 +- 注意:AttachmentSection 用 render 函数产出 DOM,不带当前组件 scoped data 属性,因此样式必须走 `:deep()`;scoped 的 `&__billing-head, &__attachment-head`(2723) 只作用于当前组件模板内(计费信息),对子组件 DOM 无效。 +- 影响:4 处使用(编辑/详情 × 合同文件/其它附件)布局统一变为「标题 + 批量下载」同排。 +- 主人二次反馈「下面的其它附件也一样」——确认 L463(编辑/其它附件 description) / L765(详情/其它附件 description+readonly) 与 L313(编辑/合同文件) / L671(详情/合同文件) 都走同一份 render+样式,无需新代码;指挥浏览器 Cmd+Shift+R 硬刷即可看到效果(render 函数组件的 :deep() 样式改 HMR 经常不传播)。 + +## 合同格式下拉改读业务字典 contractFormat(contract-manage.vue) +- 需求:新增/编辑合同管理页「合同格式」下拉由硬编码改为读取业务字典 `contractFormat`。 +- 原实现:`option/business/contract-manage.js` 里 `contractFormat` 列 `dicData` 硬编码 `[{label:'电子合同',value:'电子合同'},{label:'纸质合同',value:'纸质合同'}]`,view 里 `contractFormatOptions` computed 直接 `columnOptions('contractFormat')` 读 column.dicData。 +- 修复(4 处): + 1. data 加 `contractFormatDictOptions: []`(与 settlementModeDictOptions 并列)。 + 2. computed `contractFormatOptions` 改为优先 `contractFormatDictOptions`,为空回退 `columnOptions('contractFormat')`(保留静态兜底)。 + 3. `loadSettlementDictionaries` 的 `Promise.all` 追加 `getBizDictionary({ code: 'contractFormat' })`,用 `records()` 映射 `{label:dictValue,value:dictKey}` 填充 `contractFormatDictOptions`;再**条件覆盖** column.dicData(仅当字典非空时),避免字典未配时清掉静态兜底。 + 4. `detailValue` 的字典映射分支加入 `prop === 'contractFormat'`,详情页「合同格式」也走 `displayStatus` 显示 label。 +- 后端契约:`getBizDictionary` → `GET /blade-system/dict-biz/dictionary?code=contractFormat`,返回 `List{code,dictKey,dictValue,remark}`(DictBizController#dictionary 按 code 精确匹配)。字典 code 按用户口述用驼峰 `contractFormat`(现有 settle_method 为下划线,若后台实际是 `contract_format` 需调整 code)。 +- 参考模式:与 `settlementMode`(settle_method)完全一致。 + +## 合同类别 contractCategory 也读业务字典(contract-manage.vue,续上) +- 需求:模板里 label 实为「合同类型」(prop `contractCategory`),下拉由硬编码 `common.js#contractCategoryOptions`(客户合同/承运商合同/补充协议,value 中文)改为读业务字典 `contractCategory`。 +- 修复(3 处,与 contractFormat 同模式): + 1. data 加 `contractCategoryDictOptions: []`。 + 2. computed `contractCategoryOptions` 改为优先 `contractCategoryDictOptions`,空回退 `columnOptions('contractCategory')`(静态兜底)。 + 3. `loadSettlementDictionaries` 的 `Promise.all` 追加 `getBizDictionary({ code: 'contractCategory' })`,映射填充后**条件覆盖** `contractCategory` 列 dicData(仅非空时)。 +- 列表页列显示/搜索下拉、详情页(detailValue 已有 `prop==='contractCategory'` 分支走 displayStatus)均因 column.dicData 覆盖而自动跟随业务字典。 +- 注意:`config.defaultForm.contractCategory: '客户合同'`(option/contract-manage.js)为硬编码中文默认值,若业务字典 dictKey 非中文需同步调整。 diff --git a/src/views/business/contract-manage.vue b/src/views/business/contract-manage.vue index 514e742..6fc60f8 100644 --- a/src/views/business/contract-manage.vue +++ b/src/views/business/contract-manage.vue @@ -163,6 +163,17 @@ /> + + + + + +
- - + + - - + + - - + + + + @@ -249,28 +270,18 @@ /> - - - - - - - - - + + + + @@ -283,19 +294,8 @@ /> - - - - - + + @@ -431,7 +431,7 @@ - 添加 + 添加 @@ -1170,8 +1170,8 @@ const AttachmentSection = defineComponent({ class: 'contract-manage-form__section contract-manage-form__section--panel', }, [ - h('div', { class: 'dialog-section-title' }, this.title), h('div', { class: 'contract-manage-form__attachment-head' }, [ + h('div', { class: 'dialog-section-title' }, this.title), h( ElButton, { type: 'primary', disabled: !this.rows.length, onClick: this.batchDownload }, @@ -1270,6 +1270,8 @@ export default { selectedProjectId: '', settlementCurrencyOptions: [], settlementModeDictOptions: [], + contractFormatDictOptions: [], + contractCategoryDictOptions: [], contractPartyAOptions: [], contractPartyBOptions: [], contractPartyLoading: false, @@ -1358,7 +1360,9 @@ export default { return this.selectionList.map(item => item.id).join(','); }, contractCategoryOptions() { - return this.columnOptions('contractCategory'); + return this.contractCategoryDictOptions.length + ? this.contractCategoryDictOptions + : this.columnOptions('contractCategory'); }, signTypeOptions() { return this.columnOptions('signType'); @@ -1372,7 +1376,9 @@ export default { : this.columnOptions('settlementMode'); }, contractFormatOptions() { - return this.columnOptions('contractFormat'); + return this.contractFormatDictOptions.length + ? this.contractFormatDictOptions + : this.columnOptions('contractFormat'); }, organizationCascaderProps() { return { @@ -1822,7 +1828,9 @@ export default { Promise.all([ getSystemDictionary({ code: 'currency_type' }), getBizDictionary({ code: 'settle_method' }), - ]).then(([currencyRes, methodRes]) => { + getBizDictionary({ code: 'contractFormat' }), + getBizDictionary({ code: 'contractCategory' }), + ]).then(([currencyRes, methodRes, formatRes, categoryRes]) => { const records = response => { const data = response?.data?.data || response?.data || []; return Array.isArray(data) ? data : data.records || []; @@ -1835,10 +1843,26 @@ export default { label: item.dictValue, value: item.dictKey, })); + this.contractFormatDictOptions = records(formatRes).map(item => ({ + label: item.dictValue, + value: item.dictKey, + })); + this.contractCategoryDictOptions = records(categoryRes).map(item => ({ + label: item.dictValue, + value: item.dictKey, + })); ['settlementMode'].forEach(prop => { const column = this.findColumn(this.tableOption.column, prop); if (column) column.dicData = this.settlementModeDictOptions; }); + const formatColumn = this.findColumn(this.tableOption.column, 'contractFormat'); + if (formatColumn && this.contractFormatDictOptions.length) { + formatColumn.dicData = this.contractFormatDictOptions; + } + const categoryColumn = this.findColumn(this.tableOption.column, 'contractCategory'); + if (categoryColumn && this.contractCategoryDictOptions.length) { + categoryColumn.dicData = this.contractCategoryDictOptions; + } }); }, syncCurrentProjectOption() { @@ -2428,7 +2452,8 @@ export default { prop === 'approvalStatus' || prop === 'contractCategory' || prop === 'signType' || - prop === 'effectiveType' + prop === 'effectiveType' || + prop === 'contractFormat' ) { return this.displayStatus(this.detailRow, prop); } @@ -2819,8 +2844,13 @@ export default { :deep(.contract-manage-form__attachment-head) { display: flex; align-items: center; - justify-content: flex-end; + justify-content: space-between; margin-bottom: 16px; + + // 标题与「批量下载」按钮同排、垂直居中,消除标题自身下边距 + .dialog-section-title { + margin-bottom: 0; + } } :deep(.contract-manage-form__attachment-upload) { From 197211517355ed8122258d7f0cc4c86647259967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Wed, 9 Sep 2026 15:37:40 +0800 Subject: [PATCH 2/6] =?UTF-8?q?feat(transportCapacity):=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E8=BD=A6=E8=BE=86=E4=B8=8E=E5=8F=B8=E6=9C=BA=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=E5=B8=83=E5=B1=80=E5=B9=B6=E6=96=B0=E5=A2=9E=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 车辆新增弹窗:所有组织移至基础车辆信息区末尾,新增使用部门字段,使用部门复用部门下拉 - 车牌号三段合并为整体输入框,优化样式为flex布局,去除多余边框及阴影,统一视觉 - 长期有效勾选时清空对应日期且禁用输入,新增handleLongTermChange方法,表单校验支持长期有效跳过必填 - 司机弹窗基础身份信息新增placeholder,调整布局,基础身份三列保持不变,其他信息行按需求拆分重排为一致三列 - 后端新增use_department字段,相关mapper、service及校验同步更新,新增增量迁移脚本支持 - 车辆表单相关输入控件宽度统一调整为6列布局,保持与其它区块一致,提升整体UI协调性 - 移除车辆车牌号拆分相关字段及逻辑,车牌号统一管理为单个字段,简化处理流程 - 代码中新增校验规则validateDrivingLicenseEndDate及validateRoadTransportCertEndDate,支持长期有效逻辑 - 优化图片上传区和证件信息区表单字段排列,提升表单整体易用性与规范性 --- .workbuddy/memory/2026-09-09.md | 29 ++ src/views/transportCapacity/driver.vue | 84 ++++-- src/views/transportCapacity/vehicle.vue | 352 +++++++++++++----------- 3 files changed, 279 insertions(+), 186 deletions(-) diff --git a/.workbuddy/memory/2026-09-09.md b/.workbuddy/memory/2026-09-09.md index 05c0cec..8c736c1 100644 --- a/.workbuddy/memory/2026-09-09.md +++ b/.workbuddy/memory/2026-09-09.md @@ -83,3 +83,32 @@ 3. `loadSettlementDictionaries` 的 `Promise.all` 追加 `getBizDictionary({ code: 'contractCategory' })`,映射填充后**条件覆盖** `contractCategory` 列 dicData(仅非空时)。 - 列表页列显示/搜索下拉、详情页(detailValue 已有 `prop==='contractCategory'` 分支走 displayStatus)均因 column.dicData 覆盖而自动跟随业务字典。 - 注意:`config.defaultForm.contractCategory: '客户合同'`(option/contract-manage.js)为硬编码中文默认值,若业务字典 dictKey 非中文需同步调整。 + +## 车辆新增弹窗:所有组织移位 + 使用部门 + 长期有效清空(vehicle.vue + 后端) +- 需求(transportCapacity/vehicle):①所有组织移到「基础车辆信息」区末尾;②新增「使用部门」字段(后端 transport_vehicle 无该字段,需加);③车牌号三段(省/号码/颜色)包成整体输入框+减宽;④勾选「长期有效」清空对应日期且不可编辑。 +- 用户确认:所有组织+使用部门放「基础车辆信息」区末尾;使用部门用部门下拉(复用 getDeptTree→organizationOptions,存部门名,仅部门名非级联);车牌号包成整体输入框+减宽;长期有效 4 组全部统一清空(强制报废/行驶证/道路运输证/年审)。 +- 前端(vehicle.vue): + 1. emptyForm 加 `useDepartment: ''`。 + 2. 删「基础车辆信息」首行的「所有组织」(原 span24),在区末新增一行:`使用部门`(span8, el-select+organizationOptions, 存 rawLabel) + `所有组织`(span8, el-cascader)。organizationOptions 由 initDeptTree 填充。 + 3. `.plate-group` 由 grid(112px 1fr 112px) 改为 flex 整体输入框:外层 border+radius+focus-within 变化;内部 el-select/el-input 去 box-shadow、无边框,第一/最后 select flex 0 0 30%、中间 input flex 1,子项间用 `::before` 竖线分隔。 + 4. 4 组 date-picker 加 `:disabled="xxxLongTerm === 1"`(行驶证/道路运输证原缺,补上),checkbox 加 `@change="handleLongTermChange(日期prop, longterm prop)"`;新增方法 handleLongTermChange(勾选时清空日期并 validateField)。 + 5. formRules:drivingLicenseEndDate / roadTransportCertEndDate 由 required 改为 validator(新增 validateDrivingLicenseEndDate / validateRoadTransportCertEndDate,longTerm===1 时跳过必填),annualReview 原 validator 已支持。 +- 后端(tms-erp-api-ws,新增 use_department 列): + - `TransportVehicle.java` 加 `private String useDepartment`。 + - `blade_transport_vehicle.sql` 建表加 `use_department varchar(50)`。 + - `TransportVehicleExcel.java` 加 `使用部门` 列。 + - `TransportVehicleMapper.xml` resultMap + BaseColumn + QueryCondition(useDepartment LIKE) 各加。 + - `TransportVehicleServiceImpl.prepare()` trim useDepartment;validate() 加长度≤50 校验。 + - 新增增量迁移 `doc/sql/transport/blade_transport_vehicle_use_department_patch_20260909.sql`(ALTER ADD use_department AFTER organization_name)。 +- 注意:VO 继承 entity 无需改;Wrapper BeanUtil 同名透传。已上线库须执行 patch SQL(建表脚本是 DROP+CREATE,勿直接跑)。 +- 后续补充(vehicle.vue「车辆资质图片」区输入框对齐):第一行原 span `6/8/10` 不等宽(行驶证档案编号 6 / 行驶证有效期 8 / 道路运输证号 10)导致输入框宽度不齐,统一改为 `8/8/8`,与下方各行 span=8 一致。仅改 2 处 span,无逻辑改动。 + +## 司机弹窗:补 placeholder + 每行统一 3 列(transportCapacity/driver.vue) +- 需求:新增/编辑司机弹窗 ①输入框无提示文案;②基础身份信息 3 列,其它 4 列 / 6 列行不统一。 +- 改动(仅 1819 行 driver.vue 的 126-540 行 `` 模板,script/style 不动): + 1. **基础身份信息**:行结构不动,7 个 el-form-item 控件补 placeholder(司机姓名/身份证号/出生年月/性别/民族/学历/详细地址)。住址已有「请选择省市区」、驾驶车辆已有「请输入或选择车辆」,不动。 + 2. **驾驶证信息**:第一行 4 列(:span=6)拆为两行 — 行 1(准驾车型 / 档案编号 / 有效期 date-range,:span=8)+ 行 2(长期有效,:span=8)。起/止 placeholder 保留简短「起」「止」,符合主人 1.B 偏好(保留原 date-range 二联结构,不改 daterange)。 + 3. **从业资格证信息**:第一行 4 列拆为两行 — 行 1(从业资格认证类型 / 资格证号 / 有效期,:span=8)+ 行 2(长期有效,:span=8)。资格证号 placeholder 保留「默认身份证号」不动。 + 4. **司机联系信息**:一行 6 列拆为两行 — 行 1(司机类型 / 手机号 / 紧急联系人姓名,:span=8)+ 行 2(紧急联系人手机号 / 与联系人关系 / 所属组织,:span=8)。所属组织已有 placeholder,不动。 +- 决策点(主人确认):1.B(保留原 date-range 二联 + 第三列留空后拆行的方案);2 保留;3.A(驾驶证主页/副页、封面页/内容页两组上传图仍 :span=12,与占整行宽的原貌一致)。 +- 校验:node 脚本统计 4 个 section-card / 13 个 el-row / 31 个 el-col / 24 个 el-form-item,全平衡。改动只在 driver.vue 一文件,~25 处 Edit 调用。 diff --git a/src/views/transportCapacity/driver.vue b/src/views/transportCapacity/driver.vue index 708249e..9f9e9a7 100644 --- a/src/views/transportCapacity/driver.vue +++ b/src/views/transportCapacity/driver.vue @@ -125,43 +125,50 @@ > - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -238,7 +255,7 @@ - + - + - + - + @@ -320,6 +342,8 @@ + + + + - + @@ -453,7 +481,11 @@ - + @@ -461,13 +493,20 @@ + + - + @@ -478,6 +517,7 @@ filterable allow-create default-first-option + placeholder="请选择与联系人关系" > - + {{ auditValue('plateNo') }} - + {{ auditValue('plateColor') }} - + {{ auditValue('vehicleType') }} - + {{ auditValue('businessRelation') }} - + {{ auditValue('energyType') }} - + {{ auditValue('compulsoryScrapDate') }} @@ -176,29 +176,29 @@ - + {{ auditValue('outerLength') }} - + {{ auditValue('outerWidth') }} - + {{ auditValue('outerHeight') }} - + {{ auditValue('approvedLoadKg') }} - + {{ auditValue('tractionMassKg') }} @@ -208,17 +208,17 @@ - + {{ auditValue('customsRecordNo') }} - + {{ auditValue('drivingLicenseNo') }} - + {{ auditValue('drivingLicenseStartDate') }} @@ -227,21 +227,21 @@ - + {{ auditValue('drivingLicenseEndDate') }} - + {{ auditValue('roadTransportCertNo') }} - + {{ auditValue('roadTransportCertStartDate') }} @@ -250,28 +250,28 @@ - + {{ auditValue('roadTransportCertEndDate') }} - + {{ auditValue('annualReviewEndDate') }} - + {{ auditValue('registrationNo') }} - + {{ auditValue('registrationDate') }} @@ -288,7 +288,7 @@ - + - + - + - + - + - + - - - - - - - -
- - - - - - - -
+
@@ -462,7 +423,7 @@
- +
@@ -494,7 +455,7 @@ - + - + - + - + - +
长期有效
- +
+ + + + + + + + + + + + + + @@ -577,50 +570,54 @@ - +
长期有效
- + - +
长期有效
- +
长期有效 @@ -641,12 +639,12 @@ - + - + - + - + - + - + - + - + ({ id: '', organizationName: '', - plateProvince: '', - plateNoBody: '', + useDepartment: '', plateNo: '', plateColor: '', vehicleType: '', @@ -823,44 +820,6 @@ const emptyForm = () => ({ status: 1, }); -const plateProvinceOptions = [ - '京', - '津', - '沪', - '渝', - '冀', - '豫', - '云', - '辽', - '黑', - '湘', - '皖', - '鲁', - '新', - '苏', - '浙', - '赣', - '鄂', - '桂', - '甘', - '晋', - '蒙', - '陕', - '吉', - '闽', - '贵', - '粤', - '青', - '藏', - '川', - '宁', - '琼', - '港', - '澳', -].map(item => ({ label: item, value: item })); - -const plateColorOptions = ['黄牌', '蓝牌', '绿牌'].map(item => ({ label: item, value: item })); - export default { components: { ImageUploadField, @@ -904,8 +863,6 @@ export default { vehicleCertificateUploads: {}, uploadHeaders: getUploadHeaders(), organizationOptions: [], - plateProvinceOptions, - plateColorOptions, vehicleTypeOptions: [ { label: '高栏车', value: '高栏' }, { label: '低栏车', value: '低栏' }, @@ -928,11 +885,11 @@ export default { energyType: [{ required: true, message: '请选择能源类型', trigger: 'change' }], drivingLicenseNo: [{ required: true, message: '请输入行驶证档案编号', trigger: 'blur' }], drivingLicenseEndDate: [ - { required: true, message: '请选择行驶证有效期', trigger: 'change' }, + { validator: this.validateDrivingLicenseEndDate, trigger: 'change' }, ], roadTransportCertNo: [{ required: true, message: '请输入道路运输证号', trigger: 'blur' }], roadTransportCertEndDate: [ - { required: true, message: '请选择道路运输证有效期', trigger: 'change' }, + { validator: this.validateRoadTransportCertEndDate, trigger: 'change' }, ], annualReviewEndDate: [{ validator: this.validateAnnualReviewEndDate, trigger: 'change' }], registrationNo: [{ required: true, message: '请输入机动车登记编号', trigger: 'blur' }], @@ -1021,19 +978,20 @@ export default { return String(value).replace(/\D/g, ''); }, validatePlateNo(rule, value, callback) { - const plateProvince = String(this.vehicleForm.plateProvince || '').trim(); - const plateNoBody = String(this.vehicleForm.plateNoBody || '') + const plateNo = String(value || '') .trim() .toUpperCase(); - const plateColor = String(this.vehicleForm.plateColor || '').trim(); - if (!plateProvince || !plateNoBody || !plateColor) { - callback(new Error('请完整填写车牌号')); + if (!plateNo) { + callback(new Error('请输入车牌号')); return; } - if (!/^[A-Z][A-Z0-9挂学警港澳]{5,6}$/.test(plateNoBody)) { - callback(new Error('请输入标准车牌号')); + if (!/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼港澳]{1}[A-Z][A-Z0-9挂学警港澳]{5,6}$/.test(plateNo)) { + callback(new Error('请输入标准车牌号(如:京A12345)')); return; } + if (this.vehicleForm.plateNo !== plateNo) { + this.vehicleForm.plateNo = plateNo; + } callback(); }, validateAnnualReviewEndDate(rule, value, callback) { @@ -1043,6 +1001,35 @@ export default { } callback(); }, + // 长期有效勾选:勾选时清空对应日期(不可编辑由 date-picker :disabled 控制),取消勾选后可重新填报 + handleLongTermChange(dateProp, longTermProp) { + if (this.vehicleForm[longTermProp] === 1) { + this.vehicleForm[dateProp] = ''; + } + this.$refs.vehicleForm?.validateField(dateProp); + }, + validateDrivingLicenseEndDate(rule, value, callback) { + if (this.vehicleForm.drivingLicenseLongTerm === 1 && !value) { + callback(); + return; + } + if (!value) { + callback(new Error('请选择行驶证有效期')); + return; + } + callback(); + }, + validateRoadTransportCertEndDate(rule, value, callback) { + if (this.vehicleForm.roadTransportCertLongTerm === 1 && !value) { + callback(); + return; + } + if (!value) { + callback(new Error('请选择道路运输证有效期')); + return; + } + callback(); + }, openVehicle(row, readonly = false) { this.readonly = readonly; if (!row?.id) { @@ -1420,28 +1407,16 @@ export default { this.syncPlateNo(); }, syncPlateNo(validate = true) { - const plateProvince = String(this.vehicleForm.plateProvince || '').trim(); - const plateNoBody = String(this.vehicleForm.plateNoBody || '') - .trim() + const plateNo = String(this.vehicleForm.plateNo || '') + .replace(/\s/g, '') .toUpperCase(); - const plateColor = String(this.vehicleForm.plateColor || '').trim(); - this.vehicleForm.plateNoBody = plateNoBody; - this.vehicleForm.plateNo = - plateProvince && plateNoBody ? `${plateProvince}${plateNoBody}` : ''; - this.vehicleForm.plateColor = plateColor; + this.vehicleForm.plateNo = plateNo; if (validate) { this.$refs.vehicleForm?.validateField('plateNo'); } }, splitPlateNo() { - const plateNo = String(this.vehicleForm.plateNo || '').trim(); - if (!plateNo) { - this.vehicleForm.plateProvince = ''; - this.vehicleForm.plateNoBody = ''; - return; - } - this.vehicleForm.plateProvince = plateNo.slice(0, 1); - this.vehicleForm.plateNoBody = plateNo.slice(1).toUpperCase(); + // 车牌号已统一为单一 input,无需拆分 }, handleSubmit() { this.syncPlateNo(); @@ -1681,10 +1656,60 @@ export default { } .plate-group { - display: grid; - grid-template-columns: 112px minmax(0, 1fr) 112px; - gap: 8px; + display: flex; align-items: center; + overflow: hidden; + border: 1px solid #dcdfe6; + border-radius: 4px; + background: #fff; + transition: border-color 0.2s; + + &:hover { + border-color: #c0c4cc; + } + + &:focus-within { + border-color: #409eff; + } + + // 三个子控件:去掉各自边框,整体形成一个输入框 + :deep(.el-select), + :deep(.el-input) { + position: relative; + flex: 1; + min-width: 0; + height: 32px; + } + + :deep(.el-select:first-child) { + flex: 0 0 12%; + } + + :deep(.el-select:last-child) { + flex: 0 0 18%; + } + + :deep(.el-input__wrapper), + :deep(.el-select__wrapper) { + box-shadow: none !important; + border-radius: 0; + padding: 0 8px; + } + + // 子项之间用竖线分隔,视觉上是一个整体 + :deep(.el-select + .el-select), + :deep(.el-select + .el-input), + :deep(.el-input + .el-select) { + &::before { + content: ''; + position: absolute; + left: 0; + top: 6px; + bottom: 6px; + width: 1px; + background: #e4e7ed; + } + } } .dimension-group { @@ -1704,7 +1729,6 @@ export default { .dimension-group__label { flex-shrink: 0; color: #303133; - font-weight: 500; } .date-with-flag { From 14c6ad0a31ca0309282bf85d8b58c7e9495062de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Wed, 9 Sep 2026 17:19:33 +0800 Subject: [PATCH 3/6] =?UTF-8?q?feat(vehicle):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=BD=A6=E8=BE=86=E7=AE=A1=E7=90=86=E7=9B=B8=E5=85=B3=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E5=B8=83=E5=B1=80=E5=92=8C=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 车牌号组件改为单一输入框,去除省简称和颜色选择,实现完整车牌号输入 - 重写车牌号校验逻辑,校验完整车牌号格式,错误提示更加明确 - 车辆新增/编辑弹窗输入框宽度统一调整,基础信息和资质图片区按四列布局排列 - 修复所有组织字段宽度不一致问题,补充级联选择器样式支持 - 司机新增/编辑弹窗调整为四列布局,调整字段排列顺序,提升界面整洁度 - 客商档案中「客商类型」改名为「客商分类」,新增「客商类型」字段支持外部客商和内部组织区分 - 上传证件项 label 贴顶问题修复,统一提升到全局样式实现垂直居中 - 移除车牌颜色只读展示,审核弹窗同步删除车牌颜色字段 - 保持后端接口兼容,数据库字段未变,OCR同步调用链路无影响 --- .workbuddy/memory/2026-09-09.md | 56 ++++++++++++++ src/styles/element-ui.scss | 8 ++ src/views/transportCapacity/driver.vue | 24 ++---- src/views/transportCapacity/vehicle.vue | 99 +++++-------------------- src/views/vehicle/customer-archive.vue | 38 +++++++++- 5 files changed, 125 insertions(+), 100 deletions(-) diff --git a/.workbuddy/memory/2026-09-09.md b/.workbuddy/memory/2026-09-09.md index 8c736c1..95b4d95 100644 --- a/.workbuddy/memory/2026-09-09.md +++ b/.workbuddy/memory/2026-09-09.md @@ -103,6 +103,33 @@ - 注意:VO 继承 entity 无需改;Wrapper BeanUtil 同名透传。已上线库须执行 patch SQL(建表脚本是 DROP+CREATE,勿直接跑)。 - 后续补充(vehicle.vue「车辆资质图片」区输入框对齐):第一行原 span `6/8/10` 不等宽(行驶证档案编号 6 / 行驶证有效期 8 / 道路运输证号 10)导致输入框宽度不齐,统一改为 `8/8/8`,与下方各行 span=8 一致。仅改 2 处 span,无逻辑改动。 +## 车辆车牌号:改为单一 input 输入框(vehicle.vue,3 段 → 1 段) +- 需求:基础车辆信息区「车牌号」原本是「省简称 select + 号码 input + 车牌颜色 select」三段拼装(plateProvince/plateNoBody/plateColor),改为**单个 el-input** 直接输入完整车牌号(如 京A12345)。 +- 改动(vehicle.vue): + 1. 模板:`plate-group` 三段 → ``。删除 `.plate-group` 样式(含 focus-within、竖线分隔、child flex 占比等整段)。 + 2. emptyForm:删 `plateProvince`、`plateNoBody`,保留 `plateNo`、`plateColor`(后端字段继续存历史车牌颜色)。 + 3. data:删 `plateProvinceOptions`、`plateColorOptions` 暴露;常量 `plateProvinceOptions`(31 省简称数组)整段删除;`plateColorOptions` 常量删除。 + 4. validatePlateNo 重写:直接校验 `value`(完整车牌号),正则 `/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼港澳]{1}[A-Z][A-Z0-9挂学警港澳]{5,6}$/`,错误提示改为「请输入标准车牌号(如:京A12345)」。 + 5. syncPlateNo / splitPlateNo 重写:splitPlateNo 改为 noop(保留以兼容 OCR 后回调链路);syncPlateNo 改为 trim+upperCase 单一字段。 + 6. handlePlateBodyInput 改名为 handlePlateNoInput,新增 validatePlateFormat 失焦校验。 + 7. 车辆认证审核弹窗只读详情同步删「车牌颜色」展示(与录入表单一致)。 +- 后端不动:`plate_no` / `plate_color` 字段保留(数据库兼容历史车牌颜色),Service 无强制校验。 +- 受影响:OCR 自动识别(行驶证/机动车销售统一发票)后续调用链路无需改,因 syncPlateNo 仍对 plateNo 做归一化。 + +## 车辆新增/编辑弹窗:输入框宽度统一(vehicle.vue,前后两区) +- 需求(transportCapacity/vehicle):新增/编辑弹窗「基础车辆信息」+「车辆资质图片」两个 section 各输入框宽度要一致;截图红框重点为车牌号、外廓尺寸、所有组织/使用部门。 +- 根因:基础区原本列宽混乱(车牌号 span10 / 车辆类型 span6 / 外廓尺寸 span6,其余 span6),行内 3 列与 2 列混排;图片区文本字段全 span6,与基础区不一致。 +- 改动(vehicle.vue 仅模板 el-col span): + 1. 「基础车辆信息」区所有字段统一为 **span=8(3 列布局)**:车牌号、车辆类型、外廓尺寸、核定载质量、准牵引总质量、业务关系、能源类型、强制报废日期、海关备案号、所有组织、使用部门。 + 2. 「车辆资质图片」区文本/日期字段(行驶证档案编号、行驶证有效期、道路运输证号、道路运输证有效期、道路运输年审有效期、机动车登记编号、机动车登记日期)统一为 **span=8**。 +- 不改:只读「车辆认证审核」弹窗(L140 起的 span6 只读详情 + large 图片上传)与新增弹窗内「证件图片」上传控件(固定尺寸)保持 span6。外廓尺寸为复合控件(长/宽/高三 input),口径同 span8。 +- ⚠️ 注意:操作中曾误删核定载质量 el-col 标签(453-460 行开始时少 el-col、尾部多一个 ``),已修复为完整 `...`。 +- 后续纠偏(2026-09-09 傍晚):主人反馈「为什么不是按4列显示」——上一步把"基础车辆信息/车辆资质图片"两区误改成 3 列(span8)。同项目惯例 driver.vue/customer-archive.vue 全为 **4 列(span6,仅复合长字段 span12)**,故统一重排为 4 列: + - 基础车辆信息:`车牌号(6)+车辆类型(6)+外廓尺寸(12)` → `核定载质量/准牵引总质量/业务关系/能源类型(4×6)` → `强制报废日期/海关备案号/所有组织/使用部门(4×6)` + - 车辆资质图片:`行驶证有效期/道路运输证号/道路运输证有效期/道路运输年审有效期(4×6)` → `机动车登记编号/机动车登记日期/行驶证档案编号(3×6)`,图片上传控件仍 span6 + - 该区 span8 已全部移除,编辑表单区仅剩外廓尺寸 span12(复合控件长/宽/高)+ 图片上传 span6。 +- 宽度微调(2026-09-09 傍晚2):主人圈出「所有组织」字段宽度与同行不一致。根因:`.vehicle-form` 里的 `:deep(...){width:100%}` 选择器只列了 `el-select / el-input / el-input-number / el-date-editor`,**漏了 `el-cascader`**(所有组织用的就是级联选择器,默认不撑满整列)。已补 `:deep(.el-cascader)` 进该规则,全表单仅此一处用到 el-cascader,故所有组织与同行等宽。 + ## 司机弹窗:补 placeholder + 每行统一 3 列(transportCapacity/driver.vue) - 需求:新增/编辑司机弹窗 ①输入框无提示文案;②基础身份信息 3 列,其它 4 列 / 6 列行不统一。 - 改动(仅 1819 行 driver.vue 的 126-540 行 `` 模板,script/style 不动): @@ -112,3 +139,32 @@ 4. **司机联系信息**:一行 6 列拆为两行 — 行 1(司机类型 / 手机号 / 紧急联系人姓名,:span=8)+ 行 2(紧急联系人手机号 / 与联系人关系 / 所属组织,:span=8)。所属组织已有 placeholder,不动。 - 决策点(主人确认):1.B(保留原 date-range 二联 + 第三列留空后拆行的方案);2 保留;3.A(驾驶证主页/副页、封面页/内容页两组上传图仍 :span=12,与占整行宽的原貌一致)。 - 校验:node 脚本统计 4 个 section-card / 13 个 el-row / 31 个 el-col / 24 个 el-form-item,全平衡。改动只在 driver.vue 一文件,~25 处 Edit 调用。 + +## 新增/修改司机弹窗改为 4 列布局(driver.vue,16:xx) +- 主人要求 /transportCapacity/driver 新增司机弹窗改 4 列显示。原文件各分组已是 span=6(4 列栅格)但每行只放 3 个字段,第 4 列空置。 +- 重排结果(仅删行断 + 移动字段顺序,字段/校验/逻辑零改动): + 1. 基础身份信息:行1 司机姓名/身份证号/出生年月/性别;行2 民族/学历/住址/详细地址;行3 驾驶车辆/岗位;行4 三张证件照(不变)。 + 2. 驾驶证信息:行1 准驾车型/档案编号/有效期/长期有效;上传主页/副页 span 12→6。 + 3. 从业资格证信息:行1 类型/资格证号/有效期/长期有效;上传封面页/内容页 span 12→6。 + 4. 司机联系信息:行1 司机类型/手机号/紧急联系人姓名/紧急联系人手机号;行2 与联系人关系/所属组织。 +- 注意:此前日志记录的「3 列 span=8」方案已被后续改动覆盖为 span=6,本次以当前文件实际状态为准。 + +## 客商档案:客商类型→客商分类 + 新增客商类型(customer-archive.vue) +- 需求:原「客商类型」(prop `customerType`,字典 customer_type:客户/承运商,多选)改名「客商分类」;另新增「客商类型」字段,取值为 外部客商 / 内部组织。 +- 约定:prop `customerType` 不动(其它页面 loading-manage / dept / business-crud-page 都以 `customerType:'承运商'` 作为后端查询参数),只改中文标签。 +- 新增字段 prop = **`customerKind`**(前端自定义命名,后端尚无对应字段,需后端在客商表加列并透传),值 `external`(外部客商) / `internal`(内部组织),单选下拉,默认 `external`。 +- 改动点(8 处,全在 `src/views/vehicle/customer-archive.vue`): + 1. 表单:227 行 label 改「客商分类」;其后新增一个 `el-col :span="6"` 表单项「客商类型」prop `customerKind`(el-select + `customerKindOptions`)。 + 2. data 新增 `customerKindOptions` / `customerKindMap`(external/internal ↔ 中文)。 + 3. formRules:`customerType` 提示文案改「请选择客商分类」。 + 4. 列表列:「客户类型」label 改「客商分类」;新增「客商类型」列(prop customerKind,type select,dicData 内外部,minWidth 120,**未加 search**)。 + 5. `emptyArchive()` 加 `customerKind: 'external'`。 + 6. `normalizeDetail()` 加 `customerKind: detail.customerKind || 'external'`。 + 7. 变更记录 `getChangeFieldLabel`:`customerType:'客商分类'`,新增 `customerKind:'客商类型'`。 + 8. `formatChangeFieldValue`:别名映射加 `客商分类/客户类型 → customerType`、`客商类型 → customerKind`;valueMap 加 `customerKind:{external:'外部客商',internal:'内部组织'}`。 +- 校验:用 @vue/compiler-sfc 编译模板,0 错误。 + +## 上传证件项 label 贴顶修复(全局 archive-form 垂直居中提升) +- 症状:driver.vue 司机弹窗「驾驶证主页/副页」「封面页/内容页」等证件上传项(el-form-item 内容高 151px)label 文字贴顶,普通 32px 控件行看不出来。 +- 根因:`archive-form` class 被 driver / vehicle / ship / credit-score-quantification / loading-manage / waybill-import-dialog 等 8+ 页面复用,但「label 与控件垂直居中」规则 `.archive-form :deep(.el-form-item){align-items:center}` 锁在 customer-archive.vue 的 scoped 样式里,其它页面拿不到;flex 容器默认 stretch,label(32px) 在高控件行内贴顶。 +- 修复:规则提升到 `src/styles/element-ui.scss` 全局(紧跟 is-required 星号配套规则之后):`.archive-form .el-form-item { align-items:center }`。全站 archive-form 表单一并生效,label 与控件垂直居中。SCSS 编译通过。 diff --git a/src/styles/element-ui.scss b/src/styles/element-ui.scss index b40123f..61bfe89 100644 --- a/src/styles/element-ui.scss +++ b/src/styles/element-ui.scss @@ -1085,6 +1085,14 @@ td.el-table-fixed-column--right { line-height: inherit; margin-right: 4px; } + +// ============ archive-form:label 与控件垂直居中(全站复用) ============ +// archive-form class 被 driver / vehicle / ship / credit-score-quantification / loading-manage 等 +// 多个页面复用,但「垂直居中」规则原本锁在 customer-archive.vue 的 scoped 样式里, +// 其它页面拿不到 → 高控件行(证件上传 151px)label 贴顶。提升为全局统一生效。 +.archive-form .el-form-item { + align-items: center; +} //.el-form-item { // margin-bottom: 15px !important; //} diff --git a/src/views/transportCapacity/driver.vue b/src/views/transportCapacity/driver.vue index 9f9e9a7..11fce48 100644 --- a/src/views/transportCapacity/driver.vue +++ b/src/views/transportCapacity/driver.vue @@ -156,8 +156,6 @@ /> - - @@ -195,8 +193,6 @@ - - - + @@ -321,7 +317,7 @@ /> - +
- - - + - + - + - - - + - + - - {{ auditValue('plateNo') }} - - - {{ auditValue('plateColor') }} - - {{ auditValue('vehicleType') }} @@ -394,7 +389,7 @@ > - + - +
@@ -460,6 +455,7 @@ @@ -469,6 +465,7 @@ @@ -485,8 +482,6 @@ - - + +
@@ -529,8 +526,6 @@ - - - - - - -
@@ -595,8 +585,6 @@ - -
@@ -653,6 +641,11 @@ /> + + + + + @@ -1402,9 +1395,13 @@ export default { ); return option ? option.value : vehicleType; }, - handlePlateBodyInput(value) { - this.vehicleForm.plateNoBody = String(value || '').toUpperCase(); - this.syncPlateNo(); + handlePlateNoInput(value) { + this.vehicleForm.plateNo = String(value || '') + .replace(/\s/g, '') + .toUpperCase(); + }, + validatePlateFormat() { + this.$refs.vehicleForm?.validateField('plateNo'); }, syncPlateNo(validate = true) { const plateNo = String(this.vehicleForm.plateNo || '') @@ -1651,67 +1648,11 @@ export default { :deep(.el-date-editor.el-input__wrapper), :deep(.el-select), :deep(.el-input), - :deep(.el-input-number) { + :deep(.el-input-number), + :deep(.el-cascader) { width: 100%; } - .plate-group { - display: flex; - align-items: center; - overflow: hidden; - border: 1px solid #dcdfe6; - border-radius: 4px; - background: #fff; - transition: border-color 0.2s; - - &:hover { - border-color: #c0c4cc; - } - - &:focus-within { - border-color: #409eff; - } - - // 三个子控件:去掉各自边框,整体形成一个输入框 - :deep(.el-select), - :deep(.el-input) { - position: relative; - flex: 1; - min-width: 0; - height: 32px; - } - - :deep(.el-select:first-child) { - flex: 0 0 12%; - } - - :deep(.el-select:last-child) { - flex: 0 0 18%; - } - - :deep(.el-input__wrapper), - :deep(.el-select__wrapper) { - box-shadow: none !important; - border-radius: 0; - padding: 0 8px; - } - - // 子项之间用竖线分隔,视觉上是一个整体 - :deep(.el-select + .el-select), - :deep(.el-select + .el-input), - :deep(.el-input + .el-select) { - &::before { - content: ''; - position: absolute; - left: 0; - top: 6px; - bottom: 6px; - width: 1px; - background: #e4e7ed; - } - } - } - .dimension-group { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); diff --git a/src/views/vehicle/customer-archive.vue b/src/views/vehicle/customer-archive.vue index 12061bf..b821cec 100644 --- a/src/views/vehicle/customer-archive.vue +++ b/src/views/vehicle/customer-archive.vue @@ -224,7 +224,7 @@ - + + + + + + + + @@ -1660,7 +1677,7 @@ export default { trigger: 'blur', }, ], - customerType: [{ required: true, message: '请选择客商类型', trigger: 'change' }], + customerType: [{ required: true, message: '请选择客商分类', trigger: 'change' }], legalPerson: [{ required: true, message: '请输入企业法人', trigger: 'blur' }], contactPhone: [ { required: true, message: '请输入联系电话', trigger: 'blur' }, @@ -1767,7 +1784,7 @@ export default { overHidden: true, }, { - label: '客户类型', + label: '客商分类', prop: 'customerType', search: true, searchType: 'select', @@ -1777,6 +1794,16 @@ export default { minWidth: 140, dicData: [{ label: '全部', value: '' }], }, + { + label: '客商类型', + prop: 'customerKind', + type: 'select', + minWidth: 120, + dicData: [ + { label: '外部客商', value: 'external' }, + { label: '内部组织', value: 'internal' }, + ], + }, { label: '客户性质', prop: 'customerNature', @@ -2188,7 +2215,8 @@ export default { customerCode: '客商编号', shortName: '客商简称', fullName: '客商名称', - customerType: '客户类型', + customerType: '客商分类', + customerKind: '客商类型', customerNature: '客户性质', unifiedCreditCode: '统一信用代码', deptName: '所属组织', @@ -2376,6 +2404,7 @@ export default { rejected: '审核不通过', }, status: { 1: '启用', 2: '停用', 0: '停用' }, + customerKind: { external: '外部客商', internal: '内部组织' }, }; if (Array.isArray(value)) { return value.map(item => this.formatChangeFieldValue(normalizedField, item)).join('、'); @@ -3661,6 +3690,7 @@ export default { ...detail, deptId: this.normalizeDeptIds(detail), customerType: this.splitValue(detail.customerType), + customerKind: detail.customerKind || 'external', invoiceTaxRate: this.normalizeOptionalAmount(detail.invoiceTaxRate), registeredCapital: this.normalizeOptionalAmount(detail.registeredCapital), maxCreditLimit: this.normalizeOptionalAmount(detail.maxCreditLimit), From 716ce438623ea2dc45ea14da62bf1a2bc4e8dec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Wed, 9 Sep 2026 17:35:19 +0800 Subject: [PATCH 4/6] =?UTF-8?q?feat(driver):=20=E4=BC=98=E5=8C=96=E9=A9=BE?= =?UTF-8?q?=E9=A9=B6=E8=AF=81=E4=BF=A1=E6=81=AF=E5=BF=85=E5=A1=AB=E8=A7=84?= =?UTF-8?q?=E5=88=99=E5=92=8C=E8=A1=A8=E5=8D=95placeholder=E7=BB=9F?= =?UTF-8?q?=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 驾驶证有效期必填加红星,长期有效去除必填红星,保持校验逻辑不变 - 统一司机弹窗所有输入框和选择框的placeholder为“请输入”或“请选择”,去除字段名 - 保留复合操作、日期范围起止及默认值说明的特例placeholder不变 - 新增3处自动生成结算单开关后悬浮问号图标和提示,增强用户理解 - customer-archive中新增customerKindOptions和映射,用于客户类别选择 - 提升archive-form label与控件垂直居中样式至全局,修正多页标签顶置问题 --- .workbuddy/memory/2026-09-09.md | 35 ++++++++++++++++ .workbuddy/memory/MEMORY.md | 11 +++++ .../components/business-crud-page.vue | 13 ++++++ src/views/business/contract-manage-change.vue | 12 +++++- src/views/business/contract-manage.vue | 13 ++++++ src/views/transportCapacity/driver.vue | 41 +++++++++---------- src/views/vehicle/customer-archive.vue | 8 ++++ 7 files changed, 110 insertions(+), 23 deletions(-) diff --git a/.workbuddy/memory/2026-09-09.md b/.workbuddy/memory/2026-09-09.md index 95b4d95..c45e331 100644 --- a/.workbuddy/memory/2026-09-09.md +++ b/.workbuddy/memory/2026-09-09.md @@ -150,6 +150,7 @@ - 注意:此前日志记录的「3 列 span=8」方案已被后续改动覆盖为 span=6,本次以当前文件实际状态为准。 ## 客商档案:客商类型→客商分类 + 新增客商类型(customer-archive.vue) +- ⚠️ 补救(17:34):data 里的 `customerKindOptions`/`customerKindMap` 定义一度丢失(模板 v-for 空 → 下拉显示「无数据」,主人截图反馈),已补回 data(customerTypeOptions 之后)。其余 8 处改动经 grep 确认完好。 - 需求:原「客商类型」(prop `customerType`,字典 customer_type:客户/承运商,多选)改名「客商分类」;另新增「客商类型」字段,取值为 外部客商 / 内部组织。 - 约定:prop `customerType` 不动(其它页面 loading-manage / dept / business-crud-page 都以 `customerType:'承运商'` 作为后端查询参数),只改中文标签。 - 新增字段 prop = **`customerKind`**(前端自定义命名,后端尚无对应字段,需后端在客商表加列并透传),值 `external`(外部客商) / `internal`(内部组织),单选下拉,默认 `external`。 @@ -168,3 +169,37 @@ - 症状:driver.vue 司机弹窗「驾驶证主页/副页」「封面页/内容页」等证件上传项(el-form-item 内容高 151px)label 文字贴顶,普通 32px 控件行看不出来。 - 根因:`archive-form` class 被 driver / vehicle / ship / credit-score-quantification / loading-manage / waybill-import-dialog 等 8+ 页面复用,但「label 与控件垂直居中」规则 `.archive-form :deep(.el-form-item){align-items:center}` 锁在 customer-archive.vue 的 scoped 样式里,其它页面拿不到;flex 容器默认 stretch,label(32px) 在高控件行内贴顶。 - 修复:规则提升到 `src/styles/element-ui.scss` 全局(紧跟 is-required 星号配套规则之后):`.archive-form .el-form-item { align-items:center }`。全站 archive-form 表单一并生效,label 与控件垂直居中。SCSS 编译通过。 + +## 司机弹窗「驾驶证信息」:有效期必填、长期有效不必填(transportCapacity/driver.vue) +- 需求:驾驶证信息区「有效期」(起/止,prop `drivingLicenseEndDate`)要必填(显示红*),「长期有效」复选框(prop `drivingLicenseLongTerm`)不必填(去掉红*)。 +- 改动(formRules 两处): + 1. `drivingLicenseEndDate` 规则加 `required: true`(`{ required: true, validator: this.validateDrivingLicenseEndDate, trigger: 'change' }`)——仅用于渲染红*,实际校验仍走自定义 validator。 + 2. 删除 `drivingLicenseLongTerm` 的 `{ required: true, message: '请选择驾驶证是否长期有效' }` 规则块。 +- 关键机制(Element Plus 2.14 + async-validator 4.2.5 已核实): + - 红* 由 `form-item` 的 `isRequired = normalizedRules.some(rule => rule.required)` 决定,只要规则对象带 `required` 就显示。 + - async-validator 的 `rule.validate` 中,若存在 `rule.validator`,直接走自定义 validator 并 return,**不会**再执行 required 空值检查 → 勾「长期有效」时止日被清空/disabled 也不会误报必填。 + - 校验逻辑保持原样:起始日期恒必填;`longTerm !== 1` 时止日必填。 +- 未同步:「从业资格证信息」区仍是「有效期无红* + 长期有效有红*」的旧形态(待主人确认是否一并统一)。 + +## 司机弹窗 placeholder 统一为「请输入/请选择」(transportCapacity/driver.vue) +- 需求:新增/修改司机弹窗输入框 placeholder 去掉后面的字段名称,只保留「请输入」「请选择」。 +- 改动:18 处 placeholder 简化(7 处 → `请输入`,10 处 → `请选择`,1 处动态 cascader `driverForm.addressRegion || '请选择省市区'` → `|| '请选择'`)。 +- **保留 4 处**(主人明确确认): + 1. 驾驶车辆 `请输入或选择车辆` —— 复合操作(既可输入又可点按钮选车),去掉会丢语义。 + 2. 日期范围 `起` / `止` —— 起止标记,非字段提示。 + 3. 资格证号 `默认身份证号` —— 默认值说明,非「请输入」格式。 +- 未动:表单**校验错误提示 message 仍带字段名**(如「请选择准驾车型」),因报错需指明具体字段,与 placeholder 定位不同;主人未要求,暂保持。 +- 做法:Python 脚本按完整 placeholder 字符串精确替换(18 规则全命中,未匹配即 exit 1 中断),比逐个 Edit 高效且不会误伤。 +- 校验:`@vue/compiler-sfc` parse + compileTemplate + compileScript 三项全通过。注意脚本必须放在**项目根目录**下运行(放 /tmp 解析不到 node_modules 里的 @vue/compiler-sfc)。 +- ⚠️ git diff 显示的 `drivingLicenseLongTerm` 校验规则变动是**本次之前工作区已有的未提交改动**(见上一条日志),非本次引入,勿混淆。 + +## 「自动生成结算单」开关加 ? 悬浮提示(3 处) +- 需求:开关「开启」后面加问号图标,hover 提示「开启时,系统根据配置规则归集运单,定时生成结算单」。 +- 改动文件(同一文案,为保持全站一致): + 1. `src/views/business/components/business-crud-page.vue`(1884 行附近,`.business-crud-page__settlement-switch`) + 2. `src/views/business/contract-manage.vue`(357 行附近,`.contract-manage-form__settlement-switch`) + 3. `src/views/business/contract-manage-change.vue`(55 行,`.settlement-switch`,原为单行长标签已拆行) +- 写法:`开启` 后插 ``,再接「关闭」radio。 +- 样式:`.settlement-switch-tip { margin:0 4px; color:#a8abb2; cursor:help; font-size:14px }`,各文件 scoped 样式内一份(contract-manage 写在 `&__settlement-switch` 内)。 +- 注意:图标走 main.js 全局注册(@element-plus/icons-vue 全量注册),无需 import;写法与 `project-apply.vue` 的 `__label-tip` 一致。 +- 这三个大文件本身已存在 prettier 格式问题(改动前 git HEAD 版本同样 fail),非本次引入。 diff --git a/.workbuddy/memory/MEMORY.md b/.workbuddy/memory/MEMORY.md index ce2389b..be1c62d 100644 --- a/.workbuddy/memory/MEMORY.md +++ b/.workbuddy/memory/MEMORY.md @@ -2,6 +2,17 @@ ## 设计约定(已确认) +### 表单 placeholder 统一为「请输入 / 请选择」(不带字段名) +- **规范**:输入框 placeholder 只写动作词 `请输入` / `请选择`,**后面不跟字段名称**(label 已说明是什么字段,重复无意义)。 +- 已生效页面:waybill-manage、transport-plan、shipping-template、temporary-credit-limit(搜索栏 + 弹窗表单)、**driver.vue**(2026-09-09 补齐 18 处)。 +- **3 类例外必须保留,不要误简化**: + 1. 复合操作:如 `请输入或选择车辆`(既可键盘输入又可点按钮弹窗选车),丢掉会损失语义。 + 2. 日期区间的 `起` / `止`:是起止标记,不是字段提示。 + 3. 默认值说明:如资格证号 `默认身份证号`、车牌号 `如:京A12345`,属于示例/默认值提示,非「请输入」格式。 +- **校验错误提示 message 保持带字段名**(如「请选择准驾车型」「请输入档案编号」),与 placeholder 定位不同——报错必须指明具体哪个字段,不能只说「请选择」。 +- Avue 配置化表单:在 option 各列加 `placeholder`;搜索栏可用通用工具 `withSearchPlaceholders([...])`(见 temporary-credit-limit.js)。 +- 批量改法:Python 脚本按**完整 placeholder 字符串**做精确替换,每规则校验 `count > 0` 否则中断,避免误伤;改完用 `@vue/compiler-sfc` 的 parse + compileTemplate + compileScript 验证(脚本须放项目根目录下跑,放 /tmp 解析不到 node_modules)。 + ### 弹窗分组:统一用全局 `` - 弹窗 body 背景由 `src/styles/element-ui.scss` 全局 `.el-dialog__body { background:#f5f6fa; padding:16px }` 统一灰底。 - 每组 = 白底卡片:4px 主色竖条 + 8px 间距 + 圆角 6px + 淡阴影。组件全局注册 ``,支持 `#title` / `#extra` slot。 diff --git a/src/views/business/components/business-crud-page.vue b/src/views/business/components/business-crud-page.vue index d56a38e..f237a35 100644 --- a/src/views/business/components/business-crud-page.vue +++ b/src/views/business/components/business-crud-page.vue @@ -1883,6 +1883,12 @@ 自动生成结算单 开启 + + + 关闭
@@ -14453,6 +14459,13 @@ export default { color: #303133; } + .settlement-switch-tip { + margin: 0 4px; + color: #a8abb2; + cursor: help; + font-size: 14px; + } + &__module-form { width: 100%; diff --git a/src/views/business/contract-manage-change.vue b/src/views/business/contract-manage-change.vue index 612a872..6e57471 100644 --- a/src/views/business/contract-manage-change.vue +++ b/src/views/business/contract-manage-change.vue @@ -52,7 +52,16 @@ -
自动生成结算单开启关闭
+
+ 自动生成结算单 + + 开启 + + + + 关闭 + +
@@ -211,6 +220,7 @@ export default { .attachment-upload .vehicle-attachment-upload { width: auto; } .attachment-upload .el-upload { display: inline-flex; } .settlement-switch { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; } +.settlement-switch-tip { margin: 0 4px; color: #a8abb2; cursor: help; font-size: 14px; } .settlement-form { display: grid; grid-template-columns: repeat(3, minmax(240px, 1fr)); gap: 8px 28px; } .change-reason-section { margin: 20px 0; } .page-footer { diff --git a/src/views/business/contract-manage.vue b/src/views/business/contract-manage.vue index 6fc60f8..c8fc9fd 100644 --- a/src/views/business/contract-manage.vue +++ b/src/views/business/contract-manage.vue @@ -356,6 +356,12 @@ 自动生成结算单 开启 + + + 关闭
@@ -2758,6 +2764,13 @@ export default { align-items: center; gap: 20px; margin-bottom: 16px; + + .settlement-switch-tip { + margin: 0 4px; + color: #a8abb2; + cursor: help; + font-size: 14px; + } } &__settlement-grid { diff --git a/src/views/transportCapacity/driver.vue b/src/views/transportCapacity/driver.vue index 11fce48..cc21b73 100644 --- a/src/views/transportCapacity/driver.vue +++ b/src/views/transportCapacity/driver.vue @@ -131,7 +131,7 @@ v-model="driverForm.driverName" maxlength="10" show-word-limit - placeholder="请输入司机姓名" + placeholder="请输入" />
@@ -141,7 +141,7 @@ v-model="driverForm.idCardNo" maxlength="18" show-word-limit - placeholder="请输入身份证号" + placeholder="请输入" @input="driverForm.idCardNo = String(driverForm.idCardNo || '').toUpperCase()" />
@@ -152,13 +152,13 @@ v-model="driverForm.birthday" type="date" value-format="YYYY-MM-DD" - placeholder="请选择出生年月" + placeholder="请选择" />
- + @@ -166,7 +166,7 @@ - + @@ -297,7 +297,7 @@ filterable allow-create default-first-option - placeholder="请选择准驾车型" + placeholder="请选择" > @@ -389,7 +389,7 @@ v-model="driverForm.qualificationType" clearable filterable - placeholder="请选择从业资格认证类型" + placeholder="请选择" > @@ -464,7 +464,7 @@ - + @@ -476,7 +476,7 @@ @@ -485,7 +485,7 @@ @@ -495,7 +495,7 @@ @@ -507,7 +507,7 @@ filterable allow-create default-first-option - placeholder="请选择与联系人关系" + placeholder="请选择" > @@ -813,10 +813,7 @@ export default { drivingType: [{ required: true, message: '请选择准驾车型', trigger: 'change' }], drivingLicenseNo: [{ required: true, message: '请输入档案编号', trigger: 'blur' }], drivingLicenseEndDate: [ - { validator: this.validateDrivingLicenseEndDate, trigger: 'change' }, - ], - drivingLicenseLongTerm: [ - { required: true, message: '请选择驾驶证是否长期有效', trigger: 'change' }, + { required: true, validator: this.validateDrivingLicenseEndDate, trigger: 'change' }, ], qualificationType: [ { required: true, message: '请选择从业资格认证类型', trigger: 'change' }, diff --git a/src/views/vehicle/customer-archive.vue b/src/views/vehicle/customer-archive.vue index b821cec..1fbd0f8 100644 --- a/src/views/vehicle/customer-archive.vue +++ b/src/views/vehicle/customer-archive.vue @@ -1645,6 +1645,14 @@ export default { regionOptions: [], customerNatureOptions: [], customerTypeOptions: [], + customerKindOptions: [ + { label: '外部客商', value: 'external' }, + { label: '内部组织', value: 'internal' }, + ], + customerKindMap: { + external: '外部客商', + internal: '内部组织', + }, businessScopeOptions: [], qualificationTypeOptions: [], creditLevelOptions: ['A', 'B', 'C', 'D', 'E', 'F'].map(item => ({ From c1813e308f417df1154c8d7b49e94a73cbabb837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Wed, 9 Sep 2026 19:06:26 +0800 Subject: [PATCH 5/6] =?UTF-8?q?feat(vehicle):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E8=BD=A6=E8=BE=86=E8=AE=A4=E8=AF=81=E5=AE=A1=E6=A0=B8=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=E5=B8=83=E5=B1=80=E4=B8=8E=E9=AA=8C=E8=AF=81=E8=A7=84?= =?UTF-8?q?=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增车辆认证审核弹窗,取消独立尺寸重量卡片,外廓尺寸改为长/宽/高组合布局 - 基础信息调整为3行4列,证件信息新增车辆资质图片行,所属组织标签更名为所有组织 - 行驶证有效期必填星号动态显示,长期有效时不显示且不校验,删除旧校验方法 - driver.vue中从业资格证有效期改为起止日期区间,新增起始日期字段,调整验证规则 - 驾驶证和从业资格证长期有效时禁用起止日期输入,校验逻辑同步调整,提交保留旧值 - contract-manage-change.vue合同文件批量下载按钮移入标题栏,与其它附件分区样式统一 - 样式更新,新增 dimension-group 用于外廓尺寸排版复用及其他局部样式调整 - 修复因后端未实现接口导致的降级方案预留,等待后端补充支持 --- .workbuddy/memory/2026-09-09.md | 9 + src/views/business/contract-manage-change.vue | 5 +- src/views/transportCapacity/driver.vue | 58 +++-- src/views/transportCapacity/vehicle.vue | 223 ++++++++++-------- 4 files changed, 173 insertions(+), 122 deletions(-) diff --git a/.workbuddy/memory/2026-09-09.md b/.workbuddy/memory/2026-09-09.md index c45e331..152dc68 100644 --- a/.workbuddy/memory/2026-09-09.md +++ b/.workbuddy/memory/2026-09-09.md @@ -203,3 +203,12 @@ - 样式:`.settlement-switch-tip { margin:0 4px; color:#a8abb2; cursor:help; font-size:14px }`,各文件 scoped 样式内一份(contract-manage 写在 `&__settlement-switch` 内)。 - 注意:图标走 main.js 全局注册(@element-plus/icons-vue 全量注册),无需 import;写法与 `project-apply.vue` 的 `__label-tip` 一致。 - 这三个大文件本身已存在 prettier 格式问题(改动前 git HEAD 版本同样 fail),非本次引入。 + +## 车辆认证审核弹窗排版对齐新增弹窗(vehicle.vue) +- 诊断 `/project-apply/fund-risk-stats` No endpoint:前端已定义 getFundRiskStats(api/business/project-apply.js:13),后端未实现;方案已给(后端补 R<{high,medium}> / 前端 catch 降级),待主人选。 +- vehicle.vue 认证审核弹窗重排对齐新增弹窗:取消独立「尺寸重量」卡片,外廓尺寸改长/宽/高组合(span12,dimension-group);基础信息 3 行×4 列(车牌号/车辆类型/外廓尺寸;载质量/牵引质量/业务关系/能源类型;强制报废日期/海关备案号/所有组织/使用部门);证件信息按新增「车辆资质图片」行分布(止+运输证号+止+年审 / 登记编号+登记日期+档案编号+行驶证起 / 运输证起 / 备注整行);label「所属组织」改「所有组织」对齐新增;dimension-group 样式复制进 .certification-audit 作用域。@vue/compiler-sfc 编译校验通过。 +- vehicle.vue 行驶证有效期必填星号:原规则是纯 validator(Element Plus 不渲染星号),改为 data 内 baseRules + computed formRules,drivingLicenseEndDate 动态返回 required 规则(长期有效=1 时返回 [],星号与校验同步消失);删除 validateDrivingLicenseEndDate。经验:Element Plus 星号只在规则含 required:true 时渲染,且 el-form-item 的 :required 属性会被注入为 {required} 规则并产生英文默认提示,不宜用它控制星号。 +- 备注:车辆保存的「车牌颜色不能为空」「行驶证有效期:必填」均为后端校验(前端无对应规则),需后端改。 +- driver.vue 从业资格证有效期对齐驾驶证:单日期改 date-range 起/止(列宽 6+6+6+6 → 6+6+8+4),新增 qualificationStartDate 字段(emptyForm + handleSubmit normalize);qualificationEndDate 规则加 required:true(渲染星号,validator 豁免长期);删除 qualificationLongTerm 的 required 规则(长期有效不必填);勾长期后起止均 disabled(比驾驶证更严,驾驶证起仍可编辑)。⚠️ 后端需新增 qualification_start_date 字段否则起日期无法存取。 +- driver.vue 补充:驾驶证「有效期起」加 :disabled(长期=1 时禁用);驾驶证与从业资格证两个 validator 统一在「长期有效=1」时直接 callback() 放行(起止都不校验、不提示)。禁用不清空旧值,提交时保留原日期(后端以 longTerm 为准)。 +- contract-manage-change.vue「合同文件」批量下载按钮上移:标题与按钮合并进 .section-head(flex space-between 同排),与「其它附件/计费信息」分区一致;删除无引用的 .attachment-head 样式。 diff --git a/src/views/business/contract-manage-change.vue b/src/views/business/contract-manage-change.vue index 6e57471..5360a4d 100644 --- a/src/views/business/contract-manage-change.vue +++ b/src/views/business/contract-manage-change.vue @@ -30,8 +30,8 @@
-
合同文件
-
+
+
合同文件
批量下载
@@ -215,7 +215,6 @@ export default { .change-table { margin: 16px 0; } .ratio-tip { margin-bottom: 8px; color: #f56c6c; } .unit { margin-left: 8px; } -.attachment-head { display: flex; align-items: center; justify-content: flex-end; margin-bottom: 12px; } .attachment-upload { display: flex; justify-content: flex-start; margin-top: 12px; } .attachment-upload .vehicle-attachment-upload { width: auto; } .attachment-upload .el-upload { display: inline-flex; } diff --git a/src/views/transportCapacity/driver.vue b/src/views/transportCapacity/driver.vue index cc21b73..40389ee 100644 --- a/src/views/transportCapacity/driver.vue +++ b/src/views/transportCapacity/driver.vue @@ -325,6 +325,7 @@ type="date" value-format="YYYY-MM-DD" placeholder="起" + :disabled="driverForm.drivingLicenseLongTerm === 1" @change="validateFormField('drivingLicenseEndDate')" /> - + - +
+ + +
- + ({ drivingLicenseBack: '', qualificationType: '', qualificationNo: '', + qualificationStartDate: '', qualificationEndDate: '', qualificationLongTerm: 0, qualificationFront: '', @@ -819,9 +831,8 @@ export default { { required: true, message: '请选择从业资格认证类型', trigger: 'change' }, ], qualificationNo: [{ required: true, message: '请输入资格证号', trigger: 'blur' }], - qualificationEndDate: [{ validator: this.validateQualificationEndDate, trigger: 'change' }], - qualificationLongTerm: [ - { required: true, message: '请选择从业资格证是否长期有效', trigger: 'change' }, + qualificationEndDate: [ + { required: true, validator: this.validateQualificationEndDate, trigger: 'change' }, ], driverType: [{ required: true, message: '请选择司机类型', trigger: 'change' }], mobile: [{ required: true, message: '请输入手机号', trigger: 'blur' }], @@ -1056,19 +1067,33 @@ export default { } }, validateDrivingLicenseEndDate(rule, value, callback) { + // 勾选长期有效:起止均已禁用,不再校验 + if (this.driverForm.drivingLicenseLongTerm === 1) { + callback(); + return; + } if (!this.driverForm.drivingLicenseStartDate) { callback(new Error('请选择驾驶证有效期起')); return; } - if (this.driverForm.drivingLicenseLongTerm !== 1 && !value) { + if (!value) { callback(new Error('请选择驾驶证有效期止')); return; } callback(); }, validateQualificationEndDate(rule, value, callback) { - if (this.driverForm.qualificationLongTerm !== 1 && !value) { - callback(new Error('请选择从业资格证有效期')); + // 勾选长期有效:起止均已禁用,不再校验 + if (this.driverForm.qualificationLongTerm === 1) { + callback(); + return; + } + if (!this.driverForm.qualificationStartDate) { + callback(new Error('请选择从业资格证有效期起')); + return; + } + if (!value) { + callback(new Error('请选择从业资格证有效期止')); return; } callback(); @@ -1580,6 +1605,7 @@ export default { birthday: this.normalizeBirthday(this.driverForm.birthday), drivingLicenseStartDate: this.normalizeBirthday(this.driverForm.drivingLicenseStartDate), drivingLicenseEndDate: this.normalizeBirthday(this.driverForm.drivingLicenseEndDate), + qualificationStartDate: this.normalizeBirthday(this.driverForm.qualificationStartDate), qualificationEndDate: this.normalizeBirthday(this.driverForm.qualificationEndDate), qualificationNo: this.driverForm.qualificationNo || this.driverForm.idCardNo, posts: this.driverForm.postList.join(','), diff --git a/src/views/transportCapacity/vehicle.vue b/src/views/transportCapacity/vehicle.vue index 751f7a8..f4cd7d5 100644 --- a/src/views/transportCapacity/vehicle.vue +++ b/src/views/transportCapacity/vehicle.vue @@ -129,13 +129,6 @@ > - - - - {{ auditValue('organizationName') }} - - - @@ -147,43 +140,22 @@ {{ auditValue('vehicleType') }} - - - - - {{ auditValue('businessRelation') }} - - - - - {{ auditValue('energyType') }} - - - - - - {{ auditValue('compulsoryScrapDate') }} - - - - - - - - - - - {{ auditValue('outerLength') }} - - - - - {{ auditValue('outerWidth') }} - - - - - {{ auditValue('outerHeight') }} + + +
+
+ + {{ auditValue('outerLength') }} +
+
+ + {{ auditValue('outerWidth') }} +
+
+ + {{ auditValue('outerHeight') }} +
+
@@ -198,14 +170,85 @@ {{ auditValue('tractionMassKg') }}
+ + + {{ auditValue('businessRelation') }} + + + + + {{ auditValue('energyType') }} + + + + + + + + {{ auditValue('compulsoryScrapDate') }} + + + + + + {{ auditValue('customsRecordNo') }} + + + + + + {{ auditValue('organizationName') }} + + + + + + {{ auditValue('useDepartment') }} + + - - {{ auditValue('customsRecordNo') }} + + + {{ auditValue('drivingLicenseEndDate') }} + + + + + + + {{ auditValue('roadTransportCertNo') }} + + + + + + + {{ auditValue('roadTransportCertEndDate') }} + + + + + + + {{ auditValue('annualReviewEndDate') }} + + + + + + + + {{ auditValue('registrationNo') }} + + + + + {{ auditValue('registrationDate') }} @@ -222,20 +265,6 @@ - - - - {{ auditValue('drivingLicenseEndDate') }} - - - - - - - {{ auditValue('roadTransportCertNo') }} - - - @@ -244,34 +273,6 @@ - - - - - {{ auditValue('roadTransportCertEndDate') }} - - - - - - - {{ auditValue('annualReviewEndDate') }} - - - - - - {{ auditValue('registrationNo') }} - - - - - - - {{ auditValue('registrationDate') }} - - - @@ -866,7 +867,7 @@ export default { ], businessRelationOptions: ['自有', '管理挂靠', '业务合作'], energyTypeOptions: ['柴油', '汽油', '新能源', '天然气'], - formRules: { + baseRules: { organizationName: [{ required: true, message: '请选择所属组织', trigger: 'change' }], plateNo: [ { required: true, message: '请输入车牌号', trigger: 'change' }, @@ -877,9 +878,6 @@ export default { businessRelation: [{ required: true, message: '请选择业务关系', trigger: 'change' }], energyType: [{ required: true, message: '请选择能源类型', trigger: 'change' }], drivingLicenseNo: [{ required: true, message: '请输入行驶证档案编号', trigger: 'blur' }], - drivingLicenseEndDate: [ - { validator: this.validateDrivingLicenseEndDate, trigger: 'change' }, - ], roadTransportCertNo: [{ required: true, message: '请输入道路运输证号', trigger: 'blur' }], roadTransportCertEndDate: [ { validator: this.validateRoadTransportCertEndDate, trigger: 'change' }, @@ -891,6 +889,16 @@ export default { }, computed: { ...mapGetters(['permission', 'userInfo']), + // 行驶证有效期:用 required 规则渲染必填星号;勾选「长期有效」后免填,星号同步消失 + formRules() { + return { + ...this.baseRules, + drivingLicenseEndDate: + this.vehicleForm.drivingLicenseLongTerm === 1 + ? [] + : [{ required: true, message: '请选择行驶证有效期', trigger: 'change' }], + }; + }, // 所属组织级联:表单存组织名称,级联控件用 id 路径,两者在此双向转换 organizationCascaderValue: { get() { @@ -1001,17 +1009,6 @@ export default { } this.$refs.vehicleForm?.validateField(dateProp); }, - validateDrivingLicenseEndDate(rule, value, callback) { - if (this.vehicleForm.drivingLicenseLongTerm === 1 && !value) { - callback(); - return; - } - if (!value) { - callback(new Error('请选择行驶证有效期')); - return; - } - callback(); - }, validateRoadTransportCertEndDate(rule, value, callback) { if (this.vehicleForm.roadTransportCertLongTerm === 1 && !value) { callback(); @@ -1638,6 +1635,26 @@ export default { word-break: break-all; } + // 外廓尺寸长/宽/高组合,排版复用编辑弹窗的 dimension-group + .dimension-group { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 8px; + align-items: center; + } + + .dimension-group__item { + display: flex; + align-items: center; + gap: 8px; + min-width: 0; + } + + .dimension-group__label { + flex-shrink: 0; + color: #303133; + } + &__reason { margin-top: 12px; } From 1bbc97758d0ed34036a2c50c69e4ecc9fa38a965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Wed, 9 Sep 2026 19:25:06 +0800 Subject: [PATCH 6/6] =?UTF-8?q?fix(contract-manage-change):=20=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90=E7=BB=93=E7=AE=97?= =?UTF-8?q?=E5=8D=95=E9=97=AE=E5=8F=B7=E6=8F=90=E7=A4=BA=E5=9B=BE=E6=A0=87?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 解决图标夹在开启/关闭 radio 按钮之间,开启按钮右侧多余间距问题 - 清除开启 radio 默认 margin-right,调整提示图标左右间距 - 提示图标紧靠开启按钮一侧,关闭按钮保持较大间距 - 优化样式,使布局更美观一致 --- .workbuddy/memory/2026-09-09.md | 1 + src/views/business/contract-manage-change.vue | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.workbuddy/memory/2026-09-09.md b/.workbuddy/memory/2026-09-09.md index 152dc68..8a371bc 100644 --- a/.workbuddy/memory/2026-09-09.md +++ b/.workbuddy/memory/2026-09-09.md @@ -212,3 +212,4 @@ - driver.vue 从业资格证有效期对齐驾驶证:单日期改 date-range 起/止(列宽 6+6+6+6 → 6+6+8+4),新增 qualificationStartDate 字段(emptyForm + handleSubmit normalize);qualificationEndDate 规则加 required:true(渲染星号,validator 豁免长期);删除 qualificationLongTerm 的 required 规则(长期有效不必填);勾长期后起止均 disabled(比驾驶证更严,驾驶证起仍可编辑)。⚠️ 后端需新增 qualification_start_date 字段否则起日期无法存取。 - driver.vue 补充:驾驶证「有效期起」加 :disabled(长期=1 时禁用);驾驶证与从业资格证两个 validator 统一在「长期有效=1」时直接 callback() 放行(起止都不校验、不提示)。禁用不清空旧值,提交时保留原日期(后端以 longTerm 为准)。 - contract-manage-change.vue「合同文件」批量下载按钮上移:标题与按钮合并进 .section-head(flex space-between 同排),与「其它附件/计费信息」分区一致;删除无引用的 .attachment-head 样式。 +- contract-manage-change.vue「自动生成结算单」问号提示图标位置:原 icon 夹在开启/关闭 radio 之间,因 .el-radio 默认 margin-right:32px 导致离开启远、贴关闭;修复 = 开启 radio margin-right 清零 + icon margin 改 0 32px 0 8px。 diff --git a/src/views/business/contract-manage-change.vue b/src/views/business/contract-manage-change.vue index 5360a4d..c0e0fcb 100644 --- a/src/views/business/contract-manage-change.vue +++ b/src/views/business/contract-manage-change.vue @@ -219,7 +219,9 @@ export default { .attachment-upload .vehicle-attachment-upload { width: auto; } .attachment-upload .el-upload { display: inline-flex; } .settlement-switch { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; } -.settlement-switch-tip { margin: 0 4px; color: #a8abb2; cursor: help; font-size: 14px; } +// 问号提示图标紧靠「开启」一侧:清掉开启 radio 自带的右间距,图标与「关闭」之间留大间距 +.settlement-switch :deep(.el-radio:first-child) { margin-right: 0; } +.settlement-switch-tip { margin: 0 32px 0 8px; color: #a8abb2; cursor: help; font-size: 14px; } .settlement-form { display: grid; grid-template-columns: repeat(3, minmax(240px, 1fr)); gap: 8px 28px; } .change-reason-section { margin: 20px 0; } .page-footer {