|
|
@@ -0,0 +1,117 @@
|
|
|
+# 报价单列表 · 可配置列统计行
|
|
|
+
|
|
|
+**日期:** 2026-08-16
|
|
|
+**状态:** 待实现
|
|
|
+**范围:** `web-admin` 报价单管理主列表(`/#/crm/quote`)
|
|
|
+**非目标:** 后端聚合、跨页统计、`ListTable` 通用能力、展开行产品子表、其它业务列表
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 1. 背景与目标
|
|
|
+
|
|
|
+客户希望在【报价单管理】列表底部增加一行统计区:默认无数据;用户按列选择统计方式后,对**当前页**数据即时计算并展示。统计方式支持求和、平均、最大值、最小值。
|
|
|
+
|
|
|
+后续其它列表将**逐页单独改造**(不先做全站通用组件),本设计仅覆盖报价单页,逻辑可放在报价单目录内小文件,便于以后复制或再抽离。
|
|
|
+
|
|
|
+## 2. 已确认决策
|
|
|
+
|
|
|
+| 项 | 决策 |
|
|
|
+|---|---|
|
|
|
+| 数据范围 | 仅当前页 `quoteList`,前端计算 |
|
|
|
+| 交互 | 点击合计行对应单元格 → 下拉选择统计方式 → 同格显示结果 |
|
|
|
+| 列范围 | 所有业务列均可配置(统一交互) |
|
|
|
+| 无法计算 | 显示 `-`,不报错 |
|
|
|
+| 持久化 | `localStorage`,仅当前浏览器 |
|
|
|
+| 展示格式 | 前缀 + 数值,如 `求和 12,345.00`、`平均 -` |
|
|
|
+| 推广策略 | 一页一改;本次只改报价单 |
|
|
|
+
|
|
|
+## 3. 界面与交互
|
|
|
+
|
|
|
+### 3.1 位置
|
|
|
+
|
|
|
+主表 `ListTable`(`table-key="crm-quote"`)与分页条之间,增加**自定义合计行**(不使用 Element Plus `show-summary`,因其难以承载可点选下拉)。
|
|
|
+
|
|
|
+```
|
|
|
+┌─────────────────────────────────────┐
|
|
|
+│ 筛选 / 工具栏 │
|
|
|
+├─────────────────────────────────────┤
|
|
|
+│ ListTable 主表(当前页) │
|
|
|
+├─────────────────────────────────────┤
|
|
|
+│ 自定义列统计行(可点选) │
|
|
|
+├─────────────────────────────────────┤
|
|
|
+│ 分页 │
|
|
|
+└─────────────────────────────────────┘
|
|
|
+```
|
|
|
+
|
|
|
+### 3.2 单元格行为
|
|
|
+
|
|
|
+- **展开列、勾选列**:固定空白,不可配置。
|
|
|
+- **其余业务列**(含列设置显隐控制的列):与主表可见列同步;隐藏列不展示对应统计格。
|
|
|
+- **未选择 / 选「无」**:单元格为空(可点击以打开下拉)。
|
|
|
+- **已选择**:显示 `{方式标签} {结果}`,例如 `求和 12,345.00`、`最大值 张三`、`平均 -`。
|
|
|
+- **下拉选项**:无、求和、平均、最大值、最小值(文案固定为上述中文)。
|
|
|
+
|
|
|
+### 3.3 视觉
|
|
|
+
|
|
|
+对齐 Fresh Mint 合计行约定(见 `docs/web-admin-ui-spec-fresh-mint.md`):浅绿背景(`--primary-bg` / 等价 token)、主色顶边、字重加粗;不引入新的高饱和色。
|
|
|
+
|
|
|
+横向滚动时,合计行应与主表列对齐(实现上采用与主表相同的列定义顺序与宽度策略,避免错位)。
|
|
|
+
|
|
|
+## 4. 计算规则
|
|
|
+
|
|
|
+对当前页每一行的该列取值进行聚合;空值、无法参与的值按下列规则跳过或导致 `-`。
|
|
|
+
|
|
|
+| 方式 | 规则 |
|
|
|
+|---|---|
|
|
|
+| 无 | 不展示结果 |
|
|
|
+| 求和 | 仅对可解析为有限数字的值求和;若本列没有任何有效数字 → `-` |
|
|
|
+| 平均 | 对有效数字求算术平均(分母为有效数字个数);无有效数字 → `-` |
|
|
|
+| 最大值 | 若存在有效数字,取数值最大;否则对非空字符串做字典序最大;皆无 → `-` |
|
|
|
+| 最小值 | 对称于最大值 |
|
|
|
+
|
|
|
+说明:
|
|
|
+
|
|
|
+- 「可解析为有限数字」:去掉常见金额前缀/千分位后 `Number` 为有限数(含 0)。
|
|
|
+- 折扣率等带 `%` 的展示值:从原始行字段取数(如 `discountRate`),不要从已格式化 DOM 文案解析。
|
|
|
+- `finalAmount` 等与列表展示一致:使用与列表相同的取值函数(如 `getQuoteFinalAmount`),再参与聚合。
|
|
|
+- 状态、客户名等非数值列:求和/平均通常为 `-`;最大/最小可对字符串生效。
|
|
|
+
|
|
|
+金额类结果的数字部分格式与列表金额展示习惯一致(千分位等);前缀与数字之间一个空格。非金额数值(如查看次数)按普通数字格式化即可。
|
|
|
+
|
|
|
+## 5. 本机持久化
|
|
|
+
|
|
|
+- **Storage key:** `crm-quote-column-stats`
|
|
|
+- **Value:** JSON 对象,`{ [columnProp: string]: 'sum' | 'avg' | 'max' | 'min' }`
|
|
|
+- 选「无」或清空时删除该 prop 的键。
|
|
|
+- 进入页面时读取;切换统计方式时写入。
|
|
|
+- 换页 / 刷新后:恢复各列已选方式,并对**新的当前页数据**重新计算。
|
|
|
+
|
|
|
+不与账号、租户、后端同步。
|
|
|
+
|
|
|
+## 6. 实现边界(代码落点)
|
|
|
+
|
|
|
+| 位置 | 职责 |
|
|
|
+|---|---|
|
|
|
+| `web-admin/src/views/crm/quote/quoteListColumnStats.ts`(新建) | 类型、聚合计算、展示文案、localStorage 读写 |
|
|
|
+| `web-admin/src/views/crm/quote/QuoteListPage.vue`(修改) | 渲染合计行、绑定列显隐与当前页数据、点选下拉 |
|
|
|
+
|
|
|
+不修改:
|
|
|
+
|
|
|
+- `ListTable` 组件
|
|
|
+- 后端 API / SQL
|
|
|
+- 展开行内产品子表
|
|
|
+- 报销/地磅等现有只读 `show-summary` 页
|
|
|
+
|
|
|
+## 7. 验收要点
|
|
|
+
|
|
|
+1. 进入报价单列表:合计行存在,默认各业务格为空。
|
|
|
+2. 对金额列选「求和」:显示 `求和 …`,数值等于当前页该列之和。
|
|
|
+3. 对客户名称选「求和」:显示 `求和 -`;选「最大值」:显示字典序最大的非空客户名(有数据时)。
|
|
|
+4. 切换分页:已选方式保留,数值按新页重算。
|
|
|
+5. 刷新浏览器:方式从 localStorage 恢复。
|
|
|
+6. 列设置隐藏某列:合计行对应格消失;再显示后若曾配置过方式则恢复展示。
|
|
|
+7. 展开列 / 勾选列无下拉、无统计文案。
|
|
|
+
|
|
|
+## 8. 后续(本设计之外)
|
|
|
+
|
|
|
+其它列表需要同类能力时,复制本页模式单独接入;若多页稳定后再评估是否抽公共组件。不在本变更范围。
|