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),