Files
shanxia2.0/docs/superpowers/specs/2026-09-08-bx-date-column-sort-design.md
T
2026-09-08 22:07:29 +08:00

6.5 KiB
Raw Blame History

报销域日期列头双三角排序

日期:2026-09-08
状态:待审阅
对齐:docs/superpowers/specs/2026-09-08-crm-date-column-sort-design.md(交互与参数一致)
Demo:docs/crm-date-column-sort-demo.html(样式 2 · 双三角)


1. 背景与目标

CRM 客户 / 报价 / 合同已落地日期列双三角整库排序。报销管理下多份列表已有列头漏斗(ColumnHeaderFilter + datetime),但尚不能按日期列升/降序。

目标

  1. 有日期列的报销相关列表:日期列头双三角,整库 asc / desc,取消后恢复现网默认序。
  2. 与 CRM 同一套交互与查询参数:sortField / sortOrder。
  3. 前端优先在现有 ColumnHeaderFilter 上扩展(报销页已直接使用该组件),避免整页改迁 CrmColFilterHeader。
  4. 后端复用 resolve_datetime_order_by + 各 list 白名单。

非目标

  • 费用项目管理、工作流配置(备用金/报销单)、发票夹管理(员工汇总)
  • 文本 / 枚举 / 数字列排序
  • 弹窗内嵌表明细日期(如费用明细 occurDate、冲抵记录子表)除非该列已是主列表带漏斗的 datetime
  • 排序状态 URL / localStorage 持久化

2. 已确认产品决策

# 决策
D1 范围:仅「有日期列」的页面;费用项目 / 工作流 / 发票夹管理跳过
D2 交互与 CRM 相同:双三角;同向再点取消;仅 datetime;空值升序前、降序后
D3 架构:扩展 ColumnHeaderFilter + 页面 useColumnSort(方案 1);不用逐列手写三角
D4 参数:sortField(列 prop)+ sortOrder(asc|desc);非法回退默认序

3. 本批页面与日期列

菜单 前端路径 日期列 prop
备用金申请 views/bx/advance/apply/index.vue applyTime
备用金审批 views/bx/advance/approve/index.vue applyTime
备用金发放 views/bx/advance/issue/index.vue applyTime、issueTime
报销申请 views/bx/reimburse/apply/index.vue applyTime
报销审批 views/bx/reimburse/approve/index.vue applyTime
支付发放冲抵 views/bx/payment/index.vue applyTime、payTime
我的发票夹 views/bx/invoice-wallet/mine/index.vue createTime(发票表 + 流水表,各一套 filter/sort)
我的申请单 views/bx/view/mine/index.vue applyTime
待我审批 views/bx/view/todo/index.vue applyTime
全部申请单(总经理) views/bx/view/all/index.vue applyTime

跳过:expense-item、workflow/advance、workflow/reimburse、invoice-wallet/admin。


4. 产品与交互

与 CRM 设计 §4 一致:

  • 列头顺序:标题 → 双三角(仅 datetime) → 漏斗。
  • 同一时刻仅一列排序;藏列若为当前排序列则清除并排序重查。
  • 过滤与排序 AND;导出与列表同一套 sort 参数(若该页有导出且走同一 query builder)。

「申请时间」展示字段 applyTime 在后端多映射 create_time:排序白名单须 applyTime → create_time(或实体等价列),禁止按不存在的 apply_time 列动态拼接。


5. 架构

5.1 前端 · ColumnHeaderFilter

在 column-header-filter/index.vue 的漏斗按钮旁:

  • inject('crmColumnSort')(与 CRM 同 key,避免双套 inject;可选再兼容 columnSort)。
  • showSort = Boolean(sortApi && type === 'datetime')。
  • 样式复用已有 .col-header-sort-pair / .col-header-sort-btn。

CrmColFilterHeader 已具备三角,行为不变。未 provide 排序的页面(含跳过页)不显示三角。

5.2 前端 · 各列表页

const { setSort, clearSort, isSortActive, sortField, sortOrder, toQueryParams: toSortQueryParams, watchVisibleColumns: watchSortVisibleColumns } =
  useColumnSort({ onChange: () => { /* page=1; reload */ } })

provide('crmColumnSort', { setSort, clearSort, isSortActive, sortField, sortOrder })
// list/export params: ...toSortQueryParams()
// watchSortVisibleColumns(visibleFilterProps)

我的发票夹:发票 Tab / 流水 Tab 可各用一套 useColumnSort,inject key 用默认 + 可选第二 key,或切换 Tab 时共用一套(实现时选改动更小者;须保证当前可见表的 datetime 列能驱动正确 list API)。

5.3 后端

复用 backend/app/services/crm/list_sort.py 的 resolve_datetime_order_by(路径名含 crm,本批不强制搬家;若后续统一可迁到 app/services/list_sort.py,非本批必做)。

各 list(及共用路径的 export)增加可选 sortField / sortOrder,白名单示例:

域 prop → Column
备用金申请/审批/发放主列表 applyTime → BxAdvanceApply.create_time;发放另加 issueTime → 实际发放时间列(以 model 为准,如 issue_time / pay_time)
报销申请/审批 applyTime → BxReimburseApply.create_time
支付发放冲抵 applyTime → 单据创建/申请时间列;payTime → 处理时间列(以现网字段为准)
视图 mine/todo/all 按 biz 分支映射到 advance/reimburse 的 create_time,或统一视图查询的申请时间表达式
我的发票夹 createTime → 发票/流水表的 create_time

非法 sortField → 现网默认(一般为 create_time DESC)。


6. 测试要点

  1. 报销申请:applyTime 升/降/取消;与漏斗日期段 AND;换页保持序。
  2. 备用金发放:issueTime 仅在已发放可见列时可用;藏列清排序。
  3. 支付:payTime 在已处理 Tab。
  4. 我的申请单 / 待我审批 / 全部:备用金与报销单混合列表排序正确。
  5. 我的发票夹:上传时间/流水时间排序打整库。
  6. 费用项目、工作流、发票夹管理:无双三角。
  7. 抓包非法 sortField → 默认序、不 500。

7. 风险与后续

  • 风险:视图页(mine/todo/all)若 SQL 为 union/多表,白名单须落到真实可排序表达式,避免只改前端。
  • 风险:applyTime 与 DB create_time 映射遗漏导致排序无效或报错——实现时对照 schema validation_alias="create_time"。
  • 后续:发票夹管理若补日期列再接线;可将 list_sort 抽到中性路径。

8. 文档

  • 本设计:docs/superpowers/specs/2026-09-08-bx-date-column-sort-design.md
  • CRM 对照:docs/superpowers/specs/2026-09-08-crm-date-column-sort-design.md