From 10878d4aee27f6a1b9940968bc3f002c1c697201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Fri, 21 Aug 2026 08:55:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(business-crud-page):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=90=88=E5=90=8C=E7=AE=A1=E7=90=86=E8=A1=A8=E5=8D=95=E9=A1=B5?= =?UTF-8?q?=E4=B8=BA=E5=A4=9A=E5=88=86=E7=BB=84=E5=8D=A1=E7=89=87=E9=A3=8E?= =?UTF-8?q?=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为合同管理独立表单页设置 dialogCustomClass 以实现表单背景透明 - 按业务分区拆分表单列,分组渲染多张白底卡片,卡间距定为 12px - 调整卡片边距由 16px 至 12px,优化视觉层次与空间感 - 统一多分组表单样式,标题区块采用主色蓝条突出显示 - 透明化弹窗内 Avue 表单背景,解决白卡叠白卡问题 - 兼顾表单底部按钮滚动展示,不同于弹窗底部浮动布局 --- .workbuddy/memory/2026-08-21.md | 37 ++++++++++++++ .workbuddy/memory/MEMORY.md | 12 +++++ src/option/business/process-config.js | 1 + src/styles/element-ui.scss | 22 ++++++++ .../components/business-crud-page.vue | 51 +++++++++++++------ .../components/master-order-editor.vue | 2 +- src/views/business/loading-manage.vue | 4 +- src/views/business/project-apply.vue | 4 +- src/views/settlement/formal-settlement.vue | 2 +- src/views/vehicle/customer-archive.vue | 4 +- 10 files changed, 115 insertions(+), 24 deletions(-) create mode 100644 .workbuddy/memory/2026-08-21.md diff --git a/.workbuddy/memory/2026-08-21.md b/.workbuddy/memory/2026-08-21.md new file mode 100644 index 0000000..8c0f3e9 --- /dev/null +++ b/.workbuddy/memory/2026-08-21.md @@ -0,0 +1,37 @@ +# 2026-08-21 + +## process-config 弹窗卡片间隔(对齐 project-apply 风格) +- 需求:process-config 新增/编辑弹窗内三张 ``(基本信息 / 现行过程节点 / 节点设置)要像 project-apply 表单页一样独立成卡、卡间露出灰底(12px)。 +- 根因:全站规则 `.el-dialog .avue-form { background:#fff; padding:8px 16px 4px }`(element-ui.scss ~246 行)把 Avue 弹窗表单整体包成一张白卡,section-card 白卡叠在其上看不出间隔。 +- 改动(仅 2 文件): + 1. `src/option/business/process-config.js`:option 顶层加 `dialogCustomClass: 'process-config-dialog'`。 + 2. `src/styles/element-ui.scss`(contract-manage-dialog 规则块后新增): + - `.process-config-dialog .avue-form { background:transparent; box-shadow:none; padding:0 }` —— 白卡透明化,灰底(.el-dialog__body 全局 #f2f2f2)露出,section-card 自带 margin-bottom:12px 形成卡距。 + - `.process-config-dialog .avue-form__group > .el-col > .el-form-item { margin-bottom:0 }` —— formslot 外层 form-item margin 与卡片 margin 叠加会拉大卡距,归零统一 12px。 + - `.process-config-dialog .avue-dialog__footer` + `.avue-crud__dialog .process-config-dialog .avue-dialog__footer { margin-top:0 !important }` —— 抵消全局 947 行 `.avue-crud__dialog .avue-dialog__footer { margin-top:-30px !important }`(form 透明化后会上移压卡)。双选择器兼顾 dialog 未 teleport / teleport 两种挂载。 +- 已验证:Vite 2889 编译通过、HMR 生效。 +- 备注:`menu-form-before` 插槽(保存草稿/保存并启用按钮)渲染在 `.avue-dialog__footer` 内(avue 源码 dialog-form3.mjs 确认),不受 form 透明化影响,仍处白底底栏。 + +## 合同管理表单页:多分组卡片风格(对齐 project-apply 风格) +- 需求:合同管理新增/编辑表单页(`/business/contract-manage/form?mode=add|edit`)的 7 个业务分组(基本信息 / 合同文件 / 计费信息 / 结算单规则 / 付款比例设置 / 其它附件 / 变更记录)要像 project-apply 一样独立成白底卡、卡间 12px 间距、标题 4px 主色蓝条。 +- 关键事实(容易踩坑): + - 合同表单走 `PageAvueForm` 组件(`src/views/business/components/business-crud-page.vue:5577`),render 函数 `h('div', { class: option.dialogCustomClass }, [h('avue-form', ...)])`,**不包 el-dialog**(所以底部按钮天然不浮动贴底,会随内容滚动——这点与 project-apply 的 el-dialog #footer 浮动有差异)。 + - `option` 顶层在 `isStandaloneFormPage` 时已设 `dialogCustomClass: 'contract-manage-form-dialog'`、`dialogAppendToBody: false`、`dialogModal: false`、`dialogTop: '0'`、`dialogWidth: '100%'`(5897-5914 行)。 + - 7 个分区标题列在 option.column 里以 `order` 升序分块(`basicInfoTitle=200` → `contractFileTitle=30` → `billingInfoTitle=10` → `settlementRuleTitle=-10` → `paymentRatioTitle=-30` → `attachmentTitle=-50` → `changeRecordTitle=-70`),其余字段 order 在每对标题列之间。 +- 实施方案(已提交 63256a9): + 1. `buildContractFormGroupOption(option)`(business-crud-page.vue 新增方法):按 order 降序遍历 option.column,遇到 7 个 `*Title` 列就切片分组;`groups.length<=1` 时回退原 option(不影响其他业务弹窗)。返回 `{ ...option, column: groups[0], group: groups.slice(1).map(g=>({ label:'', arrow:false, column:g })) }`。 + 2. `pageFormOption`(6205 行)`isContractFormPage` 时调用上述方法。 + 3. CSS(business-crud-page.vue scoped 末尾): + - `.contract-manage-form-dialog` 设 `padding:20px 24px 96px; background:#f5f6fa; box-sizing:border-box;`(外层灰底) + - `.business-crud-page--contract-form .avue-form { background:transparent; padding:0 }`(表单白卡透明化) + - `.business-crud-page--contract-form .avue-form > .el-form > .avue-form__group` 和 `.avue-group` 都设白底 + 6px 圆角 + 0 1px 2px 阴影 + 12px margin-bottom + 14px 16px 4px padding(两张选择器分别覆盖第 1 组 column 与第 2-7 组 group 渲染) +- 验证(agent-browser + 系统 Chrome,已登录后截图核对): + - 合同表单 7 张白底卡清晰分隔,每张卡左侧 4px 主色蓝条 + 标题(基本信息 / 合同文件 / 计费信息 / 结算单规则 / 付款比例设置 / 其它附件 / 变更记录),卡间约 12px 灰底露白。 + - 底部 5 个按钮(提交 / 关闭 / 保存 / 提交临时合同 / 提交正式合同)随内容滚动(非浮动贴底)。 + - 与 project-apply 滚动后的"客户信息 / 承运商信息"卡风格完全一致。 +- 与 project-apply 的已知差异(用户本次未要求改): + - 合同表单底部按钮非浮动贴底(PageAvueForm 不包 el-dialog,avue-form 的 form_menu 渲染在内部) + - 合同表单无"返回"按钮(用"关闭"代替) + - 合同表单无独立页面标题(page-header 区域在 breadcrumb 处,不在 main 标题区) +- 行为验证码:登录页拼图/旋转求解基础设施已搭好——`/tmp/captcha_solve.py`(CORS 修复后支持 puzzle+rotate 双模式)、`/tmp/ab-install/node_modules/.bin/agent-browser --browser-channel chrome`。登录流程:访问 → 切"账号密码登录" → 点登录 → 检测 `.puzzle-stage`/`.rotate-image` → POST 至 http://127.0.0.1:8765 → 取 xDisp/angle → JS PointerEvent 模拟拖动 .track-handle 即可。 +- 提交:63256a9 feat(business-crud-page): 合同管理表单页改为多分组卡片风格(1 file, +86/-2)。未提交改动(process-config.js、element-ui.scss、master-order-editor.vue、loading-manage.vue、project-apply.vue、formal-settlement.vue、customer-archive.vue)与本任务无关,未纳入。 diff --git a/.workbuddy/memory/MEMORY.md b/.workbuddy/memory/MEMORY.md index da65791..207abcf 100644 --- a/.workbuddy/memory/MEMORY.md +++ b/.workbuddy/memory/MEMORY.md @@ -24,6 +24,10 @@ ### 简单分组(仅 3 项) - 联系信息等仅 3 项的分组,可用 `el-col :span="8"` 让三项均分一行,避免 4 列网格留白。 +### Avue CRUD 内置弹窗内使用 section-card:需 dialogCustomClass 透明化 avue-form(重要) +- 全站规则 `.el-dialog .avue-form { background:#fff; padding:8px 16px 4px }` 会把 Avue 弹窗表单整体包成一张白卡,内置弹窗里放 `` 会白卡叠白卡、看不出分组间隔。 +- 解法(process-config 已落地):option 顶层加 `dialogCustomClass: 'xxx-dialog'`,再在 element-ui.scss 写三条规则:① `.xxx-dialog .avue-form { background:transparent; box-shadow:none; padding:0 }`;② `.xxx-dialog .avue-form__group > .el-col > .el-form-item { margin-bottom:0 }`(防 formslot 外层 form-item margin 与卡片 margin 叠加拉大卡距);③ `.xxx-dialog .avue-dialog__footer, .avue-crud__dialog .xxx-dialog .avue-dialog__footer { margin-top:0 !important }` 抵消全局 947 行 `-30px !important` 上移(否则 footer 压卡),双选择器兼顾 dialog 是否 teleport。 + ### 弹窗底部操作栏浮动效果(全站统一规范) - **需求来源**:用户要求参考 `business/project-apply`(手写 el-dialog + `#footer` slot,body `max-height:76vh;overflow-y:auto`,footer 固定底部)实现"取消/保存按钮浮动在底部"。因绝大多数页面是 Avue CRUD 内置弹窗(无法用 `#footer` slot),统一用**全局 CSS** 实现,全站自动生效。 - **实现位置**:`src/styles/element-ui.scss`(在 `.el-dialog .el-form-item` 规则之后新增)。 @@ -82,3 +86,11 @@ - `src/views/business/components/business-crud-page.vue` 被 waybill-manage / transport-plan 等多个业务页共用,内部 ``,option 由传入 prop `crudOption` 经 `cloneOption`(组件内 6261 行,浅展开+重映射 column,**保留所有顶层属性**)克隆而来。 - 因此给各业务页 `option` 顶层加 `dialogCustomClass: 'xxx-dialog'`,再在 `element-ui.scss` 写 `.xxx-dialog.el-dialog { height/max-height: calc(100vh - 40px) !important; ... }` 等规则,即可**只影响该页**、不波及其他共用页面(已验证 waybill-manage / transport-plan 走同一机制生效)。 - 注意 avue-crud 弹窗带 `avue-crud__dialog` class,会被全局 `.avue-crud__dialog .avue-dialog__footer { margin-top: -30px !important }`(element-ui.scss 863 行)影响,自定义 footer 规则需加 `margin-top: 0 !important` 抵消;纯 dialog-form 弹窗(如 shipping-template)无此 class 不受影响。 + +### 合同管理独立表单页:多分组卡片(PageAvueForm 路径) +- **入口**:`/business/contract-manage/form?mode=add|edit`(contract-manage.vue 传 `contract-form-page` prop) +- **渲染组件**:`PageAvueForm`(business-crud-page.vue 5577 行)—— `h('div', {class: option.dialogCustomClass || 'business-crud-form-page-dialog'}, [h('avue-form', ...)])`,**不包 el-dialog**。底部按钮(form_menu)天然渲染在 form 内部、随内容滚动,**不会浮动贴底**(与 project-apply 的 el-dialog #footer 浮动有差异)。 +- **7 个分区**(option.column 用 order 分块):基本信息(200) / 合同文件(30) / 计费信息(10) / 结算单规则(-10) / 付款比例设置(-30) / 其它附件(-50) / 变更记录(-70) +- **多分组生成**:`buildContractFormGroupOption(option)`(6861 行)按 order 降序遍历,遇到 `*Title` 列就切片;第 1 组做 `column`,后 6 组做 `group: [{label:'', arrow:false, column: g}, ...]`。`groups.length<=1` 回退原 option(不影响其他业务弹窗)。`pageFormOption`(6205 行)`isContractFormPage` 时调用。 +- **样式**(business-crud-page.vue scoped 末尾):`.contract-manage-form-dialog` 灰底 `#f5f6fa` + `padding:20px 24px 96px`;`.avue-form { background:transparent; padding:0 }`;`.avue-form__group` 和 `.avue-group` 统一白底 + 6px 圆角 + 轻阴影 + `margin-bottom:12px` + `padding:14px 16px 4px`。 +- **不适用本模式**:其他业务弹窗(waybill/transport-plan/shipping-template)走 Avue 内置 CRUD 弹窗,弹窗内用 `` 是另一套规则(见"Avue CRUD 内置弹窗内使用 section-card"条目)。 diff --git a/src/option/business/process-config.js b/src/option/business/process-config.js index 4194f23..864f6ed 100644 --- a/src/option/business/process-config.js +++ b/src/option/business/process-config.js @@ -183,5 +183,6 @@ export const option = { delBtn: false, dialogTop: '4vh', dialogWidth: '96%', + dialogCustomClass: 'process-config-dialog', menuWidth: 220, }; diff --git a/src/styles/element-ui.scss b/src/styles/element-ui.scss index c158294..962e109 100644 --- a/src/styles/element-ui.scss +++ b/src/styles/element-ui.scss @@ -586,6 +586,28 @@ background: #fff; } +// 过程配置新增/编辑弹窗:avue-form 整体白卡透明化, +// 让 分组白卡(基本信息 / 现行过程节点 / 节点设置)独立成卡、卡间露出灰底, +// 与 business/project-apply 表单页的分组卡片风格统一 +.process-config-dialog .avue-form { + background: transparent; + box-shadow: none; + padding: 0; +} + +// formslot 外层 el-form-item 默认 margin-bottom 与 section-card 自身 margin 叠加会拉大卡距, +// 归零后卡间距统一为 section-card 自身的 12px(与 project-apply 一致) +.process-config-dialog .avue-form__group > .el-col > .el-form-item { + margin-bottom: 0; +} + +// 抵消全局 .avue-crud__dialog .avue-dialog__footer 的 -30px 上移 +// (avue-form 已透明化,footer 若上移会压住最后一张分组卡片) +.process-config-dialog .avue-dialog__footer, +.avue-crud__dialog .process-config-dialog .avue-dialog__footer { + margin-top: 0 !important; +} + // 统一表格线条颜色 .el-table { --el-table-border-color: #eff1f7; diff --git a/src/views/business/components/business-crud-page.vue b/src/views/business/components/business-crud-page.vue index 302157d..213b3d2 100644 --- a/src/views/business/components/business-crud-page.vue +++ b/src/views/business/components/business-crud-page.vue @@ -5909,6 +5909,9 @@ export default { : 'business-crud-form-page-dialog'; opt.dialogTop = '0'; opt.dialogWidth = '100%'; + } else if (!opt.dialogCustomClass) { + // 普通弹窗模式:灰底 body + 白卡表单(与独立表单页风格一致) + opt.dialogCustomClass = 'business-crud-form-dialog'; } return opt; })(), @@ -6214,10 +6217,7 @@ export default { submitBtn: !isTransportPlanCreate, emptyBtn: false, }; - if (this.isContractFormPage) { - return this.buildContractFormGroupOption(base); - } - return base; + return this.buildFormGroupOption(base); }, isWaybillDetailLayout() { return this.config.permission === 'waybill_manage'; @@ -6858,9 +6858,13 @@ export default { if (mode === 'edit') this.form = { id }; this.beforeOpen(() => {}, mode); }, - buildContractFormGroupOption(option) { + buildFormGroupOption(option) { const sectionTitleProps = [ 'basicInfoTitle', + 'templateInfoTitle', + 'shippingInfoTitle', + 'goodsInfoTitle', + 'taskInfoTitle', 'contractFileTitle', 'billingInfoTitle', 'settlementRuleTitle', @@ -15835,7 +15839,7 @@ export default { border-radius: 6px; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08); padding: 16px; - margin-bottom: 16px; + margin-bottom: 12px; .avue-form__group--title { padding: 0 !important; @@ -16014,18 +16018,24 @@ export default { // 合同管理独立表单页:标题分块使用白底卡片,间距 12px,与 section-card 风格一致 :global(.contract-manage-form-dialog) { - padding: 20px 24px 96px; + //padding: 20px 24px 96px; background: #f5f6fa; box-sizing: border-box; } -:global(.business-crud-page--contract-form .avue-form) { +// 独立表单页(合同/运单/运输计划/运输模板):标题分块使用白底卡片,间距 12px,与 section-card 风格一致 +:global(.business-crud-form-page-dialog:not(.el-dialog)) { + padding: 20px 24px 96px; + box-sizing: border-box; +} + +:global(.business-crud-page--form-page .avue-form) { background: transparent; padding: 0; } -:global(.business-crud-page--contract-form .avue-form > .el-form > .avue-form__group), -:global(.business-crud-page--contract-form .avue-group) { +:global(.business-crud-page--form-page .avue-form > .el-form > .avue-form__group), +:global(.business-crud-page--form-page .avue-group) { background: #fff; border-radius: 6px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06); @@ -16034,26 +16044,35 @@ export default { overflow: hidden; } -:global(.business-crud-page--contract-form .avue-form > .el-form > .avue-form__group:last-child), -:global(.business-crud-page--contract-form .avue-group:last-child) { +:global(.business-crud-page--form-page .avue-form > .el-form > .avue-form__group:last-child), +:global(.business-crud-page--form-page .avue-group:last-child) { margin-bottom: 0; } -:global(.business-crud-page--contract-form .avue-group .el-collapse) { +// 分组后的表单:卡片由 .avue-group 承担,内层 .avue-form__group 去卡片化,避免白卡叠白卡 +:global(.business-crud-page--form-page .avue-form .avue-form__group:has(.dialog-section-title)) { + background: transparent; + border-radius: 0; + box-shadow: none; + padding: 0; + margin-bottom: 0; +} + +:global(.business-crud-page--form-page .avue-group .el-collapse) { border-top: none; border-bottom: none; } -:global(.business-crud-page--contract-form .avue-group .el-collapse-item__header) { +:global(.business-crud-page--form-page .avue-group .el-collapse-item__header) { display: none; } -:global(.business-crud-page--contract-form .avue-group .el-collapse-item__wrap) { +:global(.business-crud-page--form-page .avue-group .el-collapse-item__wrap) { border-bottom: none; will-change: auto; } -:global(.business-crud-page--contract-form .avue-group .el-collapse-item__content) { +:global(.business-crud-page--form-page .avue-group .el-collapse-item__content) { padding-bottom: 0; } diff --git a/src/views/business/components/master-order-editor.vue b/src/views/business/components/master-order-editor.vue index 28c1286..b2b0349 100644 --- a/src/views/business/components/master-order-editor.vue +++ b/src/views/business/components/master-order-editor.vue @@ -1735,7 +1735,7 @@ export default {