Compare commits

...
1 Commits
Author SHA1 Message Date
bot-ci 3254648849 fix(system): sort recent tasks by started_at desc
「最近任务」原先按 kv 键名排序。改为后端 `_task_records` 按
started_at 倒序写入 dict(缺开始时间排末尾,含进行中);
前端不再参与排序。配套 test_system_tasks_sorted_by_started_at_desc。
2026-11-02 19:52:46 +08:00
2 changed files with 60 additions and 4 deletions

No files matched your search

+17 -4
View File
@@ -622,19 +622,32 @@ class DashboardQueries:
continue continue
return None return None
@staticmethod
def _task_started_sort_key(value: Any) -> tuple[int, int]:
"""缺 started_at 的排末尾;有值的按开始时间倒序(含进行中)。"""
if isinstance(value, Mapping):
raw = value.get("started_at")
try:
return (0, -int(raw))
except (TypeError, ValueError):
pass
return (1, 0)
def _task_records(self, conn: sqlite3.Connection) -> dict[str, Any]: def _task_records(self, conn: sqlite3.Connection) -> dict[str, Any]:
rows = conn.execute( rows = conn.execute(
"SELECT k, v FROM kv WHERE k LIKE 'task:last:%' ORDER BY k" "SELECT k, v FROM kv WHERE k LIKE 'task:last:%'"
).fetchall() ).fetchall()
result: dict[str, Any] = {} items: list[tuple[str, Any]] = []
for row in rows: for row in rows:
name = str(row["k"]).removeprefix("task:last:") name = str(row["k"]).removeprefix("task:last:")
try: try:
value = json.loads(str(row["v"])) value = json.loads(str(row["v"]))
except (TypeError, json.JSONDecodeError): except (TypeError, json.JSONDecodeError):
value = {"raw": row["v"]} value = {"raw": row["v"]}
result[name] = value items.append((name, value))
return result items.sort(key=lambda pair: self._task_started_sort_key(pair[1]))
# 插入序即开始时间倒序;前端 Object.entries 保留该序,勿再排序。
return dict(items)
def _task_running(self, conn: sqlite3.Connection) -> dict[str, Any]: def _task_running(self, conn: sqlite3.Connection) -> dict[str, Any]:
rows = conn.execute( rows = conn.execute(
+43
View File
@@ -681,6 +681,48 @@ def test_overview_adjacent_previous_with_seed_and_dual_fields():
finally: finally:
db.close() db.close()
def test_system_tasks_sorted_by_started_at_desc():
"""最近任务按 started_at 倒序;缺开始时间的排末尾(含进行中无 finished)。"""
import json
with tempfile.TemporaryDirectory() as tmp:
db, q = setup(tmp)
try:
repo = Repository(db)
# 故意打乱写入/键名字母序;finished_at 与 started_at 错开,避免误用完成时间
samples = (
# name, started_at, finished_at
("zzz_old", FIXED_NOW - 300, FIXED_NOW - 10), # 开始最早,完成却很晚
("aaa_mid", FIXED_NOW - 100, FIXED_NOW - 90),
("mmm_new", FIXED_NOW - 10, None), # 进行中:只有 started
("no_time", None, FIXED_NOW), # 缺 started,应末尾
)
for name, started, finished in samples:
payload = {
"name": name,
"ok": True if finished is not None else True,
"error": None,
"summary": {},
}
if started is not None:
payload["started_at"] = started
if finished is not None:
payload["finished_at"] = finished
repo.kv_set(f"task:last:{name}", json.dumps(payload))
for legacy in ("snapshot", "fans", "discovery"):
repo.kv_delete(f"task:last:{legacy}")
DASHBOARD_CACHE.clear()
system = q.system()
assert list(system["tasks"].keys()) == [
"mmm_new", "aaa_mid", "zzz_old", "no_time",
]
overview = q.overview()
assert list(overview["tasks"].keys()) == list(system["tasks"].keys())
finally:
db.close()
def main_test(): def main_test():
test_overview() test_overview()
test_video_listing_filters_and_sorting() test_video_listing_filters_and_sorting()
@@ -696,6 +738,7 @@ def main_test():
test_fans_candidates_system_and_export() test_fans_candidates_system_and_export()
test_system_status_uses_completed_date_and_running_flags() test_system_status_uses_completed_date_and_running_flags()
test_system_next_runs_follow_last_completion_not_wall_clock() test_system_next_runs_follow_last_completion_not_wall_clock()
test_system_tasks_sorted_by_started_at_desc()
test_growth_auto_falls_back_to_one_day() test_growth_auto_falls_back_to_one_day()
test_snapshot_recent_next_run_follows_completion() test_snapshot_recent_next_run_follows_completion()
test_overview_adjacent_previous_with_seed_and_dual_fields() test_overview_adjacent_previous_with_seed_and_dual_fields()