6.5 KiB
报销域日期列头双三角排序
日期: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),但尚不能按日期列升/降序。
目标
- 有日期列的报销相关列表:日期列头双三角,整库
asc/desc,取消后恢复现网默认序。 - 与 CRM 同一套交互与查询参数:
sortField/sortOrder。 - 前端优先在现有
ColumnHeaderFilter上扩展(报销页已直接使用该组件),避免整页改迁CrmColFilterHeader。 - 后端复用
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. 测试要点
- 报销申请:
applyTime升/降/取消;与漏斗日期段 AND;换页保持序。 - 备用金发放:
issueTime仅在已发放可见列时可用;藏列清排序。 - 支付:
payTime在已处理 Tab。 - 我的申请单 / 待我审批 / 全部:备用金与报销单混合列表排序正确。
- 我的发票夹:上传时间/流水时间排序打整库。
- 费用项目、工作流、发票夹管理:无双三角。
- 抓包非法
sortField→ 默认序、不 500。
7. 风险与后续
- 风险:视图页(mine/todo/all)若 SQL 为 union/多表,白名单须落到真实可排序表达式,避免只改前端。
- 风险:
applyTime与 DBcreate_time映射遗漏导致排序无效或报错——实现时对照 schemavalidation_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