Enhance smoking tracking API with new features and improvements

- Added a new API endpoint `GET /api/v1/smoke/home` to consolidate core modules for the home dashboard, reducing the need for multiple requests.
- Updated the `smoke` routes to include the new home endpoint and improved user profile management with the addition of a `quit_date` field.
- Enhanced the algorithm for calculating daily targets and next smoke suggestions, ensuring accurate future time handling and user-specific recommendations.
- Improved API documentation to reflect new endpoints, response formats, and detailed field descriptions for better clarity and usability.
- Refactored user authentication handling in various handlers to streamline the process and ensure consistent error responses.
This commit is contained in:
nepiedg
2026-01-29 17:16:35 +00:00
parent 3154365ab2
commit 9200600b1c
21 changed files with 703 additions and 178 deletions
+18 -17
View File
@@ -71,6 +71,11 @@ if suggested_time in [sleep_time, wake_up_time]:
└── 否 → 返回建议时间
```
### 2.7 过期/未来记录兜底
- 如果用户补录了“未来时间”的抽烟记录,为了避免前端出现负倒计时,服务端会把 `last_smoke_at` 限制在当前 `as_of` 时刻以内。
-`plan_date` 是“今天”且 `last_smoke_at + interval` 早于当前时间时,会根据已过去的分钟数计算需要补齐的间隔,向前跳跃若干次直到结果落在未来。这样首页和 `GET /next_smoke_time` 都能返回一个“未来的下一次建议时间”,不会出现提示已经过期的时间点。
- 如果 `plan_date` 是将来日期(例如明天的日程),仍然按照指定日期的起床时间作为 `not_before_at`,不会使用上述补齐逻辑。
---
## 3. AI 增强算法
@@ -177,26 +182,22 @@ function calculateStage(startDate) {
}
```
### 4.3 每日目标计算
### 4.3 每日目标计算(线性递减)
以 onboarding 完成日期为起点,到 `quit_date` 线性递减到 0
```javascript
// utils/target.js
function calculateDailyTarget(baseline, stage, dayInStage) {
if (stage === 1) {
return baseline
}
if (stage === 2) {
const reduction = (dayInStage / 14) * 0.5
return Math.max(Math.round(baseline * (1 - reduction)), 1)
}
if (stage === 3) {
const targetRate = 0.25 - (dayInStage / 9) * 0.25
return Math.max(Math.round(baseline * targetRate), 0)
}
return baseline
function calculateDailyTarget(baseline, startDate, quitDate, today) {
if (!baseline || !startDate || !quitDate) return baseline
if (today >= quitDate) return 0
const totalDays = daysBetween(startDate, quitDate)
if (totalDays <= 0) return baseline
const remainingDays = daysBetween(today, quitDate)
const target = Math.round(baseline * (remainingDays / totalDays))
return remainingDays > 0 ? Math.max(target, 1) : 0
}
```