feat(sync-history): 新增同步结果查询(每次自动/手动/立即同步的记录)
后端: - db.py SCHEMA 新增 sync_history 表(不可变,每次同步尝试一行) + 索引 - garmin.py: _log_sync_history() 在 sync_data 全部出口记录; trigger 区分 auto(调度器)/manual(同步页开始同步)/quick(设置页立即同步); start_sync 限流拦截分支同样留档; 写入失败只告警不影响同步 - scheduler.py 自动同步传 trigger="auto"; routes 新增 GET /garmin/sync-history 按时间倒序返回(默认 50 条,上限 200) 前端: - api.ts 增加 SyncHistoryItem 类型 + getSyncHistory() - 新页面 /sync-history/ 同步记录: 卡片列表, 状态(成功/失败/被限流)chip 配色, 时间本地化(今天/昨天/X月X日), 触发类型标签, 范围与耗时 - 同步页与设置页同步区块均加入口链接
This commit is contained in:
@@ -87,6 +87,31 @@ CREATE TABLE IF NOT EXISTS sync_status (
|
||||
FOREIGN KEY (user_id) REFERENCES users(id)
|
||||
);
|
||||
|
||||
-- One immutable row per sync attempt (auto / manual / 立即同步), so the user
|
||||
-- can see what ran and what happened. sync_status above only keeps the
|
||||
-- *current* state; it says nothing about a run that finished hours ago.
|
||||
-- Column is trigger_kind, not trigger: TRIGGER is a MariaDB reserved word and
|
||||
-- a bare `trigger` column fails with 1064 there (SQLite tolerates it, so a
|
||||
-- local green suite does not catch it).
|
||||
CREATE TABLE IF NOT EXISTS sync_history (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
trigger_kind VARCHAR(16) NOT NULL,
|
||||
status VARCHAR(24) NOT NULL,
|
||||
days INT DEFAULT 0,
|
||||
records_synced INT DEFAULT 0,
|
||||
activities_synced INT DEFAULT 0,
|
||||
badges_synced INT DEFAULT 0,
|
||||
personal_records_synced INT DEFAULT 0,
|
||||
started_at DATETIME NOT NULL,
|
||||
finished_at DATETIME,
|
||||
duration_seconds INT DEFAULT 0,
|
||||
message TEXT,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_sync_history_user_time
|
||||
ON sync_history (user_id, started_at);
|
||||
|
||||
-- Garmin OAuth tokens, obtained once through an interactive login.
|
||||
-- Garmin accounts with two-factor auth cannot be logged into unattended: the
|
||||
-- library asks for an MFA code on stdin, which a gunicorn worker does not
|
||||
|
||||
Reference in New Issue
Block a user