本文目录导读:

在PHP项目中统计“慢跑恢复时间”数据,需要看你具体想统计什么维度的数据,这里的“恢复时间”通常有两种理解:①生理恢复(心率降到正常区间所需时间)或 ②训练间隔(两次慢跑之间的休息天数)。
下面从数据采集、数据库设计、PHP统计逻辑和前端展示四个维度给出完整方案。
数据模型设计(MySQL)
首先需要两张核心表:run_records(跑步记录)和 recovery_logs(恢复日志)。
-- 跑步记录表
CREATE TABLE run_records (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_id INT UNSIGNED NOT NULL,
ran_at DATETIME NOT NULL, -- 开始跑步时间
duration_minutes INT, -- 跑步时长(分钟)
distance_km DECIMAL(5,2), -- 距离
avg_hr INT, -- 平均心率
max_hr INT, -- 最大心率
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_run (user_id, ran_at)
) ENGINE=InnoDB;
-- 恢复日志表(每次跑后记录身体感受或心率恢复数据)
CREATE TABLE recovery_logs (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_id INT UNSIGNED NOT NULL,
run_id INT UNSIGNED, -- 关联上一次跑步
recovery_minutes INT, -- 恢复所需分钟数(跑后心率降至100bpm所需时间)
sleep_quality TINYINT, -- 睡眠质量1-10
soreness_level TINYINT, -- 肌肉酸痛程度1-10
resting_hr INT, -- 次日晨脉(静息心率)
recorded_on DATE, -- 记录日期
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_date (user_id, recorded_on),
FOREIGN KEY (run_id) REFERENCES run_records(id)
) ENGINE=InnoDB;
替代方案:如果你只关心生理恢复(心率),可以不建恢复日志表,直接在
run_records增加hr_recovery_time字段(跑后心率恢复到静息水平的时间)。
统计维度与 PHP 实现逻辑
场景A:统计单次跑步的“恢复效率”(心率恢复速度)
业务含义:跑后心率下降速度越快,通常代表心肺功能越好。
// 输入:run_id
public function calculateRecoveryRate(int $runId): float
{
$sql = "SELECT
max_hr,
TIMESTAMPDIFF(MINUTE, ran_at, recovery_logs.recorded_on) AS recovery_time
FROM run_records
LEFT JOIN recovery_logs ON recovery_logs.run_id = run_records.id
WHERE run_records.id = ?";
// ... 执行查询(PDO预处理)...
// 假设逻辑:恢复指数 = 最大心率下降50bpm所需分钟数(越小越好)
$dropRate = ($record['max_hr'] - 100) / max($record['recovery_time'], 1);
return round($dropRate, 2); // bpm/min
}
场景B:统计最近N天的平均恢复时间(趋势分析)
业务含义:判断整体恢复能力是否变好。
// 参数:user_id, days
public function getAvgRecoveryTrend(int $userId, int $days = 30): array
{
$startDate = date('Y-m-d', strtotime("-{$days} days"));
$sql = "SELECT
DATE(ran_at) AS run_date,
AVG(recovery_minutes) AS avg_recovery_time
FROM run_records r
LEFT JOIN recovery_logs l ON l.run_id = r.id
WHERE r.user_id = :uid AND r.ran_at >= :start
GROUP BY DATE(ran_at)
ORDER BY run_date";
// 结果示例: [['run_date' => '2025-05-01', 'avg_recovery_time' => 15.2], ...]
}
场景C:统计“训练间隔”对恢复的影响(相关性分析)
业务含义:恢复时间是否足够(两次跑步间隔超过48小时才健康)。
// 核心SQL:计算每两次跑步的间隔,并匹配恢复分钟数
public function getIntervalVsRecovery(int $userId): array
{
$sql = "SELECT
r1.ran_at AS current_run,
r2.ran_at AS previous_run,
TIMESTAMPDIFF(HOUR, r2.ran_at, r1.ran_at) AS interval_hours,
l.recovery_minutes
FROM run_records r1
LEFT JOIN run_records r2 ON
r2.ran_at < r1.ran_at
AND r2.user_id = r1.user_id
LEFT JOIN recovery_logs l ON l.run_id = r1.id
WHERE r1.user_id = ?
GROUP BY r1.id
HAVING previous_run IS NOT NULL
ORDER BY current_run DESC";
// 在PHP中再计算:如果间隔 < 24小时 和 > 48小时的 恢复时间统计均值
}
前端可视化建议
统计完数据后,推荐用 Chart.js 或 ECharts 展示:
| 图表类型 | 实现提示 | |
|---|---|---|
| 折线图 | 每日平均恢复时间趋势 | 用场景B的数据,横轴日期,纵轴分钟数 |
| 散点图 | 训练间隔 vs 恢复时间 | 场景C的数据,可判断相关性 |
| 仪表盘 | 当前恢复状态评级(快/正常/慢) | PHP中定义阈值:<10分钟优秀,10-15良好,15-20及格,>20需加休 |
注意事项与最佳实践
- 时区问题:用
ran_at比较时,确保PHP和数据库时区统一(如date_default_timezone_set('Asia/Shanghai'))。 - 数据缺失处理:很多人跑步后不记录恢复日志,统计时可用
COALESCE(l.recovery_minutes, 0)或过滤掉NULL数据,避免影响AVG。 - 性能优化:当数据量大时(>10万条),
GROUP BY查询需添加组合索引(user_id, ran_at)。 - 第三方API接入(可选):
- 若对接佳明/手表,心率恢复时间(HRR)通常已经是官方指标,直接同步字段即可。
- 若用微信运动/微信小程序,可直接读取睡眠和步数,通过
recovery_logs录入。
完整示例代码(控制器方法)
// 控制器 RecoveryController.php
public function weeklySummary(Request $request)
{
$userId = $request->user()->id;
$weekAgo = date('Y-m-d', strtotime('-7 days'));
$stats = DB::table('run_records as r')
->join('recovery_logs as l', 'r.id', '=', 'l.run_id')
->where('r.user_id', $userId)
->where('r.ran_at', '>=', $weekAgo)
->select(
DB::raw('AVG(l.recovery_minutes) as avg_recovery'),
DB::raw('COUNT(DISTINCT r.id) as runs'),
DB::raw('MAX(l.resting_hr) as highest_resting_hr')
)
->get();
// 业务判断:合理恢复时间
$status = match(true) {
$stats->avg_recovery < 10 => '极佳',
$stats->avg_recovery < 15 => '良好',
$stats->avg_recovery < 20 => '一般',
default => '需加休'
};
return view('recovery', ['stats' => $stats, 'status' => $status]);
}
按照上面设计,你可以完成:
- ✅ 记录每次跑后的心率恢复时间
- ✅ 按日期/周/月统计平均恢复趋势
- ✅ 分析休息间隔与恢复之间的关系
- ✅ 通过图表直观展示给用户
如果你需要对接特定设备(如Apple Watch、Garmin Connect API)来获取原始心率数据(自动计算恢复时间),请在评论区说明设备类型,我可以补充对应的OAuth调用逻辑和数据转换代码。