diff --git a/.workbuddy/memory/2026-08-06.md b/.workbuddy/memory/2026-08-06.md index 55fbaf2..77f590c 100644 --- a/.workbuddy/memory/2026-08-06.md +++ b/.workbuddy/memory/2026-08-06.md @@ -1,17 +1,18 @@ -# 2026-08-06 +# 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 16px;label 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 宽度」。 +## 运输计划调度弹窗 UX 分析 +- 完成 `/business/transport-plan` 调度弹窗的 UX 审查,对比 project-apply 页面风格 +- 输出 6 项改进方案(P0-P5),核心问题为缺少灰底(#f5f6fa)+白卡(section-card)分组设计模式 +- 所有改动集中在 `business-crud-page.vue` 一个文件 +- 待用户确认后实施第一阶段(P0灰底 + P1白卡分组) -## 将 project-apply 弹窗标准推广为「全项目通用标准」 -用户要求把 project-apply 弹窗视觉(灰底 + 分组白卡 + 标题在卡内)复制到其他页面。落地方式(已执行): -- 新增可复用组件 `src/components/section-card/main.vue`:白卡 + 标题在卡头(4px 主色竖条 + 8px 间距),支持 `title` prop 与 `#title`/`#extra` slot;已在 `src/main.js` 全局注册为 ``。 -- 在 `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 个分区全部改用 ``;`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)。 -- 注意:其他模块的**自定义弹窗**需按同样方式用 `` 包裹各组(灰底已由全局规则自动生效);如需继续推进其余模块可照此模式批量处理。 +## 已实施的改进(全部在 business-crud-page.vue) +- P0: `__dispatch-dialog` 的 `.el-dialog__body` 改为 `padding:16px; background:#f5f6fa; overflow-y:auto`(原 padding:0) +- P1: 调度弹窗三块分区用全局 `` 包裹:基本信息 / 收发货路线 / 待调度列表;"新增"按钮+汇总文字移入列表卡 `#extra` slot +- P2: `__dispatch-route-line` 由黑色实线改为 `#409EFF` 虚线 + 箭头(主色方向感) +- P3: 待调度列表纳入白卡容器(随 P1 完成) +- P4: 调度表操作列 `width` 180→220 预留扩展 +- P5: `__dispatch-footer` 增加 `border-top` + padding/margin-top 分隔 +- 旧 `__dispatch-list` / `__dispatch-top`(border-bottom/32px padding) 样式已清理;section-card 已全局注册,无需 import +- 验证:SFC 模板单独编译通过(6 处 section-card 引用配对平衡);完整 vite build 仍因预存 `xlsx` 幽灵依赖(pnpm 未装)失败,与本次改动无关 +- 注意:本项目完整 build 依赖 `xlsx@0.18.5`(package.json 有声明但 node_modules 缺失),属环境预存问题,非本次引入 diff --git a/.workbuddy/memory/MEMORY.md b/.workbuddy/memory/MEMORY.md index 188f057..1f718fc 100644 --- a/.workbuddy/memory/MEMORY.md +++ b/.workbuddy/memory/MEMORY.md @@ -1,16 +1,66 @@ # 项目长期记忆(tms-erp-web-ws / Saber3 客商模块) ## 设计约定(经用户确认的决策) -- 弹窗内多字段表单分组:**「灰色分组块 + 白色内层卡片」双色方案**(用户最终确认)。 - - 外层 `.archive-form__group`:灰底 `#f0f2f5` + 8px 圆角 + `16px 20px` 内边距,分组标题(`.dialog-section-title`,自带 4px 主色竖条)浮于灰底上。 - - 内层字段区:直接把分组内唯一的 `> .el-row` 设为白底(`#fff` + 6px 圆角 + 极淡阴影 `0 1px 2px rgba(0,0,0,.04)` + `18px 16px 4px` 内边距),形成「白卡片浮于灰底」的层次,而非逐个输入框强制白底。 - - 理由:契合 AGENTS.md「去卡片化」哲学(不嵌套 `el-card`),同时用户明确要灰底+白内容对比,全局 `.dialog-section-title` 直接复用即可。 - - 适用:新增/编辑弹窗中字段超过 ~10 个、需按业务语义分组时。 + +### 弹窗内多字段表单分组:使用全局 `` 组件(项目统一标准) + +**整体结构**: +- 整个弹窗 body 由 `src/styles/element-ui.scss` 全局 `.el-dialog__body { background: #f5f6fa; padding: 16px }` 统一灰底(无需页面再覆盖)。 +- 每个业务分组 = 一张白底卡片。用全局组件 `...`,自动渲染 4px 主色竖条 + 8px 间距的卡头与白底 body(圆角 6px + 极淡阴影),与 `loading-manage.vue` / `customer-archive.vue` 等已落地页面一致。 +- 严禁再手写 `.xxx-form__block` + `.dialog-section-title` override 拼凑卡片(项目已有 `` 标准组件)。 + +**HTML 结构**(每组三件套): +```vue + + + ... + + + +``` + +**适用**:新增/编辑弹窗中字段超过 ~10 个、需按业务语义分组时。 + +### 简单分组(仅 3 项) - 联系信息等仅 3 项的分组,可用 `el-col :span="8"` 让三项均分一行,避免 4 列网格留白。 +### 上传证件区域尺寸规范(transportCapacity 模块强制) +- **比例**:中国二代身份证标准尺寸 85.6 × 53.98 mm → 宽:高 = **1.586 : 1**(横放) +- **尺寸**:取真实身份证的 ~75% → 固定 **240 × 151 px**(1.586:1 精确:151 × 1.586 ≈ 240) +- **位置**:在 el-col 列内 `margin: 0` 左对齐显示(不再 `width: 100%` 占满整栏,也不再居中) +- **适用范围**:所有 `` 上传区,包括身份证正反面、大头照、机动车行驶证主页正/反面/副页正/反面、道路运输证、机动车登记本、船舶所有权/安全环保/国籍/最低安全配员/光船租赁/营业运输 等所有 cert 图片 +- **实现方式**:在每个页面 scoped 样式里覆盖 class-prefix 对应的 `--large` 选择器(`.driver-uploader--large` / `.vehicle-uploader--large` / `.ship-uploader--large`): + ```scss + :deep(.xxx-uploader) { display: block; } // 不再 width:100% + :deep(.xxx-uploader--large) { + display: block; + width: 240px; + margin: 0; + } + :deep(.xxx-uploader--large .el-upload), + :deep(.xxx-uploader--large.el-upload) { + width: 100%; + height: 151px; + } + ``` +- **CSS 顺序要点**:`.xxx-uploader`(特定性 0,0,1,0)必须写在 `.xxx-uploader--large`(同为 0,0,1,0)之前,源码位置决定覆盖生效。 + +### 上传图片点击放大预览(全局组件 `image-upload-field` 已实现) +- **组件**:`src/components/image-upload-field/main.vue`。原裸 `` 改为 ``。点击图片即全屏预览(滚轮缩放 / 旋转 / 下载),零额外依赖。 +- **预览与上传分离**:图片 `@click.stop` 阻止冒泡到 `el-upload`(否则会触发重传);"更换"入口(form 模式图片下方 `el-link`、card 模式 head 的 `actionText`)通过 `el-upload` 内部隐藏 `input.el-upload__input` 的 `.click()` 触发文件框。 +- **为什么用 DOM click**:Element Plus `el-upload` 仅 expose `abort/submit/clearFiles/handleStart/handleRemove`,**没有** `openFileDialog`,故用 `this.$refs.uploadRef.$el.querySelector('.el-upload__input').click()`。 +- **readonly 模式**:仅渲染 `el-image` 预览,不显示上传入口(查看档案时也能放大看证件)。 +- **z-index 注意**:务必 `preview-teleported`(预览层挂 body)+ `:z-index="3000"`,否则会被 `el-dialog` 遮罩(2000 区间)盖住。 +- **适用范围**:全仓通用组件,driver / vehicle / ship 三个页面自动获得该能力(改动一次组件即可)。 + ## 关键文件 -- 客商档案弹窗:`src/views/vehicle/customer-archive.vue`(手写 `el-form`,非 Avue option 驱动;分组结构见 `.archive-form__group`)。 -- 全局弹窗分区标题规范:`src/styles/element-ui.scss` 的 `.dialog-section-title`。 +- 通用分组白卡组件:`src/components/section-card/main.vue`(已全局注册为 ``,支持 `title` / `#title` / `#extra` slot)。 +- 弹窗灰底 body + section-card 全局样式:`src/styles/element-ui.scss`(`.el-dialog__body`、`.section-card { &__header / &__bar / &__title / &__extra / &__body }`)。 +- 司机档案弹窗:`src/views/transportCapacity/driver.vue`(手写 `el-form` + `` 4 大分组:基础身份信息 / 驾驶证信息 / 从业资格证信息 / 司机联系信息)。 +- 车辆档案弹窗:`src/views/transportCapacity/vehicle.vue`(手写 `el-form` + `` 2 大分组:基础车辆信息 / 车辆资质图片;6 张大图按身份证比例 240×151 左对齐)。 +- 船舶档案弹窗:`src/views/transportCapacity/ship.vue`(手写 `el-form` + `` 2 大分组:基础船舶信息 / 船舶证书信息;内部 6 张 cert 图片按身份证比例 240×151 左对齐;子证书分段用 `.cert-block` + border-top)。 +- 客商档案弹窗:`src/views/vehicle/customer-archive.vue`(工商信息 / 联系信息 / 财务/信用信息 / 其他信息 等分组也用 ``)。 +- 项目补录弹窗:`src/views/business/project-apply.vue`(手写 `__grid` / `__table` / `__textarea-list` 同款白卡结构,先于 `` 组件化之前落地,可视为视觉参照)。 ## 环境注意 - Vite 代理跨域:Saber3 axios 开 `withCredentials=true`,直连绝对地址后端须让 CORS `Allow-Origin` 为具体域名(不能用 `*`),否则浏览器拒绝。改 `.env`/`vite.config.mjs` 必须重启 dev。 diff --git a/src/components/image-upload-field/main.vue b/src/components/image-upload-field/main.vue index 802c128..cb01185 100644 --- a/src/components/image-upload-field/main.vue +++ b/src/components/image-upload-field/main.vue @@ -1,28 +1,57 @@