From 3fa1f8e312b0da1d10563d968a7d53213e87f215 Mon Sep 17 00:00:00 2001 From: zlwu Date: Sun, 6 Sep 2026 07:32:11 +0800 Subject: [PATCH] docs: add design for reimburse apply server-side column filters. Co-authored-by: Cursor --- ...urse-apply-server-column-filters-design.md | 217 ++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 docs/superpowers/specs/2026-09-06-reimburse-apply-server-column-filters-design.md diff --git a/docs/superpowers/specs/2026-09-06-reimburse-apply-server-column-filters-design.md b/docs/superpowers/specs/2026-09-06-reimburse-apply-server-column-filters-design.md new file mode 100644 index 000000000..6ba98b697 --- /dev/null +++ b/docs/superpowers/specs/2026-09-06-reimburse-apply-server-column-filters-design.md @@ -0,0 +1,217 @@ +# 报销申请:列头漏斗整库服务端筛选 + +**日期**:2026-09-06 +**状态**:待审阅 +**范围(本轮)**:`web-admin` 【报销申请】`src/views/bx/reimburse/apply/index.vue` + 后端 `GET /reimburses/my`(及同页导出) +**后续**:CRM 及其他列表按本标杆推广(不在本轮实现) + +--- + +## 1. 背景与问题 + +【报销申请】已落地 Excel 风格列头漏斗(`ColumnHeaderFilter` + `useClientColumnFilters`),但过滤仅作用于**当前页已加载行**,不传给后端。换页后条件只作用于新页;文本列「本页可选值」也无法代表全库。 + +目标:改为**整库服务端筛选**,并统一四类列交互,作为后续全站列表/弹窗列表推广的标杆。 + +--- + +## 2. 产品决策(已确认) + +### 2.1 检索入口 + +- **去掉**顶部 `filter-block`。 +- 检索只走:**列头漏斗** + **工具栏快捷搜索**。 +- 多列条件之间 **AND**;快捷搜索 `keyword` 与列条件 **AND**。 + +### 2.2 原顶部条件迁移 + +| 规则 | 说明 | +|------|------| +| 有列则挂漏斗 | 原顶部有过的检索字段,列表必须有对应数据列;若无,**先补列再加漏斗**。 | +| 默认值迁移 | 原顶部筛若有默认值,写入对应列漏斗的**初始生效条件**;首屏即按该条件请求。漏斗按钮呈 active。 | +| 本页现状 | 【报销申请】原顶部字段(单号/费用项目/状态/申请时间)均已有列;`filterForm` 初始均为空,**无默认值可迁**。 | + +### 2.3 列类型交互 + +| 类型 | 适用列(本页) | 交互 | +|------|----------------|------| +| `datetime` | 申请时间 | 开始日期 + 结束日期,闭区间(含起止当天) | +| `number` | 报销金额(元) | 运算符(介于/等于/大于/…)+ 单值或区间 | +| `enum` | 状态 | 固定选项多选勾选(待提交/审批中/审批通过/审批驳回) | +| `text`(新语义) | 报销单号、报销标题、费用项目、当前节点 | **单行输入模糊检索**(废除「本页可选值」勾选) | + +勾选列、序号列不加漏斗。 + +### 2.4 列显示与筛选绑定 + +**隐藏某列时:自动清空该列已生效的漏斗条件,并立即重查。** + +- 再显示该列:**不**自动恢复默认值或原条件;漏斗为空,需用户重设。 +- 「重置列显示」恢复默认可见列时:**一并恢复**列漏斗的初始默认值(与重置语义一致)。本页无默认,影响为清空全部列条件即可。 +- 理由:看不见的列不允许仍挂筛选,避免「无故变少」且无法从列头改条件。 + +### 2.5 清空与导出 + +- 「清空列过滤」:清空全部列条件并重查;**不**清快捷搜索(快捷搜索自带清空)。 +- 导出(`exportMy`):与当前列表同一套 `keyword` + 列条件参数。 + +### 2.6 不在本轮 + +- CRM / 其他 BX 列表、弹窗内列表推广。 +- 将约定写入 OpenSpec 基线(可在标杆验收后另开变更)。 + +--- + +## 3. 架构方案 + +**选定:扩展现有 GET 扁平查询参数**(与已有 `applyDateFrom` / `applyDateTo` 风格一致)。 + +备选未选: + +- 单一 `columnFilters` JSON:灵活但本页过重。 +- 改 POST 查询体:与现网列表 GET 习惯不一致。 + +前端引入(或演进)`useServerColumnFilters`:管理列条件 state、`toQueryParams()`、隐藏列清条件、触发 `page=1` 重查。表格直接绑定服务端 `rows`,**不再**对当前页做二次 `filter`。 + +保留近期修复:日期面板 teleport 导致 popover 误关时的抑制关闭逻辑。 + +--- + +## 4. API 约定 + +### 4.1 `GET /api/.../reimburses/my` + +在现有分页、租户、数据权限、软删之上增加/明确: + +| 参数 | 类型 | 说明 | +|------|------|------| +| `page` / `pageSize` | int | 已有 | +| `keyword` | string | **仅工具栏快捷搜索**:单号 / 标题 / 费用项目名联合模糊(保持现网 OR 语义) | +| `applyDateFrom` / `applyDateTo` | `YYYY-MM-DD` | 申请时间(`create_time`)闭区间;已有 | +| `applyCode` | string | 报销单号模糊 | +| `title` | string | 报销标题模糊 | +| `expenseName` | string | 费用项目模糊;复用 `build_expense_name_condition` | +| `amountOp` | string | `between` \| `eq` \| `gt` \| `gte` \| `lt` \| `lte` | +| `amount` | string/number | 单值运算时使用 | +| `amountMin` / `amountMax` | string/number | `between` 时使用;只填一端则只约束一端 | +| `statusIn` | string | 状态多选,逗号分隔,如 `draft,pending`;空则不按状态筛 | +| `currentNode` | string | 当前节点名模糊 | + +兼容:若仍收到单值 `status`,可视为仅含该值的 `statusIn`。前端本页以 `statusIn` 为准。 + +列表 `total` 必须反映过滤后全量条数。 + +### 4.2 导出 + +`POST /reimburses/my/export`(或现有导出体)须接受与列表相同的过滤字段,过滤逻辑与 list **共用同一拼装函数**,避免漏参。 + +### 4.3 校验 + +- 日期:`from > to` 由前端拦截;后端可防御性忽略或 400。 +- 金额:`between` 且 min>max 前端拦截;非法 `amountOp` 后端忽略或 400。 +- 所有业务查询继续强制 `tenant_no` + 数据权限;不信任客户端改租户。 + +--- + +## 5. 前端改造要点 + +### 5.1 `ColumnHeaderFilter` + +- `text`:单行输入 + 确定/取消/清空本列;文案提示「模糊匹配」。 +- `enum` / `number` / `datetime`:保持面板能力;确定后由页面触发服务端查询。 +- 继续处理日期选择器与 popover 的误关问题。 + +### 5.2 `useServerColumnFilters`(建议新建) + +职责: + +- `filters`:已生效条件;`initialFilters` 支持默认值。 +- `toQueryParams()` → 请求/导出。 +- `setFilter` / `clearColumn` / `clearAll` → 回调 `onChange` → 页面 `search(1)`。 +- `onColumnHidden(prop)`:清空该 prop 条件并 `onChange`。 +- `isFilterActive(prop)`:驱动漏斗 active 样式。 +- 与 `useClientColumnFilters` 并存一段时间;本页切换到服务端版。客户端版可留给纯本地小表,或后续废弃。 + +### 5.3 页面 `reimburse/apply/index.vue` + +- 删除 `filter-block` 与 `filterForm` 驱动的顶部搜索。 +- `useServerPaged` 的请求参数 = 快捷搜索 + `toQueryParams()`。 +- 列 `v-if="isColumnVisible(...)"` 变为隐藏时调用 `onColumnHidden`。 +- 工具栏保留「清空列过滤」(`hasActiveFilters` 时显示)。 +- 快捷搜索清空/搜索不自动清列条件。 + +### 5.4 本页列定义一览 + +| prop | label | type | 默认可见 | 初始条件 | +|------|-------|------|----------|----------| +| applyTime | 申请时间 | datetime | 是 | 无 | +| applyCode | 报销单号 | text | 是(固定列) | 无 | +| title | 报销标题 | text | 是 | 无 | +| expenseName | 费用项目 | text | 是 | 无 | +| amount | 报销金额(元) | number | 是 | 无 | +| status | 状态 | enum | 是 | 无 | +| currentNode | 当前节点 | text | 否(现有 defaultVisible: false) | 无 | + +`currentNode` 默认隐藏:首屏无该列条件。用户打开列后再筛。若将来为该列配置默认条件,则须默认可见,或首屏强制带参且列默认可见(遵循「有条件则列应可操作」;本设计选「藏列清条件」,故默认条件列必须默认可见)。 + +--- + +## 6. 数据流 + +```text +进入页 + → 应用 initialFilters(本页为空) + → GET /reimburses/my (page, pageSize, keyword?, column params?) + +列漏斗确定 + → 更新 filters → page=1 → 同上 GET + +藏列 + → 若该列有生效条件:删除该条件 → 重查 + → 再显示:条件为空 + +清空列过滤 + → filters={} → 重查(保留 keyword) + +导出 + → 与当前列表相同的 keyword + column params +``` + +--- + +## 7. 验收标准 + +1. 页面无顶部筛选区;有列头漏斗 + 工具栏快捷搜索。 +2. 日期/数字/状态/文本四类行为符合 §2.3,且过滤结果跨页、跨 pageSize 一致;`total` 正确。 +3. 换页不丢失已生效列条件与快捷搜索。 +4. 隐藏带条件的列 → 该条件消失且列表刷新;再显示后漏斗为空。 +5. 「重置列显示」后列可见性恢复默认,列漏斗恢复为 initial(本页即全空)。 +6. 导出 Excel 与当前筛选结果一致(在权限范围内)。 +7. 租户隔离与「我的申请」数据范围与改造前一致。 +8. 选择申请时间起止时,过滤弹窗不因点选日期面板而提前关闭。 + +--- + +## 8. 风险与注意 + +- `keyword` 与列上 `applyCode`/`title`/`expenseName` 同时存在时为 AND,可能比旧「顶部单号」更严;属预期。 +- 费用项目展示可能来自明细多行,服务端模糊须与现 `build_expense_name_condition` 一致,避免只匹配主表名。 +- `statusIn` 多选后,旧单选 `status` 调用方需兼容。 +- 推广 CRM 时复用参数命名与 `useServerColumnFilters`,按页补齐缺列与后端字段。 + +--- + +## 9. 实现顺序(建议) + +1. 后端:抽取/扩展 my 列表与导出的过滤拼装;支持上表参数。 +2. 前端 composable + `ColumnHeaderFilter` 文本模式改造。 +3. 改造 `apply/index.vue`:去顶部筛、接线服务端列筛、藏列清条件。 +4. 手工验收 §7;必要时补 API 单测覆盖 amount/statusIn/日期组合。 + +--- + +## 10. 修订记录 + +| 日期 | 说明 | +|------|------| +| 2026-09-06 | 初稿:整库服务端列筛;去顶部筛;藏列清条件;四类交互;本页无默认值 |