2026-08-11-oa-approval-task-filter-design.md 7.2 KB

OA 审批任务中心检索区设计

模块: OA 审批 · 待办 / 已办 / 我发起的 / 抄送我的
日期: 2026-08-11
状态: 已实现
UI Demo: docs/demos/oa-approval-task-filter-demo.html
决策记录:

  • 实现方案: 方案 B(后端扩展 list_tasks 查询参数 + 四页各自加 filter-block)
  • 交互: 即时检索(watchDebounced 300ms)+ 保留「搜索」「重置」
  • 暂不抽公共筛选组件(方案 C 可后续再做)

1. 背景与目标

四页任务列表(pending / done / mine / cc)目前仅分页拉取,抄送页仅有「阅读状态」筛选。用户需要在列表上方按流程名称、申请时间、流程状态等条件检索,并在输入/选择条件后自动触发查询,无需依赖点击「搜索」才能看到结果。

成功标准:

  • 四页均具备 Fresh Mint 规范的 filter-block 检索区
  • 条件变更防抖 300ms 后自动请求;点「搜索」立即请求;「重置」清空后请求
  • 筛选在服务端分页前生效,total 与列表一致

2. 范围

2.1 页面与字段

页面 路由视图 流程名称 申请人 申请时间 流程状态 阅读状态
待办中心 views/oa-approval/pending/index.vue ✓ ✓ ✓ ✓ —
已办中心 views/oa-approval/done/index.vue ✓ ✓ ✓ ✓ —
我发起的 views/oa-approval/mine/index.vue ✓ — ✓ ✓ —
抄送我的 views/oa-approval/cc/index.vue ✓ ✓ ✓ ✓ ✓(已有)

字段语义:

  • 流程名称: 模糊匹配应用名 oa_app.app_name;同时允许匹配实例标题 oa_instance.title
  • 申请人: 模糊匹配发起人 sys_user.nick_name(与 _user_name_map / 列表列 initiatorUserName 同源)
  • 申请时间: 日期区间,过滤实例 create_time(与列表列 applyTime 同源)
  • 流程状态: 精确匹配 oa_instance.status
  • 阅读状态: 仅抄送,沿用现有 readStatus=unread|read|all

2.2 流程状态下拉枚举

与 oa_instance.status 注释及引擎终态标签一致(不含任务态 approved / pending 等):

value 展示文案
"" 全部
running 进行中
completed 已完成
rejected 已拒绝
returned 已打回
cancelled 已撤销

2.3 非目标

  • 不做前端对当前页数据的假过滤
  • 本迭代不抽取跨页公共筛选组件
  • 不改变列表列、操作列、详情跳转等既有行为
  • 不改动待办数 / 抄送未读角标统计接口的过滤语义(角标仍为全量未读/待办计数)

3. 交互设计

对齐 Fresh Mint §5 与现有列表页(单位列表、订单列表、展馆预约、抄送我的):

  1. 结构: panel-top → filter-block →(抄送保留工具栏)→ list-body list-wrap → 分页
  2. 筛选区: filter-form + 四列 filter-grid + filter-actions-row
  3. 操作按钮: 重置(btn-ghost + RefreshLeft)+ 搜索(btn-main + Search)
  4. 即时检索: 对 searchForm(及日期区间)使用 watchDebounced(..., { debounce: 300, deep: true });触发时将 page 置为 1 再 load
  5. 搜索按钮: 清除等待中的防抖(若有)并立即 load(页码回 1)
  6. 重置: 恢复默认值(抄送 readStatus 默认仍为 unread;其余为空),页码回 1 并 load
  7. 文本框支持 clearable;日期使用 el-date-picker type="daterange",value-format="YYYY-MM-DD"

参考 Demo: docs/demos/oa-approval-task-filter-demo.html


4. API 设计

4.1 端点

继续使用:

GET {OA_BASE}/tasks/{kind}

kind ∈ { pending, done, mine, cc }

4.2 新增 / 沿用 Query 参数

参数 必填 说明
appName 否 流程名称关键词,trim 后非空才参与 LIKE
initiatorName 否 申请人姓名关键词;mine 可不传
applyTimeFrom 否 申请日起始日 YYYY-MM-DD(含当日 00:00:00)
applyTimeTo 否 申请日结束日 YYYY-MM-DD(含当日 23:59:59)
instanceStatus 否 实例状态精确匹配;不在 §2.2 枚举内的值视为未传(不加状态条件)
readStatus 否 仅 cc,现有行为不变
page / pageSize 否 现有行为不变

响应形状不变: { list, total }。

4.3 后端实现要点(list_tasks)

  • mine: 以 OaInstance 为主查询;按条件 join OaApp / SysUser(发起人)过滤;order_by create_time DESC 后分页
  • pending / done / cc: 以 OaTask 为主查询(既有 kind 条件保留);通过 instance_id join OaInstance,再按需 join OaApp / 发起人 SysUser;过滤后对任务分页
  • 所有业务查询继续带 tenant_no + del_flag=0
  • 空字符串参数视为未传

5. 前端改动清单

文件 改动
web-admin/src/api/oaApproval.ts fetchOaTasks params 扩展上述字段并透传
web-admin/src/views/oa-approval/pending/index.vue 增加筛选区 + 即时检索
web-admin/src/views/oa-approval/done/index.vue 同上
web-admin/src/views/oa-approval/mine/index.vue 同上(无申请人字段)
web-admin/src/views/oa-approval/cc/index.vue 在现有阅读状态筛选上扩展字段 + 改为即时检索

建议四页共用同一套状态文案/选项常量(可在各页内联小常量或抽到 oa-approval 下小 util;本设计不强制新文件)。


6. 后端改动清单

文件 改动
backend/app/api/oa_approval.py list_oa_tasks 增加 Query,传入 list_tasks
backend/app/services/oa_engine.py list_tasks 增加过滤参数并在分页前应用
backend/tests/test_oa_engine.py 或新测文件 覆盖名称 / 时间 / 状态 / 抄送组合过滤

无表结构变更,无需新 SQL DDL。


7. 测试计划

  1. 后端单测: 各 kind 在带 appName / initiatorName / 时间区间 / instanceStatus 时结果与 total 正确;cc + readStatus 与新条件可组合
  2. 前端手测: 四页输入流程名即时刷新;改状态下拉即时刷新;点搜索无额外延迟感;重置恢复默认;抄送默认仍为未读;分页切换后改条件回到第 1 页
  3. 回归: 无筛选时列表与改前一致;待办/抄送角标行为不变

8. 风险与注意点

  • 申请人模糊检索使用 SysUser.nick_name(与 _user_name_map 一致),避免「筛得到但展示名对不上」
  • applyTimeTo 须包含结束日全天,避免只比较日期字符串导致漏当日下午数据
  • 即时检索会增加请求频率,300ms 防抖与现有业务页一致;连续输入以最后一次为准
  • 待办列表中实例多为 running,「流程状态」在待办页仍保留以支持边界数据与体验统一

9. 验收对照

  • Demo 视觉结构在四页落地(filter-block / 四列栅格 / 重置+搜索)
  • 条件变更 300ms 内自动出结果;搜索立即;重置清空
  • 服务端过滤 + 分页 total 正确
  • 抄送阅读状态行为不回退
  • 相关后端测试通过