第57篇:多条件审批过滤引擎

概述

在企业级审批系统中,随着审批数据的增长,用户需要一种高效、灵活的方式来筛选和查找审批记录。星办OA 在 ApprovalDomain.ts 中实现了 filterApprovals 过滤引擎,支持三维过滤逻辑:视图过滤、类型过滤和关键词匹配。本文将深入分析过滤引擎的实现原理、三维过滤的协作机制以及如何通过 ApprovalView 实现视图切换。

一、过滤引擎的核心函数

1.1 filterApprovals 完整实现

export function filterApprovals(approvals: ApprovalRequest[], view: string,
  type: string, keyword: string): ApprovalRequest[] {
  let normalizedKeyword: string = keyword.trim().toLowerCase()
  let result: ApprovalRequest[] = []

  approvals.forEach((item: ApprovalRequest) => {
    // 第一维:视图过滤
    let inView: boolean = false
    if (view === ApprovalView.PENDING) {
      inView = item.pendingForMe && item.status === ApprovalStatus.PENDING
    } else if (view === ApprovalView.MINE) {
      inView = item.isMine
    } else {
      inView = item.handledByMe
    }

    // 第二维:类型过滤
    let inType: boolean = type === '全部' || item.type === type

    // 第三维:关键词匹配
    let searchable: string = `${item.id} ${item.title} ${item.applicant}`.toLowerCase()
    let inKeyword: boolean = normalizedKeyword.length === 0 || searchable.includes(normalizedKeyword)

    // 三维条件同时满足时加入结果集
    if (inView && inType && inKeyword) {
      result.push(item)
    }
  })

  return result
}

1.2 函数签名分析

filterApprovals(
  approvals: ApprovalRequest[],  // 完整审批列表
  view: string,                  // 视图筛选(待我审批/我发起的/已处理)
  type: string,                  // 类型筛选(全部/请假/报销/出差/...)
  keyword: string                // 关键词搜索
): ApprovalRequest[]

参数设计原则: 过滤引擎采用纯函数设计,输入完整的审批列表和三个筛选条件,输出过滤后的子集。这种设计保证了函数的可测试性和可预测性——相同的输入必定产生相同的输出。

二、三维过滤逻辑详解

2.1 第一维:视图过滤

视图过滤是最高优先级的筛选维度,它决定了用户从哪个视角查看审批数据:

let inView: boolean = false
if (view === ApprovalView.PENDING) {
  inView = item.pendingForMe && item.status === ApprovalStatus.PENDING
} else if (view === ApprovalView.MINE) {
  inView = item.isMine
} else {
  inView = item.handledByMe
}

三个视图的筛选条件:

视图 筛选条件 业务含义

待我审批(PENDING) pendingForMe === truestatus === PENDING 当前等待我审批的请求
我发起的(MINE) isMine === true 我提交的所有请求
已处理(HANDLED) handledByMe === true 我已经处理过的请求

视图切换的业务场景:

  • 待我审批视图:一个审批人每天登录系统后,首先查看的是"待我审批"视图,了解自己需要处理哪些审批请求。
  • 我发起的视图:申请人提交审批后,通过"我发起的"视图追踪申请进度,查看是已通过、已驳回还是仍在审批中。
  • 已处理视图:审批人回顾自己处理过的历史记录,查看过往的审批决策。

2.2 第二维:类型过滤

类型过滤是第二维筛选,在视图筛选的基础上进一步缩小范围:

let inType: boolean = type === '全部' || item.type === type

类型过滤的逻辑: 当选择"全部"时,不过滤类型,返回视图中所有类型的审批记录;当选择具体类型(如"报销")时,只返回该类型的审批记录。

6 种审批类型的过滤场景:

筛选类型 业务场景

全部 查看所有类型的审批概览
请假 集中处理请假申请
报销 财务人员集中处理报销
出差 出差审批集中管理
采购 采购审批专项处理
加班 加班审批统一管理
用印 用印审批专项处理

2.3 第三维:关键词匹配

关键词匹配是最细粒度的筛选维度,通过全文搜索实现精确查找:

let searchable: string = `${item.id} ${item.title} ${item.applicant}`.toLowerCase()
let inKeyword: boolean = normalizedKeyword.length === 0 || searchable.includes(normalizedKeyword)

搜索范围分析: 搜索覆盖了三个字段:

  • 审批单号(id:如搜索"A20260824001"可以精确匹配到某条审批
  • 审批标题(title:如搜索"报销"可以匹配所有标题中包含"报销"的审批
  • 申请人(applicant:如搜索"周婷"可以找出该员工提交的所有审批

关键词匹配的模糊搜索机制:

// 关键词标准化
let normalizedKeyword: string = keyword.trim().toLowerCase()

// 搜索文本标准化
let searchable: string = `${item.id} ${item.title} ${item.applicant}`.toLowerCase()

// 模糊匹配
let inKeyword: boolean = normalizedKeyword.length === 0 || searchable.includes(normalizedKeyword)

模糊匹配的特点:

  • 大小写不敏感:搜索关键词和搜索文本都转换为小写,确保大小写不影响搜索结果
  • 部分匹配:使用 includes 方法实现部分匹配,如搜索"李"可以匹配"李明"
  • 首尾空格去除:使用 trim() 去除关键词首尾空格,避免因空格导致的匹配失败
  • 空关键词跳过:当关键词为空时,跳过关键词过滤,提高搜索效率

三、三维过滤的协作机制

3.1 过滤流水线

三维过滤使用严格的 AND 逻辑串联:

inView && inType && inKeyword

这意味着一条审批记录必须同时满足三个条件才会出现在结果集中。这种设计的优势是:

  • 精确性:三个维度层层递进,逐步缩小范围,最终找到用户需要的记录
  • 可预测性:用户添加的每个条件都会进一步缩小结果集,行为符合直觉
  • 组合灵活性:用户可以自由组合条件,如"待我审批的报销申请"或"我发起的包含'上海'的审批"

3.2 过滤场景示例

场景一:查看待审批的报销申请

filterApprovals(approvals, ApprovalView.PENDING, '报销', '')
// 结果:pendingForMe=true && status=PENDING && type=报销
// 匹配:报销 - 客户拜访交通费报销

场景二:搜索我发起的、包含"显示器"的审批

filterApprovals(approvals, ApprovalView.MINE, '全部', '显示器')
// 结果:isMine=true && title.includes('显示器')
// 匹配:采购 - 产品部显示器采购

场景三:搜索周婷提交的待审批申请

filterApprovals(approvals, ApprovalView.PENDING, '全部', '周婷')
// 结果:pendingForMe=true && status=PENDING && applicant.includes('周婷')
// 匹配:报销 - 客户拜访交通费报销

四、ApprovalView 视图定义

4.1 视图常量

export class ApprovalView {
  static readonly PENDING: string = '待我审批'
  static readonly MINE: string = '我发起的'
  static readonly HANDLED: string = '已处理'
}

ApprovalView 使用静态常量定义三个视图名称,字符串常量既是视图的标识符,也是 UI 上显示的文字。这种设计简化了视图名称的管理,避免了名字和标识符之间的映射。

4.2 视图在 Store 中的使用

ApprovalStore 中提供了三个预定义的视图查询方法:

getPendingApprovals(): ApprovalRequest[] {
  return filterApprovals(this.approvals, ApprovalView.PENDING, '全部', '')
}

getMineApprovals(): ApprovalRequest[] {
  return filterApprovals(this.approvals, ApprovalView.MINE, '全部', '')
}

getHandledApprovals(): ApprovalRequest[] {
  return filterApprovals(this.approvals, ApprovalView.HANDLED, '全部', '')
}

以及一个通用的过滤方法,支持自定义三个维度:

getFilteredApprovals(view: string, type: string, keyword: string): ApprovalRequest[] {
  return filterApprovals(this.approvals, view, type, keyword)
}

五、过滤引擎的性能考量

5.1 时间复杂度

filterApprovals 使用线性扫描(forEach)遍历审批列表,时间复杂度为 O(n),其中 n 是审批记录的总数。

对于演示数据(7 条记录)来说,线性扫描的效率完全足够。在真实生产环境中,如果审批记录数量达到数千甚至数万条,可以考虑以下优化策略:

  • 预索引:为视图类型(pendingForMeisMinehandledByMe)建立索引
  • 分页加载:结合分页机制,每次只加载和过滤当前页的数据
  • 延迟计算:使用 LazyForEach 实现虚拟列表,只渲染可见区域的数据

5.2 搜索优化

当前的关键词搜索使用 includes 方法,实现了简单的模糊匹配。如果需要更高级的搜索功能,可以考虑:

  • 多字段权重:标题匹配的权重高于审批单号匹配
  • 拼音搜索:支持中文拼音搜索,如搜索"li ming"匹配"李明"
  • 全文索引:构建倒排索引,加速搜索

六、实际应用场景

6.1 仪表盘统计

过滤引擎与仪表盘统计共用相同的筛选逻辑:

export function getDashboardStats(approvals: ApprovalRequest[], messages: ApprovalMessage[]): DashboardStats {
  let stats: DashboardStats = new DashboardStats()
  approvals.forEach((item: ApprovalRequest) => {
    if (item.pendingForMe && item.status === ApprovalStatus.PENDING) {
      stats.pending++       // 待我审批数
    }
    if (item.isMine) {
      stats.mine++          // 我发起的数
    }
    if (item.handledByMe) {
      stats.handled++       // 已处理数
    }
  })
  messages.forEach((item: ApprovalMessage) => {
    if (!item.isRead) {
      stats.unread++        // 未读数
    }
  })
  return stats
}

6.2 列表页的视图切换

在审批列表页中,用户可以通过 Tab 切换视图:

[待我审批] [我发起的] [已处理]

切换视图时,调用 filterApprovals 重新渲染列表。如果同时选择了类型筛选或输入了搜索关键词,这三个条件会组合使用。

七、总结

filterApprovals 过滤引擎是星办OA 审批系统的数据检索核心,它通过三维过滤逻辑(视图过滤、类型过滤、关键词匹配)实现了高效、灵活的数据筛选。

三维过滤的设计优势:

  • 视图维度:从用户角色视角出发,解决了"谁看到什么数据"的问题
  • 类型维度:从业务分类视角出发,解决了"按类型筛选"的问题
  • 关键词维度:从搜索需求出发,解决了"精确查找"的问题

工程实现特点:

  • 纯函数设计:无副作用,输入输出确定,易于测试和调试
  • AND 逻辑串联:三个条件同时满足,结果精确可控
  • 模糊搜索:大小写不敏感、部分匹配、空关键词跳过
  • 视图常量:使用 ApprovalView 静态常量统一管理视图名称

通过 filterApprovals 函数,星办OA 实现了从"海量数据"到"精准结果"的高效筛选,为用户提供了流畅的审批数据检索体验。

源文件路径: commons/common/src/main/ets/model/ApprovalDomain.ts

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐