Files
tms-erp-web/.workbuddy/memory/2026-08-27.md
T
gxwebsoft 36cc9c751c style(ui): 优化必填星号与多行label的对齐方式
- 修复客商档案中必填项红色星号 * 与首行文字未垂直居中的问题
- 全站统一必填星号 * 的垂直居中规则,兼容单行与多行 label
- 临时额度管理弹窗多行 label 调整星号与首字对齐,避免视觉偏移
- 调整客户档案中信用评分表和附件描述布局,使字段间距合理且内容可编辑
- /business/project-apply 搜索栏项目负责人改为手动输入,优化模糊查询体验
- 新增项目编号、客户名称、下游承运商三个搜索字段,增加查询灵活性
- 调整项目申请按钮权限顺序,新增及重大项目补录按钮功能互换
- 注释隐藏tags.vue中avue-tags相关菜单按钮,简化界面
- 修改vite开发服务器端口和代理配置,指向内网环境方便调试
- 更新 pnpm-lock.yaml 应用 avue 相关补丁,保证依赖兼容性
2026-08-27 19:45:14 +08:00

99 lines
16 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-27 工作日志
## 全站底部操作栏「返回」按钮统一改为「取消」
- 起因:用户访问 `/vehicle/customer-archive/form` 独立表单页,指出底部「返回」按钮应全站统一为「取消」。
- 改动文件(模板/逻辑中的「返回」→「取消」):
- `src/views/vehicle/customer-archive.vue`:主表单页 footer 逻辑 `readonly ? '关闭' : isArchivePage ? '返回' : '取消'``readonly ? '关闭' : '取消'`4 处子弹窗(contact/receipt/invoice/score`>返回</el-button>``>取消</el-button>`replace_all)。
- `src/views/payment/invoice-receipt-form.vue``payment-application-form.vue``payment/payment-application-form.vue``goBack` 返回按钮 →「取消」。
- `src/views/business/components/master-order-editor.vue``master-order-dispatch.vue``master-order-detail.vue``$emit('back')` 返回按钮 →「取消」。
- `src/views/business/components/business-crud-page.vue`:运输计划导入弹窗关闭按钮 →「取消」。
- `src/views/system/user.vue`:用户弹窗关闭按钮 →「取消」。
- `src/views/business/project-apply.vue`:独立表单页(isProjectFormPage`closeProjectForm` 返回按钮 ×2 →「取消」。
- 未改动:`src/lang/zh.js` 登录 i18n 段 `back: '返回'`(无 `$t('back')` 引用,属登录流程返回,非业务 footer 操作栏)。
- 规范固化:更新 MEMORY.md「弹窗 / 独立表单页底栏按钮统一规则」,明确全站底部操作栏「返回」统一为「取消」,仅只读查看 / 纯关闭场景保留「关闭」。
## 发货模板独立表单页(shipping-template/formfooter 缺「取消」+ 去图标
- 起因:用户访问 `/business/shipping-template/form?mode=add`,指出底部按钮缺「取消」且不需要图标(统一只要文字)。
- 该页极薄,仅 `<business-crud-page standalone-form-page>`footer 由 `business-crud-page.vue``PageAvueForm` 渲染。
- 改动(`src/views/business/components/business-crud-page.vue`):
- `#menu-form-before` 次要按钮 `关闭``取消`(条件 `isStandaloneFormPage && !showTransportPlanCreateActions`),影响 `/waybill-manage/form``/transport-plan/form``/shipping-template/form` 三处独立表单页。
- `#menu-form` 的运输计划创建模式次要按钮 `关闭``取消`
- 新增样式 `:global(.business-crud-form-page-dialog .avue-form__menu .el-icon){display:none}`Avue 的 `avue-form` 提交/清空按钮内置图标(`submitIcon:'el-icon-check'``emptyIcon:'el-icon-delete'`),且 Avue 源码用 `||` 兜底无法通过 option 去除,故用 CSS 在独立表单页容器内统一隐藏图标,仅保留文字,不影响其它弹窗。
- 规范固化:MEMORY.md「弹窗 / 独立表单页底栏按钮统一规则」补充「独立表单页 Avue 表单 footer 去图标(统一纯文字)」说明。
## 底部操作栏按钮间距统一去 gap
- 起因:用户指出这些底部按钮间距不一致,要求统一,并把用了 `gap` 的全部去掉。
- 方案:所有底部操作栏(footer / `__actions` / `page-actions`**移除 `gap`**,间距统一回落到 Element Plus 全局默认的相邻按钮 `.el-button+.el-button{margin-left:12px}`(恒为 12px),不再散落 `gap:8/12/16px`
- 全局对齐:`.el-dialog__footer .el-button + .el-button``margin-left:8px` 改为 `12px``src/styles/element-ui.scss`),使弹窗 footer 也与之一致。
- 已去 gap 的 footer 容器:`vehicle/customer-archive.vue`(`.archive-form__footer`)、`business/components/master-order-editor.vue`(`footer`)、`business/components/master-order-dispatch.vue`(`.segment-actions`/`.pending-actions`)、`business/project-apply.vue`(`.project-apply-dialog__footer`)、`business/components/business-crud-page.vue`(`.business-crud-form-page-dialog .avue-form__menu`)、payment 6 个表单页(`*__actions`)、`settlement/components/pre-settlement-editor.vue`(`&__page-actions`)、`settlement/components/formal-settlement-editor.vue`(`.formal-editor__page-actions`)、`settlement/receivable-payable-detail.vue`(`.settlement-detail-page__actions`)。
- 风控:确认 Avue 的 `.avue-form__menu`/`.avue-dialog__footer` 自身不带按钮间距,去掉 gap 后由 EP 默认 12px margin 接管(不会贴死)。
- 范围说明:本次聚焦近几轮在统一的模块(vehicle/payment/business/settlement)。若要把 loading-manage、contract-manage、transit 等其它模块的底部栏也纳入,需再处理。
## 客商档案搜索区「所属组织」从扁平下拉改为树形下拉
- 起因:用户截图 `/vehicle/customer-archive` 搜索区,指出「所属组织」是扁平下拉,要求统一按新增/编辑表单(多选 `el-tree-select`)实现。
- 原 column 配置:`prop: 'deptName'` + `search: true` + `searchType: 'select'` + `dicData: [{label:'全部',value:''}, ...flattenDept]`initDeptTree() 异步把 dicData 写回 column(数据已加载,只是渲染风格不一致)。
- 改动:
- column 移除 `searchType: 'select'``searchValue: ''``dicData`,仅保留 `search: true, searchOrder: 1`
- `initDeptTree()` 中改写 `deptColumn.renderSearch = scope => this.renderDeptSearch(scope)`
- 新增 `methods.renderDeptSearch(scope)`:通过 `vue``h` 函数返回一个 `el-tree-select` vnode(多选 + check-strictly + 树形 + 折叠 tag + 全宽),onUpdate 时把 ID 数组按 `deptOptions` 查 rawLabel,逗号拼接写入 `scope.row.deptName`(即 searchForm.deptName),保持后端接口字段不变。
- `searchChange/searchReset` 链路无需改:`onLoad` 已通过 `query` 透传 deptName 到后端。
- `src/styles/element-ui.scss` 新增 `.avue-crud__search .el-form-item__content > .el-tree-select { width:100%; max-width:100%; }`:搜索区树形下拉全宽兜底,不影响新增/编辑表单(用 `el-col :span=6` 栅格自然分开)。
- 方案说明:Avue-crud 搜索 form-temp 内部 render 函数支持 column.renderSearch 自定义渲染(`header-search2.mjs` 行 93 `render: ele.renderSearch`),不需要重写整个搜索区;自定义 slot `<template #search-deptName>` 在 el-input 等自闭合组件上无法落地(slot 名不会被 el-input 识别),所以走 renderSearch。
- 选择项:用户确认「仅替换所属组织一格」「多选」「传 deptName」三项。
- 排查「出不来了」反馈:主人实测搜索区只有 label,控件区域空白。原因 `h('el-tree-select', {...})` 传字符串时 Vue 3 `_createVNode` 直接把 type 当 ELEMENTshapeFlag=1)处理,**不会调用 resolveComponent**,结果浏览器渲染出未知标签 `<el-tree-select>`,内容为空。
- 修复:从 `element-plus` import `ElTreeSelect` 组件对象,`h(ElTreeSelect, {...})` 走组件 vnode 路径;同时把 `modelValue` 默认值改为 `[]`(多选模式数组要求,避免 el-tree-select 警告)。
- 教训:Avue `column.render`/`renderSearch` 等接受 vnode 的字段,传字符串组件名时 Vue 不会 resolve,必须直接 import 组件对象或在 setup 内 `resolveComponent()`
- 排查「选中不了」反馈:控件显示出来了,但点击树节点无法选中/再选。根因 `onUpdate:modelValue` 里把 `scope.row.deptName` 写成了名字**字符串**,而该字段正是 el-tree-select 的 `modelValue`(多选模式必须是**ID 数组**),第一次选中后 modelValue 变字符串,el-tree-select 内部状态错乱,后续点击无法更新。
- 修复:renderDeptSearch 的 `onUpdate:modelValue` 只把 `scope.row.deptName` 写成 ID 数组(保留数组形态);在 `searchChange(params, done)` 里把 Avue 拷贝出来的 `params.deptName` 数组(注意:`filterParams``deepClone`params 与 scope.row 是不同引用,改它不破坏搜索框显示)按 `deptOptions` 查 rawLabel 再 `join(',')` 转成名字字符串写入 `query`,后端字段 deptName 不变。重置由 Avue `resetForm` 清空 scope.row.deptName 为 `''`renderDeptSearch 读到非数组回退 `[]` 显示空,无需额外处理。
## 船舶表单「安放龙骨日期/建造完工日期」label 收窄并换行
- 起因:用户截图 `transportCapacity/ship` 新增船舶弹窗,指出该字段 label 宽达 185px,要求最大 88px 并允许换行。
- 改动:`src/views/transportCapacity/ship.vue` 第 169 行,给该 `el-form-item` 增加 `label-width="88px"` 覆盖全局 `label-width="100"`;全局 `.ship-form :deep(.el-form-item__label)` 已设置 `white-space: normal; line-height: 20px`,换行已支持。
## 船舶证书信息两块表单改 4 列
- 起因:用户截图 `transportCapacity/ship` 船舶证书信息,指出「船舶所有权证书」「内河船舶安全与环保证书」两块想改成 4 列。
- 改动:`src/views/transportCapacity/ship.vue`
- 「船舶所有权证书」5 个字段:第一行 `登记号码/初次登记号码/船舶所有人/取得所有权日期` 4 列,第二行 `船舶识别号` 1 列(所有 `el-col :span="8"``:span="6"`)。
- 「内河船舶安全与环保证书」4 个字段:合并为一行 4 列(`总吨/净吨/船检登记号/船舶类型`),`el-col :span="8"``:span="6"`
- 未改动:船舶国籍证书、最低安全配员证书(日期范围,保持 `span=16` 整行)、光船租赁登记证明书、船舶营业运输证书(用户未要求)。
## 客商档案必填星号 * 与首行文字垂直居中
- 起因:用户截图「新增客商档案」基础信息分组,指出必填项 label(如「统一社会信用代码」折行后)红色星号 * 未与首行文字垂直居中对齐。
- 根因:Element Plus `.el-form-item__label` 默认 `inline-flex + align-items: flex-start``:before` 星号高度(`1em`≈14px)与文字行盒(`line-height:18px`)不一致,多行时错位。
- 改动(`src/views/vehicle/customer-archive.vue``.archive-form :deep` 块):
- `:deep(.el-form-item.is-required .el-form-item__label)``align-items: flex-start; padding-top:7px; padding-bottom:7px`7px=(32-18)/2,使内容下沉到 label 中线)。
- `:deep(.el-form-item.is-required .el-form-item__label::before)``display:inline-block; height:18px; line-height:18px; margin-right:4px`(高度=行高,参与行内对齐)。
- 范围:仅作用于 `.archive-form` 作用域(archive-form + dialog-form-label-fixed),不影响全站弹窗;与 `dialog-form-label.js` 的列宽对齐工具兼容。
- 待观察:刷新 dev 验证「统一社会信用代码」等折行字段星号是否视觉居中;若其它模块(payment/settlement 等)也有类似折行 label,可复制同样规则或提至 `element-ui.scss` 全局。
## 必填星号 * 垂直居中规则全站化
- 起因:用户确认客商档案星号居中效果 OK,要求全站统一。
- 关键差异:全站默认 label 是 `height:32px` 固定高度,客商档案 label 是 `height:auto + line-height:18px`,前者不能套用 `padding:7px` 下沉方案(会撑变形)。
- 改动:`src/styles/element-ui.scss` 新增全局规则 `.el-form-item.is-required .el-form-item__label::before { display:inline-block; line-height:inherit; margin-right:4px }`(让星号行高跟随 label,flex-start 下与首行文字等高居中),兼容单行(32px)与多行(auto+18px)两种场景。
- 客商档案 `customer-archive.vue` 的 scoped 规则(含 `padding:7px` 下沉)保留不动,scoped 特异性更高会覆盖全局;两处机制不同但视觉目标一致。
- 验收:刷新各弹窗(payment/settlement/transportCapacity 等)验证必填项星号与首行/单行文字垂直居中。
## 临时额度管理弹窗「换行 label 必填星号与首字对齐」
- 起因:用户截图 `/business/temporary-credit-limit` 新增弹窗,指出 `* 申请临时额度(万元)` 这种 label 在弹窗内被强制折两行(label `width: calc(6em + 24px) + word-break + overflow-wrap: anywhere`)时,红色 `*` 落在了第一行与"(万元)"之间的中部(不再与首字"申"平行)。
- 根因:弹窗 `.temporary-credit-limit-dialog .el-form-item { align-items: center }` 让 label 整体垂直居中于 input。label 高度被多行内容撑到 ~36px 时,`::before` 星号和"申"字是 label 内的两个匿名 flex items,默认 `align-items: flex-start`,但 form-item 外部的 `align-items:center` 把 label 拉到了 input 中线,导致 `*` 视觉偏移。配合 Element Plus 默认 label `inline-flex + height:32px`,多行 label 视觉反而被截一半。
- 改动(`src/views/business/temporary-credit-limit.vue` 第 808-844 行 普通 `<style>` 块):
- `.temporary-credit-limit-dialog .el-form-item { align-items: flex-start }`(取消上下居中,星号回到第一行最左)。
- `.temporary-credit-limit-dialog .el-form-item__label { height:auto !important; line-height:18px; padding-top:7px }`(用 padding 视觉补偿使单行 label 内容仍接近 input 中线:(32-18)/2=7px)。
- `.temporary-credit-limit-dialog .el-form-item.is-required .el-form-item__label::before { display:inline-block; line-height:18px; height:18px; vertical-align:middle }`(关键:`vertical-align:middle``*` 字符中心相对 baseline 上移半个 x-height,与"申"字字符中心同水平线,规避汉字和拉丁字符 baseline 差异导致的偏下)。
- 验证:未登录验证,刷新 `/business/temporary-credit-limit` 点新增应可见「*申请临时额度(万元)」label 中 `*` 与"申"字严格同基线;其它单行 label(如"项目名称 / 项目编号 / 承办部门 / 申请有效期至"等)保持 label 文字中心对齐 input 中线,无视觉回退。
- 范围:仅作用于 `temporary-credit-limit-dialog`(实际 `<el-dialog class="temporary-credit-limit-page__attachment-viewer-dialog">` 不带此 class,不会受影响);`business-crud-page` 内部 dialog 共享的 avue-form 暂不动,避免影响其它弹窗。
## 项目立项 /business/project-apply 搜索栏「项目负责人」改成手动输入
- 起因:搜索栏的「项目负责人」原本是 select(绑定 `principalUserId`,通过 `/blade-system/user/user-list` 拉用户列表),体验不好,用户希望改成手动输入姓名模糊查询。
- 改动文件:`src/option/business/project-apply.js`
- 移除 `principalUserId` 字段的 `type:'select' / search:true / dicUrl / dicFormatter / props / filterable` 等所有下拉相关配置,保留 `hide:true`(仍可作为数据传输字段)。
-`principalUserName` 字段加 `search:true / searchPlaceholder:'请输入' / searchOrder:4`,让搜索栏收集姓名字符串。
- 顺手清理无引用的 `userDicFormatter` 工具函数。
- 后端要求:`/blade-transport/project-apply/list` 需支持按 `principalUserName`(后端对应列)做 like 模糊查询;BladeX + MyBatis-Plus 标准 wrapper 对字符串字段默认 like,通常无需后端改动。
- 注意点:表格列字段未动(仍展示 `principalUserName` 的真实姓名),新增/编辑弹窗里的「项目负责人」选择器逻辑保持原样(双击 readonly 输入 + 弹窗选人)。
## /business/project-apply 新增 3 个搜索字段
-`src/option/business/project-apply.js``projectCode`(项目编号,searchOrder:8)、`customerNames`(客户名称,searchOrder:9)、`carrierNames`(下游承运商,searchOrder:10)加上 `search:true / searchPlaceholder:'请输入'`
- 三者均为普通文本列,搜索时以字符串 like 模糊查询传给 `/blade-transport/project-apply/list`,通常无需后端改动。
- 搜索栏现有 10 个字段,`createCrudOption` 已设 `searchIndex:4`,默认折叠仅显示首行 4 个(生效类型/审批状态/项目类型/项目负责人),其余(含本次新增)需点「展开」。