Files
tms-erp-web/.workbuddy/memory/2026-08-06.md
赵忠林 02b2e3b673 refactor(transportCapacity): 使用 section-card 重构司机管理弹窗布局
- 将司机管理页面新增/编辑弹窗中四个分组改为使用标准 section-card 组件包裹
- 删除手写的扁平样式和红色竖条,统一使用全局 element-ui 样式维护弹窗视觉风格
- 调整司机证件上传区尺寸为 240x151 px,保持身份证比例并左对齐显示
- 优化弹窗中各表单项布局,提高视觉层次与一致性
- 更新 scoped 样式,移除无用的 section-title 样式,保持代码清洁
2026-08-06 16:53:23 +08:00

108 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 2026-08-06
## 复盘 src/views/business/project-apply.vue 弹窗 UI 规范
- 主弹窗为**自定义 el-dialog + el-form**(非 Avue option 驱动width 1440px、top 4vh、append-to-body、destroy-on-close。
- 分区标题复用全局 `.dialog-section-title`4px 主色竖条 + 8px 间距);页面将其改造为「白卡头 + 下方白内容卡」拼合方案radius 6px + 淡阴影 0 1px 2px rgba(0,0,0,.04))。
- 表单label-position="right" / label-width="auto";两列 grid`column-gap: 72px`);表单项 margin-bottom 16pxlabel min-width 160px。
- 备注类 textarea 整行展示 + 200 字上限 + show-word-limit金额/天数有非负与范围校验。
- 底部按钮:非变更弹窗=取消/提交(右对齐);变更弹窗=提交/保存/关闭(左对齐)。
- **与设计规范(AGENTS.md)对照**:基本符合 4.8 弹窗表单规范;但本页 scoped 用 `white-space: normal` 覆盖了全局 `.el-dialog .el-form-item__label { white-space: nowrap }`允许长标签换行与全局「label 不换行」取向不同);两列 grid 统一 min-width 160px未严格「按列分别计算 label 宽度」。
## 将 project-apply 弹窗标准推广为「全项目通用标准」
用户要求把 project-apply 弹窗视觉(灰底 + 分组白卡 + 标题在卡内)复制到其他页面。落地方式(已执行):
- 新增可复用组件 `src/components/section-card/main.vue`:白卡 + 标题在卡头4px 主色竖条 + 8px 间距),支持 `title` prop 与 `#title`/`#extra` slot已在 `src/main.js` 全局注册为 `<section-card>`
-`src/styles/element-ui.scss` 末尾新增全局标准:① `.el-dialog__body` 统一灰底 `#f5f6fa`(影响全项目所有弹窗);② `.el-dialog .avue-form` 自动包白卡Avue 默认增删改弹窗无需改 option 即统一);③ `.el-dialog .avue-form__group` 分组白卡option.group 渲染为标题在卡内);④ 弹窗内 `.el-form-item` 默认 16px 间距;⑤ `.section-card` 全局样式;⑥ `.form-grid-2` 两列栅格工具类column-gap 72px
- 应用落地business 模块自定义弹窗——`common-route.vue` 的「选择常用地址」弹窗用 section-card 包成「查询条件/常用地址」两组;`loading-manage.vue` 主弹窗 6 个分区全部改用 `<section-card>``common-cargo.vue` 导入弹窗经全局 `.el-dialog .avue-form` 规则自动获得白卡。`project-apply.vue` 本身作为参照未改(其 scoped 样式已符合,全局灰底与其一致)。
- 验证:`vite build` 失败为仓库既有问题(`waybill-import-dialog.vue` 引入的 `xlsx` 依赖缺失),与本次改动无关;改用 `@vue/compiler-sfc` 编译三个改动 .vue均 OK+ sass 编译 `element-ui.scss`OK
- 注意:其他模块的**自定义弹窗**需按同样方式用 `<section-card>` 包裹各组(灰底已由全局规则自动生效);如需继续推进其余模块可照此模式批量处理。
## 继续推广vehicle/customer-archive.vue 弹窗
- 用户反馈 `/vehicle/customer-archive` 新增客商档案弹窗需与 `/business/project-apply` 一致。
- 已将该页主弹窗内的表单分组由旧版「灰底分组块 + 内层白卡 + 标题在卡内」全部替换为 `<section-card>`
- 工商信息 / 联系信息 / 财务/信用信息 / 其他信息 四个分组改为 section-card删除外层浮于灰底的「基本信息」大标题分组已足够清晰避免嵌套
- 客商材料、变更记录两个非表单分区也改用 `<section-card>`,其中客商材料的操作按钮通过 `#extra` 插槽放在卡头右侧。
- 清理了失效的 `.archive-form__group``.customer-material-section``.change-record-section``.section-title` 等 scoped 样式。
- 验证:`@vue/compiler-sfc` 编译 `customer-archive.vue` OKsass 编译 `element-ui.scss` OKsection-card 标签开合平衡。
## 继续推广transportCapacity/driver.vue 弹窗
- 用户反馈司机管理页面(`/transportCapacity/driver`)新增/编辑弹窗的 UI 与「重大项目补录」等不一致,仍是红色竖条 + 字段直接落在灰底上的扁平样式,要求统一为「灰底弹窗 + 白底分组卡片」。
- 改造 `src/views/transportCapacity/driver.vue`
- 4 个分组(基础身份信息 / 驾驶证信息 / 从业资格证信息 / 司机联系信息)由原 `<div class="section-title">` + 扁平 `<el-row>` 改为标准 `<section-card title="...">` 包裹。
- 删除手写的 `.section-title`(红色竖条)、`.driver-form__block`(白底分组卡)、自定义 `.driver-dialog { :deep(.el-dialog__body) { background: #f0f2f5; ... } }` ——以上视觉均由 `src/styles/element-ui.scss` 的全局 `.el-dialog__body { background: #f5f6fa; padding: 16px; }` + `.section-card { ... }` 自动覆盖。
- 弹窗内 4 个分组的二级 row 网格不变3列/4列 12栏布局由每张白卡的 body 承载。
- 教训:第一次改动按 `project-apply.vue` 的手写方式做了一版(手写 `dialog-section-title` override + `__block`),与已落的「全项目通用标准」重复。**今后新页面/新弹窗直接用 `<section-card>`,不要再手写卡片样式**。
## 调整 `/base/fee-item` 弹窗左右表单项间距
- 用户反馈费用项弹窗中「费用类型」与「费用项代码」左右列太挤。
- 修改 `src/views/base/fee-item.vue` 的 scoped 样式:将弹窗内 `.avue-form__row` / `.el-row` 的负边距与 `.el-col` 的水平 padding 从 `36px` 加大到 `48px`,等效 gutter 由 72px 增至 96px。
- 该样式限定在 `.avue-crud__dialog` 内,仅影响新增/编辑弹窗,不影响列表搜索栏。
## 调整 `/vehicle/violation-record` 弹窗两栏横向间距
- 用户反馈违章记录新增弹窗左右两列表单项间距太小,列与列之间距离过近。
- 修改 `src/views/vehicle/violation-record.vue` 的 scoped 样式:限定在 `.el-dialog__body .avue-form` 内,将 `.el-row` 负边距与 `.el-col` 水平 padding 均设为 `24px`,等效 gutter 由默认 `20px` 增至 `48px`
- 仅作用于弹窗内的 Avue 表单,不影响列表搜索栏;保持表单项纵向间距不变。
## 将 `/business/process-config` 弹窗改为 section-card 卡片式布局
- 用户反馈过程配置新增弹窗需将「基本信息」「现行过程节点」「节点设置」等分组改为白卡(参考重大项目补录)。
- 改造 `src/views/business/process-config.vue` + `src/option/business/process-config.js`
- 取消本页 `.avue-crud__dialog .avue-form` 的全局自动白卡(避免白底套白底),改为灰底上直接叠 `<section-card>`
- `basicInfo-form``<section-card title="基本信息">` 包裹;将原独立 Avue 字段 `includedNodes` 改为 formslot 并移入该卡片内部,用 `el-select` multiple 自定义渲染,保留 `searchLabel` 使搜索栏不受影响。
- `nodeConfigJson-form` 拆分为 `<section-card title="现行过程节点">``<section-card title="节点设置">` 两张白卡。
- 新增 `includedNodeValues` 计算属性,实现下拉框与 `nodeRows.enabled` / `form.includedNodes` 的双向同步。
- 添加 `.process-config-page__field-label--required` 样式给必填项标红 `*`
- 通过 scoped 覆盖消除 formslot 外层 `.el-form-item` 的额外 `margin-bottom`,由 section-card 自身控制卡片间距。
- 验证:`@vue/compiler-sfc` 编译 `process-config.vue` template/script OKsass 编译其 scoped style OKsection-card 标签开合平衡。
## 修正 process-config 弹窗「卡片看不见」的真正根因(重要坑)
- 现象:用 `<section-card>` 包了基本信息/现行过程节点/节点设置三张白卡,但弹窗里看不出卡片,用户反馈"还是不对"。
- 排查发现:之前方向的"灰底缺失"是错的——全局 `.el-dialog__body { background:#f5f6fa }``.el-dialog .avue-form { 白卡 }` 早就定义在 `src/styles/element-ui.scss`(216/222 行),灰底一直有。
- **真正根因**Avue CRUD 弹窗默认 `append-to-body:true`DOM 挂在 `<body>` 下、在组件模板之外。组件 scoped 样式里的 `:deep(.avue-crud__dialog .avue-form)` 编译为 `[data-v-x] .avue-form`,要求祖先带 scoped 属性,而 append-to-body 弹窗没有该祖先 → 规则不命中 → 全局 `.el-dialog .avue-form` 白卡未被取消 → 白卡套白卡section-card 被白色表单卡盖住看不见。
- 修正:作用于 append-to-body 弹窗的样式必须用 `:global(...)`(完全全局、不依赖 scoped 祖先)。给 option 加 `dialogCustomClass: 'process-config-dialog'``dialogCustomClass` 由 Avue 直接挂在 `.el-dialog` 根元素上),把所有弹窗内覆盖规则改为 `:global(.process-config-dialog .avue-form)` + `!important`(取消全局 `.el-dialog .avue-form` 白卡,露出灰底),并清零 formslot 的 `.el-form-item`/`.el-col`/`.el-form-item__content`/`.avue-form__row` 占位与内边距让卡片满宽贴边。列表内的 `:deep(.el-table)` 仍有效(列表在组件 DOM 内),弹窗内表格需用 `:global(.process-config-dialog .el-table)`
- **二级坑(本次才真正修对)**DOM 路径里**不要写 `.avue-crud__dialog`**。该 class 只存在于 avue 默认 `index.css`,而 Avue 组件 JSdialog-form3.mjs实际只把 `dialogCustomClass` 加到 `.el-dialog` 根、内部是 `.el-dialog__body > .avue-form``.avue-crud__dialog` 在运行时根本不渲染。之前写 `.process-config-dialog .avue-crud__dialog .avue-form` 整体不命中,白卡一直没被取消 → 卡片照样看不见。正确路径:`dialogCustomClass`(=`.el-dialog`) 直接作祖先,下接 `.avue-form`/`.el-form-item`/`.el-col` 等。
- **三级坑**`includedNodes` 列虽已改 formslot 且在 basicInfo 卡片内手动渲染但它没有关掉表单显示Avue 仍会为其渲染一个**空的 `.el-form-item`**(无对应 `#includedNodes-form` 槽),在「基本信息」与「节点设置」卡片间留下空隙。修正:给 `includedNodes``addDisplay:false, editDisplay:false`(保留 `search:true`+`searchLabel` 不影响搜索栏)。
- 教训(可复用):**凡要给 Avue/Element 的 append-to-body 弹窗el-dialog 默认 append-to-body写 scoped 覆盖样式,一律用 `:global()``:deep()` 在弹窗 DOM 上不生效;且选择器祖先只用 `dialogCustomClass`(挂在 `.el-dialog`),不要误加 `.avue-crud__dialog`(运行时不存在)。** 之前 vehicle/customer-archive、loading-manage 等自定义弹窗若也用 append-to-body弹窗内 `:deep` 覆盖同样可能失效(它们当时多靠全局 `.el-dialog .avue-form`/`.section-card` 兜底,未暴露)。
## 继续推广transportCapacity 三页面弹窗 + 上传区整改
- 用户确认 `/transportCapacity/driver` 改造效果正确,并要求:
- `/transportCapacity/vehicle``/transportCapacity/ship` 两个页面的弹窗也按同样 `<section-card>` 标准整改。
- 上传证件区域整改为:① 宽高比 = 中国二代身份证 1.586:185.6 × 53.98 mm② 区域大小取真实身份证的 50%,固定 165 × 104 px③ 适用范围 = **全部**上传区(含机动车行驶证主页正/反/副页正/反、道路运输证、机动车登记本、船舶所有权/安全环保/国籍/最低安全配员/光船租赁/营业运输 共 6 张 + 行驶证 4 张),居中显示不再 100% 占栏。
- 已落地:`src/views/transportCapacity/driver.vue` + `vehicle.vue` + `ship.vue` 三页面:
- vehicle.vue: 2 个分组 `<div class="section-title">` 替换为 `<section-card title="基础车辆信息/车辆资质图片">`;删除 `.section-title``.section-title:first-child` scoped 规则。
- ship.vue: 2 个分组替换为 `<section-card title="基础船舶信息/船舶证书信息">`6 个子证书仍保留 `.cert-block` + `.cert-block__title` 做内部子分段(外层白卡 + 内层 1px border-top 分隔线,视觉层次合理);删除 `.section-title``.section-title--wide``.section-title:first-child` scoped 规则。
- driver.vue: 之前已用 `<section-card>` 完成,本次仅收尾上传区尺寸。
- 三页面的 `uploader` 样式统一改造:`.xxx-uploader` 取消强制 width:100%;新增 `.xxx-uploader--large { display:block; width:165px; margin:0 auto }``.xxx-uploader--large .el-upload { width:100%; height:104px }``--large` 选择器特定性 0,0,1,0 写在最后覆盖默认规则,源码位置在 `.xxx-uploader` 之后,确保 CSS 顺序覆盖生效)。
- 保留每个 class-prefix 的非 large 默认高度170px、placeholder 边框/背景/居中等样式。
- 验证:`@vue/compiler-sfc` 编译三个 .vue 均 OK`<section-card>` 标签数量 driver 4/4、vehicle 2/2、ship 2/2 平衡vite dev 服务对 `/transportCapacity/{driver,vehicle,ship}` 均返回 200prettier 通过。
- 沉淀到 MEMORY.md 的设计约定:「上传证件区域 = `aspect-ratio: 1.586` + 固定 165 × 104 px + 居中」为全 transportCapacity 模块统一的硬规范。后续若其他模块也使用 `<image-upload-field large>` 应套用同款规范。
## 上调 transportCapacity 三页面上传证件区域尺寸165×104 → 240×151并左对齐
- 用户反馈上一轮的 165×104真实身份证 50%)偏小、看不清楚。
- 三页面(`driver/vehicle/ship.vue`)的 `.xxx-uploader--large` 尺寸统一上调到 **240 × 151 px**(约真实身份证 75%,保持 1.586:1对齐方式由 `margin: 0 auto` 居中改为 `margin: 0` 左对齐。
- 仅改三页面 scoped 样式里的 `width / height / margin` 三处数值,未动模板与组件逻辑;非 large 默认高度 170px 等样式保留。
- 同步更新 MEMORY.md「上传证件区域尺寸规范」为 240×151 + 左对齐。
## 规划:将 process-config.vue 弹窗布局对标 project-apply.vue尚未落地
- 用户要求参考 `/business/project-apply.vue` 重构 `process-config.vue`**主要是 UI 布局**。
- 现状回顾process-config 弹窗卡片**已用 `<section-card>` 包裹**basicInfo / 现行过程节点 / 节点设置),但弹窗机制仍是 **Avue `avue-crud` 表单槽(`#basicInfo-form`/`#nodeConfigJson-form`+ `before-open`/`row-save`/`row-update`**;字段用 `el-row/el-col :span=12` + 手写 `.process-config-page__field`flex 左标签右控件)。
- 目标对标 project-apply① 列表只做表格/搜索,新增/编辑/查看改为**自定义 `el-dialog` + 手写 `el-form`**(去掉 Avue 表单槽与 before-open/row-save/row-update② 字段布局从 `el-row/el-col + 手写 label` 改为 **CSS 两列网格 `.__grid`column-gap 72px+ 原生 `el-form-item` labelright/auto**;③ 卡片继续用 `<section-card>`(项目统一标准,不回头手写白卡);④ 底部「取消/提交」(查看态隐藏提交)。
- 逻辑NODE_TEMPLATES、parseNodeConfig、validateRow、loadProjectOptions、includedNodeValues 计算属性)全部保留,仅把 Avue 钩子改为自定义 `openConfigDialog/submitConfig``api.submit/copy/enable/disable/remove/getDetail` 不变。
- 待确认决策:卡片实现用 `<section-card>`(推荐,符合项目标准)还是 1:1 还原 project-apply 的手写白卡(与项目标准不一致)。用户仅要求先规划,未授权落地。
## 已落地process-config.vue 弹窗重构为自定义 el-dialog对标 project-apply卡片用 section-card
- 已按方案执行:`src/views/business/process-config.vue` 改为「列表 avue-crud仅表格/搜索)+ 自定义 el-dialog 新增/编辑/查看」结构。
- 关键改造:① 删除 `@before-open/@row-save/@row-update``#basicInfo-form`/`#nodeConfigJson-form` 表单槽;② 新增 `el-dialog.process-config-dialog`1440px / top4vh / append-to-body / destroy-on-close+ 手写 `el-form.ref=configForm`label right/auto+ 两列 CSS 网格 `.process-config-form__grid`column-gap 72px③ 三张白卡仍用 `<section-card>`(基本信息 / 现行过程节点 / 节点设置);④ 底部「取消 / 提交」(查看态隐藏提交)。
- 逻辑保留NODE_TEMPLATES、parseNodeConfig、validateRow、loadProjectOptions、includedNodeValues 计算属性、节点表格/时间轴渲染均不变;仅把 Avue 钩子换成 `openConfigDialog/resetConfigDialog/submitConfig`,新增 `formRules` + `configDialogTitle` + `handleValidateFail`
- 样式:删除原 `:global(.process-config-dialog .avue-form …)` 及其 `.el-form-item/.el-col/.avue-form__row` 覆盖(不再用 Avue 表单);新增 `:global(.process-config-dialog .el-dialog__body){ max-height:76vh; overflow-y:auto }`(灰底 16px 已由全局规则提供);`.process-config-form` 作用域样式grid/label min-width160/节点表头 #f5f7fa/偶数行 #fafafa/timeline/require-*)。
- 注意:自定义 el-dialog 是 `append-to-body`,作用于弹窗的覆盖样式仍须 `:global()``.el-dialog__body``.process-config-form` 及其 `:deep()` 因内容由本组件渲染、带 scoped 属性可命中。
- 验证:`@vue/compiler-sfc` 编译 template+script OK、scoped style 括号配平 OK无 beforeOpen/rowSave/forms lot 残留引用。
## 全局组件 image-upload-field 增加点击放大预览
- 用户要求证件图片可点击放大查看。确认方案:用 Element Plus 原生 el-imagepreview-src-list+ 改全局组件一次、driver/vehicle/ship 三页自动生效。
- 改造 `src/components/image-upload-field/main.vue`:① 两模式form / card`<img>` 都换成 `el-image`preview-src-list=[value], fit=contain, preview-teleported, z-index=3000, @click.stop② form 模式图片下方加 `el-link`「更换」、card 模式 head 的 actionText 改 `el-link` 可点;③ 新增 `triggerUpload()``el-upload` 隐藏 `input.el-upload__input``.click()` 触发文件框el-upload 仅 expose abort/submit/clearFiles/handleStart/handleRemove无 openFileDialog须 DOM 方式);④ `@click.stop` 阻止图片点击冒泡到 el-upload 误触发重传;⑤ readonly 时仅预览、无上传入口。
- 兼容性:三页 scoped 样式同时写了 `.xxx-uploader .el-upload`(后代)与 `.xxx-uploader.el-upload`(同元素)两种选择器,把 `.xxx-uploader` 从 el-upload 移到外层 div 后高度样式仍生效;`.xxx-uploader--large` 同理。
- 验证:`@vue/compiler-sfc` 解析 main.vue + 三页均 OKvite dev 对三页均返回 200确认 el-upload 内部隐藏 input 类名为 `.el-upload__input`(源码 `ns.e('input')`)。