API-INFO-020 P1 | heatmap 日期过滤与阅读数据接入 【status:partial】 #118

Closed
opened 2026-06-07 11:03:40 +08:00 by wangdl · 2 comments
Owner

目标

GET /activity/heatmap?days=365

规则

  • 必须按 userId + activityDate 范围过滤(不再 findAll 全表)
  • 数据来源 DailyLearningActivity

详见设计文档 API-INFO-000。

## 目标 ```http GET /activity/heatmap?days=365 ``` ### 规则 - 必须按 userId + activityDate 范围过滤(不再 findAll 全表) - 数据来源 DailyLearningActivity 详见设计文档 API-INFO-000。
wangdl added this to the M8:学习信息收集与基础分析闭环 milestone 2026-06-07 11:03:40 +08:00
wangdl changed title from API-INFO-013 P1 | Activity heatmap 接入阅读数据 to API-INFO-020 P1 | heatmap 日期过滤与阅读数据接入 2026-06-07 11:22:19 +08:00
wangdl changed title from API-INFO-020 P1 | heatmap 日期过滤与阅读数据接入 to API-INFO-020 P1 | heatmap 日期过滤与阅读数据接入 【status:partial】 2026-06-07 19:04:18 +08:00
Author
Owner

审查结论:当前 API 项目学习信息收集体系基本为全新建设。可复用:JWT Guard、LearningSession 基础表/CRUD、DailyLearningActivity 基础表、ActivityController 部分接口、LearningRecord schema。其余 ReadingEvent/TemporaryMaterial/Progress/批量上报/Processor/聚合/查询接口/错误码/去重/权限/测试/文档均不存在或仅部分存在。

本 Issue: /activity/heatmap 存在但 findAll 全表。需加日期过滤。blocked-by:api-info-core

标签: audit:reviewed audit:api-info status:partial work:extend-existing,work:api

## 审查结论:当前 API 项目学习信息收集体系基本为全新建设。可复用:JWT Guard、LearningSession 基础表/CRUD、DailyLearningActivity 基础表、ActivityController 部分接口、LearningRecord schema。其余 ReadingEvent/TemporaryMaterial/Progress/批量上报/Processor/聚合/查询接口/错误码/去重/权限/测试/文档均不存在或仅部分存在。 **本 Issue**: /activity/heatmap 存在但 findAll 全表。需加日期过滤。blocked-by:api-info-core **标签**: audit:reviewed audit:api-info status:partial work:extend-existing,work:api
Author
Owner

完成报告

交付

1. Repository 新增 findByDateRange — 日期范围过滤代替全表扫描:

async findByDateRange(userId: string, from: Date, to: Date) {
  return prisma.dailyLearningActivity.findMany({
    where: { userId, activityDate: { gte: from, lte: to } },
    orderBy: { activityDate: "asc" },
  });
}

2. getHeatmap 更新 — 接受 days 参数(默认 365,最大 365):

async getHeatmap(userId: string, days: number = 365) {
  const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
  const activities = await this.repository.findByDateRange(userId, from, new Date());
  // ... map to { date: durationSeconds }
}

3. ControllerGET /activity/heatmap?days=365

@Get("heatmap")
async getHeatmap(@CurrentUser() user, @Query("days") days?) {
  const d = Math.min(Number(days ?? 365) || 365, 365);
  return this.activityService.getHeatmap(userId, d);
}
## 完成报告 ### 交付 **1. Repository 新增 `findByDateRange`** — 日期范围过滤代替全表扫描: ```typescript async findByDateRange(userId: string, from: Date, to: Date) { return prisma.dailyLearningActivity.findMany({ where: { userId, activityDate: { gte: from, lte: to } }, orderBy: { activityDate: "asc" }, }); } ``` **2. `getHeatmap` 更新** — 接受 days 参数(默认 365,最大 365): ```typescript async getHeatmap(userId: string, days: number = 365) { const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000); const activities = await this.repository.findByDateRange(userId, from, new Date()); // ... map to { date: durationSeconds } } ``` **3. Controller** — `GET /activity/heatmap?days=365` ```typescript @Get("heatmap") async getHeatmap(@CurrentUser() user, @Query("days") days?) { const d = Math.min(Number(days ?? 365) || 365, 365); return this.activityService.getHeatmap(userId, d); } ```
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: wangdl/api-server#118
No description provided.