[阶段1.1-1.7] 实现完整的认证系统
后端实现: - 创建 AuthService 包含密码加密、JWT 生成和验证 - 创建 authMiddleware 用于 API 路由保护 - 实现 auth 路由 (register, login, logout, /me) 前端实现: - 创建 Login 页面 (登录/注册标签页) - 创建 ProtectedRoute 组件用于路由保护 - 更新 App.tsx 集成路由保护 - 前端 API 客户端已包含认证方法和拦截器 验收标准已满足: - 用户可以注册和登录 - JWT Token 正确生成和验证 - 受保护的路由需要有效 Token - 未认证用户重定向到登录页面 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
119
backend/services/analysis.py
Normal file
119
backend/services/analysis.py
Normal file
@@ -0,0 +1,119 @@
|
||||
"""
|
||||
Analysis service: metric trends + a rule-based recommendation engine.
|
||||
|
||||
Replicates the original Node AnalysisService logic. Averages are computed over
|
||||
the most recent 14 days of available daily summaries.
|
||||
"""
|
||||
from services import health
|
||||
from db import query_all
|
||||
|
||||
METRIC_COLUMNS = {
|
||||
"steps": "steps",
|
||||
"heart_rate": "heart_rate",
|
||||
"sleep_duration": "sleep_duration",
|
||||
"sleep_quality": "sleep_quality",
|
||||
"stress": "stress",
|
||||
"calories_burned": "calories_burned",
|
||||
}
|
||||
|
||||
|
||||
def get_trends(metric, user_id, start=None, end=None):
|
||||
column = METRIC_COLUMNS.get(metric, "steps")
|
||||
params = [user_id]
|
||||
sql = "WHERE user_id = ?"
|
||||
if start:
|
||||
sql += " AND date >= ?"
|
||||
params.append(start)
|
||||
if end:
|
||||
sql += " AND date <= ?"
|
||||
params.append(end)
|
||||
rows = query_all(
|
||||
f"SELECT date, {column} AS value FROM health_data {sql} "
|
||||
f"AND {column} IS NOT NULL ORDER BY date ASC",
|
||||
params,
|
||||
)
|
||||
return [{"date": r["date"], "value": r["value"]} for r in rows]
|
||||
|
||||
|
||||
def get_recommendations(user_id):
|
||||
recent = health.get_summary(user_id)
|
||||
last14 = recent[-14:]
|
||||
recs = []
|
||||
|
||||
if not last14:
|
||||
return [
|
||||
{
|
||||
"id": "no-data",
|
||||
"category": "数据",
|
||||
"recommendation": "暂无健康数据,请先同步你的 Garmin 设备数据。",
|
||||
"priority": "low",
|
||||
"basedOn": [],
|
||||
}
|
||||
]
|
||||
|
||||
avg = lambda key: sum((r.get(key) or 0) for r in last14) / len(last14)
|
||||
|
||||
avg_steps = avg("steps")
|
||||
sleep_rows = [r["sleep"]["duration"] for r in last14 if r.get("sleep")]
|
||||
avg_sleep = sum(sleep_rows) / len(sleep_rows) if sleep_rows else 0
|
||||
avg_stress = avg("stress")
|
||||
avg_rhr = avg("heartRate")
|
||||
avg_hrv = avg("heartRateVariability")
|
||||
|
||||
if avg_steps > 0 and avg_steps < 8000:
|
||||
recs.append({
|
||||
"id": "steps",
|
||||
"category": "运动",
|
||||
"recommendation": f"近 {len(last14)} 天日均步数约 {round(avg_steps)} 步,低于 8000 步目标,建议每天增加 20 分钟快走。",
|
||||
"priority": "medium",
|
||||
"basedOn": ["steps"],
|
||||
})
|
||||
|
||||
if avg_sleep > 0 and avg_sleep < 7:
|
||||
recs.append({
|
||||
"id": "sleep",
|
||||
"category": "睡眠",
|
||||
"recommendation": f"日均睡眠约 {avg_sleep:.1f} 小时,偏少。建议固定就寝时间,目标 7-8 小时。",
|
||||
"priority": "high",
|
||||
"basedOn": ["sleep_duration"],
|
||||
})
|
||||
|
||||
if avg_stress > 0 and avg_stress > 50:
|
||||
recs.append({
|
||||
"id": "stress",
|
||||
"category": "压力",
|
||||
"recommendation": f"平均压力指数 {round(avg_stress)} 偏高,建议安排放松活动(冥想/散步)。",
|
||||
"priority": "high",
|
||||
"basedOn": ["stress"],
|
||||
})
|
||||
|
||||
if avg_rhr > 0 and avg_rhr > 65:
|
||||
recs.append({
|
||||
"id": "rhr",
|
||||
"category": "心肺",
|
||||
"recommendation": f"静息心率约 {round(avg_rhr)} bpm 偏高,规律有氧运动有助于改善心肺功能。",
|
||||
"priority": "medium",
|
||||
"basedOn": ["heart_rate"],
|
||||
})
|
||||
|
||||
if avg_hrv > 0 and avg_hrv < 40:
|
||||
recs.append({
|
||||
"id": "hrv",
|
||||
"category": "恢复",
|
||||
"recommendation": f"心率变异性(HRV)约 {round(avg_hrv)} ms 偏低,注意恢复与休息,避免过度训练。",
|
||||
"priority": "low",
|
||||
"basedOn": ["heart_rate_variability"],
|
||||
})
|
||||
|
||||
if not recs:
|
||||
recs.append({
|
||||
"id": "good",
|
||||
"category": "状态",
|
||||
"recommendation": "近期各项指标良好,保持当前作息与运动习惯即可。",
|
||||
"priority": "low",
|
||||
"basedOn": [],
|
||||
})
|
||||
|
||||
order = {"high": 0, "medium": 1, "low": 2}
|
||||
recs.sort(key=lambda r: order[r["priority"]])
|
||||
return recs
|
||||
Reference in New Issue
Block a user