diff --git a/api.py b/api.py index 6055446..5df96fd 100644 --- a/api.py +++ b/api.py @@ -149,12 +149,9 @@ def api_player(pid): def api_games(): q = request.args.get("q", "") status = request.args.get("status", "") - limit = int(request.args.get("limit", 30)) - r = tools.search_games(q, limit=limit) - results = r.get("results", []) - if status: - results = [g for g in results if g["status"] == status] - return jsonify(results) + page = max(1, int(request.args.get("page", 1))) + size = min(40, max(1, int(request.args.get("size", 12)))) + return jsonify(tools.list_games(q, status=status, page=page, size=size)) @app.route("/api/games/") diff --git a/static/app.js b/static/app.js index bc4fbe7..ab10f35 100644 --- a/static/app.js +++ b/static/app.js @@ -86,7 +86,12 @@ function loadView(v) { $$("#view-players .btn.small").forEach((x) => x.classList.toggle("active", x.dataset.pos === "")); loadPlayers(); } - else if (v === "games") loadGames(""); + else if (v === "games") { + gamesPage = 1; gamesQ = ""; gamesStatus = ""; + $("#search-games").value = ""; + $$("#view-games .btn.small").forEach((x) => x.classList.toggle("active", x.dataset.status === "")); + loadGames(); + } else if (v === "news") loadNews(""); else if (v === "persons") loadPersons(""); else if (v === "standings") { @@ -405,7 +410,7 @@ function renderPager(d, key) { } function goPage(key, p) { if (key === "players") { playersPage = p; loadPlayers(); } - else if (key === "games") { gamesPage = p; loadGames($("#search-games").value.trim()); } + else if (key === "games") { gamesPage = p; loadGames(); } } $("#btn-players").addEventListener("click", () => { playersQ = $("#search-players").value.trim(); playersPage = 1; loadPlayers(); }); @@ -439,12 +444,11 @@ async function openPlayer(id) { } /* ================= 比赛 ================= */ -let gameStatusFilter = ""; -async function loadGames(q) { - const url = `/api/games?q=${encodeURIComponent(q)}&limit=40`; - const games = await getJSON(url); - const list = games.filter((g) => !gameStatusFilter || g.status === gameStatusFilter); - $("#list-games").innerHTML = list.map((g) => { +let gamesPage = 1, gamesQ = "", gamesStatus = ""; +async function loadGames() { + const d = await getJSON(`/api/games?q=${encodeURIComponent(gamesQ)}&status=${gamesStatus}&page=${gamesPage}&size=12`); + const games = d.results || []; + $("#list-games").innerHTML = games.map((g) => { const finished = g.status === "finished"; const score = finished ? `${g.away_score} : ${g.home_score}` : "VS"; return `
@@ -460,14 +464,16 @@ async function loadGames(q) {
🕐 ${esc(g.game_time)} · ${esc(g.venue)} · ${esc(g.broadcast)}
`; }).join("") || '
没有符合条件的比赛
'; + renderPager(d, "games"); } $$("#view-games .btn.small").forEach((b) => b.addEventListener("click", () => { $$("#view-games .btn.small").forEach((x) => x.classList.remove("active")); b.classList.add("active"); - gameStatusFilter = b.dataset.status; - loadGames($("#search-games").value.trim()); + gamesStatus = b.dataset.status; + gamesPage = 1; + loadGames(); })); -$("#btn-games").addEventListener("click", () => loadGames($("#search-games").value.trim())); +$("#btn-games").addEventListener("click", () => { gamesQ = $("#search-games").value.trim(); gamesPage = 1; loadGames(); }); $("#search-games").addEventListener("keydown", (e) => { if (e.key === "Enter") $("#btn-games").click(); }); async function openGame(id) { const g = await getJSON(`/api/games/${id}`); diff --git a/static/index.html b/static/index.html index 928eaf7..4173756 100644 --- a/static/index.html +++ b/static/index.html @@ -78,7 +78,8 @@ -
+
+
diff --git a/static/style.css b/static/style.css index e8a82f6..cf817c0 100644 --- a/static/style.css +++ b/static/style.css @@ -132,6 +132,10 @@ main { flex: 1; width: 100%; max-width: 1200px; margin: 0 auto; padding: 20px 16 .pager button.active { background: linear-gradient(135deg, #f97316, #ea580c); color: #fff; border-color: transparent; } .pager button:disabled { opacity: .35; cursor: default; } .pager span { margin: 0 4px; } + +/* ---------- 比赛网格卡片(固定宽度,宽度足够一行多个) ---------- */ +.games-grid { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); align-items: stretch; } +.games-grid .list-item { display: flex; flex-direction: column; justify-content: space-between; gap: 8px; height: 100%; padding: 14px 16px; } .card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 14px 16px; cursor: pointer; transition: .18s; } .card:hover { transform: translateY(-3px); border-color: var(--orange2); box-shadow: 0 6px 20px rgba(0,0,0,.35); } .card h3 { font-size: 15.5px; margin-bottom: 4px; } diff --git a/tools.py b/tools.py index fbd7bca..39186c3 100644 --- a/tools.py +++ b/tools.py @@ -279,6 +279,18 @@ def get_game_detail(game_id): return detail +# ================================================================== 比赛列表(前台分页版) +def list_games(q="", status="", page=1, size=12): + """前台比赛列表:关键词 + 状态筛选 + 分页(数据量小,全量匹配后切片)""" + r = search_games(q, limit=500) + results = r.get("results", []) + if status: + results = [g for g in results if g["status"] == status] + total = len(results) + start = (page - 1) * size + return {"results": results[start:start + size], "total": total, "page": page, "size": size} + + # ================================================================== 排名 def search_standings(query_text, limit=20, season=None): q = (query_text or "").strip()