diff --git a/reaction_board/web/queries.py b/reaction_board/web/queries.py index 5db1331..20314c8 100644 --- a/reaction_board/web/queries.py +++ b/reaction_board/web/queries.py @@ -622,19 +622,32 @@ class DashboardQueries: continue return None + @staticmethod + def _task_finished_sort_key(value: Any) -> tuple[int, int]: + """缺 finished_at 的排末尾;有值的按完成时间倒序。""" + if isinstance(value, Mapping): + raw = value.get("finished_at") + try: + return (0, -int(raw)) + except (TypeError, ValueError): + pass + return (1, 0) + def _task_records(self, conn: sqlite3.Connection) -> dict[str, Any]: 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() - result: dict[str, Any] = {} + items: list[tuple[str, Any]] = [] for row in rows: name = str(row["k"]).removeprefix("task:last:") try: value = json.loads(str(row["v"])) except (TypeError, json.JSONDecodeError): value = {"raw": row["v"]} - result[name] = value - return result + items.append((name, value)) + items.sort(key=lambda pair: self._task_finished_sort_key(pair[1])) + # 插入序即完成时间倒序;JSON/Object.entries 会保留。 + return dict(items) def _task_running(self, conn: sqlite3.Connection) -> dict[str, Any]: rows = conn.execute( diff --git a/reaction_board/web/static/views/system.js b/reaction_board/web/static/views/system.js index f4920d7..eff2b78 100644 --- a/reaction_board/web/static/views/system.js +++ b/reaction_board/web/static/views/system.js @@ -6,7 +6,16 @@ import { } from "../format.js"; function taskRows(tasks) { - const entries = Object.entries(tasks || {}); + const entries = Object.entries(tasks || {}).sort((a, b) => { + const fa = Number(a[1] && a[1].finished_at); + const fb = Number(b[1] && b[1].finished_at); + const aOk = Number.isFinite(fa); + const bOk = Number.isFinite(fb); + if (aOk && bOk) return fb - fa; + if (aOk) return -1; + if (bOk) return 1; + return String(a[0]).localeCompare(String(b[0])); + }); if (!entries.length) return emptyState("暂无任务记录", "运行一次同步、快照或发现后会写入最近结果。"); return `