如何使用RxJS对Activity数据对象按项目维度聚合统计总工时
实现步骤
- 修正聚合逻辑问题
你当前的聚合逻辑是按客户ID统计,且没有处理project可选的空值情况,需要调整为按项目维度统计:
// 先定义聚合结果的类型 interface ProjectAggregation { projectName: string; totalHours: number; } function aggregateByProject(activities: Activity[]): ProjectAggregation[] { const projectMap = activities.reduce((acc, activity) => { // 跳过没有关联项目的活动 if (!activity.project) return acc; const projectId = activity.project.id; if (!acc[projectId]) { acc[projectId] = { projectName: activity.project.name, totalHours: 0 }; } acc[projectId].totalHours += activity.hours; return acc; }, {} as Record<number | string, ProjectAggregation>); // 转为数组方便前端渲染 return Object.values(projectMap); }
- RxJS流组合逻辑
常规业务场景下会有三个可观察流:活动数据源流activities$、搜索关键词流query$、聚合维度选择流aggregator$,用combineLatest组合实现响应式更新:
import { combineLatest } from 'rxjs'; import { map } from 'rxjs/operators'; // 组合三个流 const displayData$ = combineLatest([activities$, query$, aggregator$]).pipe( map(([activities, query, aggregator]) => { // 第一步:执行过滤逻辑 let filteredActivities = activities; if (query) { const lowerQuery = query.toLowerCase(); filteredActivities = activities.filter(e => e.employee.firstName.toLowerCase().includes(lowerQuery) || e.employee.lastName.toLowerCase().includes(lowerQuery) || e.type.name.toLowerCase().includes(lowerQuery) || e.project?.name.toLowerCase().includes(lowerQuery) || e.project?.customer.name.toLowerCase().includes(lowerQuery) ) } // 第二步:判断是否需要按项目聚合 if (aggregator === 'project') { return aggregateByProject(filteredActivities); } // 不需要聚合直接返回过滤后的原活动列表 return filteredActivities; }) );
- 渲染数据
直接订阅displayData$即可拿到最终要展示的数据,根据返回数据是活动数组还是聚合结果数组,对应渲染表格即可。
内容的提问来源于stack exchange,提问作者Man24
相关产品推荐
相关产品推荐

