From 14317a44a2009ffc063b132c9c203b3c8a715b50 Mon Sep 17 00:00:00 2001 From: hz4th_coder Date: Mon, 17 Aug 2026 23:46:22 +0800 Subject: [PATCH] =?UTF-8?q?v1.2.8=20=E7=90=83=E5=91=98=E9=A1=B5=E5=A2=9E?= =?UTF-8?q?=E5=BC=BA=EF=BC=9A=E4=BD=8D=E7=BD=AE=E7=AD=9B=E9=80=89=E6=A0=87?= =?UTF-8?q?=E7=AD=BE(=E5=85=A8=E9=83=A8/=E6=8E=A7=E5=8D=AB/=E5=88=86?= =?UTF-8?q?=E5=8D=AB/=E5=B0=8F=E5=89=8D/=E5=A4=A7=E5=89=8D/=E4=B8=AD?= =?UTF-8?q?=E9=94=8B)=20+=20=E5=88=86=E9=A1=B5=E6=8E=A7=E4=BB=B6(24?= =?UTF-8?q?=E6=9D=A1/=E9=A1=B5=EF=BC=8C=E9=A1=B5=E7=A0=81=E7=9C=81?= =?UTF-8?q?=E7=95=A5=E5=8F=B7)=EF=BC=8C=E5=8F=AF=E4=B8=8E=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E7=BB=84=E5=90=88=E7=AD=9B=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api.py | 6 ++++-- static/app.js | 53 ++++++++++++++++++++++++++++++++++++++++++----- static/index.html | 11 +++++++++- static/style.css | 8 +++++++ tools.py | 20 ++++++++++++++++++ 5 files changed, 90 insertions(+), 8 deletions(-) diff --git a/api.py b/api.py index 761a09d..6055446 100644 --- a/api.py +++ b/api.py @@ -129,8 +129,10 @@ def api_team(tid): @app.route("/api/players") def api_players(): q = request.args.get("q", "") - r = tools.search_players(q, limit=int(request.args.get("limit", 60))) - return jsonify(r.get("results", [])) + position = request.args.get("position", "") + page = max(1, int(request.args.get("page", 1))) + size = min(60, max(1, int(request.args.get("size", 24)))) + return jsonify(tools.list_players(q, position=position, page=page, size=size)) @app.route("/api/players/") diff --git a/static/app.js b/static/app.js index ea2df9d..bc4fbe7 100644 --- a/static/app.js +++ b/static/app.js @@ -80,7 +80,12 @@ $$(".tab").forEach((t) => t.addEventListener("click", () => { function loadView(v) { if (v === "teams") loadTeams(); - else if (v === "players") loadPlayers(""); + else if (v === "players") { + playersPage = 1; playersQ = ""; playersPos = ""; + $("#search-players").value = ""; + $$("#view-players .btn.small").forEach((x) => x.classList.toggle("active", x.dataset.pos === "")); + loadPlayers(); + } else if (v === "games") loadGames(""); else if (v === "news") loadNews(""); else if (v === "persons") loadPersons(""); @@ -363,17 +368,55 @@ async function openTeam(id) { } /* ================= 球员 ================= */ -async function loadPlayers(q) { - const players = await getJSON(`/api/players?q=${encodeURIComponent(q)}&limit=60`); +let playersPage = 1, playersQ = "", playersPos = ""; +const POS_CN = { PG: "控卫", SG: "分卫", SF: "小前", PF: "大前", C: "中锋" }; + +async function loadPlayers() { + const d = await getJSON(`/api/players?q=${encodeURIComponent(playersQ)}&position=${playersPos}&page=${playersPage}&size=24`); + const players = d.results || []; $("#grid-players").innerHTML = players.map((p) => `
-

${esc(p.name)} ${esc(p.position)} #${p.number}

+

${esc(p.name)} ${esc(POS_CN[p.position] || p.position)} #${p.number}

${esc(p.team || "")} · ${esc(p.country)}
本季:${p.season.pts} 分 / ${p.season.reb} 板 / ${p.season.ast} 助
`).join(""); + renderPager(d, "players"); } -$("#btn-players").addEventListener("click", () => loadPlayers($("#search-players").value.trim())); + +/* 通用分页控件 */ +function renderPager(d, key) { + const pages = Math.max(1, Math.ceil(d.total / d.size)); + const cur = d.page; + const el = document.getElementById(`pager-${key}`); + if (!el) return; + const nums = []; + for (let i = 1; i <= pages; i++) { + if (pages > 9 && i !== 1 && i !== pages && Math.abs(i - cur) > 2) { + if (nums[nums.length - 1] !== "…") nums.push("…"); + continue; + } + nums.push(i); + } + el.innerHTML = ` + + ${nums.map((n) => n === "…" ? `` : ``).join("")} + + 共 ${d.total} 条`; +} +function goPage(key, p) { + if (key === "players") { playersPage = p; loadPlayers(); } + else if (key === "games") { gamesPage = p; loadGames($("#search-games").value.trim()); } +} + +$("#btn-players").addEventListener("click", () => { playersQ = $("#search-players").value.trim(); playersPage = 1; loadPlayers(); }); $("#search-players").addEventListener("keydown", (e) => { if (e.key === "Enter") $("#btn-players").click(); }); +$$("#view-players .btn.small").forEach((b) => b.addEventListener("click", () => { + $$("#view-players .btn.small").forEach((x) => x.classList.remove("active")); + b.classList.add("active"); + playersPos = b.dataset.pos; + playersPage = 1; + loadPlayers(); +})); async function openPlayer(id) { const p = await getJSON(`/api/players/${id}`); openModal(` diff --git a/static/index.html b/static/index.html index c3134fe..928eaf7 100644 --- a/static/index.html +++ b/static/index.html @@ -58,8 +58,17 @@
-
+
+ + + + + + + +
+
diff --git a/static/style.css b/static/style.css index 8855e40..e8a82f6 100644 --- a/static/style.css +++ b/static/style.css @@ -124,6 +124,14 @@ main { flex: 1; width: 100%; max-width: 1200px; margin: 0 auto; padding: 20px 16 .btn.small.active { color: var(--orange2); border-color: var(--orange2); background: rgba(249,115,22,.08); } .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 14px; } + +/* ---------- 分页控件 ---------- */ +.pager { display: flex; align-items: center; justify-content: center; gap: 6px; margin-top: 18px; color: var(--sub); font-size: 12.5px; flex-wrap: wrap; } +.pager button { background: var(--bg2); border: 1px solid var(--line); color: var(--txt); border-radius: 999px; padding: 6px 14px; cursor: pointer; font-size: 12.5px; transition: .15s; } +.pager button:hover:not(:disabled) { border-color: var(--orange2); color: var(--orange2); } +.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; } .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 522cace..fbd7bca 100644 --- a/tools.py +++ b/tools.py @@ -157,6 +157,26 @@ def get_player(player_id): return _fmt_player(p) if p else None +# ================================================================== 球员列表(前台分页版) +def list_players(q="", position="", page=1, size=24): + """前台球员列表:关键词 + 位置筛选 + 分页(区别于 search_players 工具版)""" + q = expand_aliases((q or "").strip()) + conds, args = [], [] + if q: + like = f"%{fuzzy(q)}%" + conds.append("(p.name LIKE ? ESCAPE '\\' OR p.name_en LIKE ? ESCAPE '\\' OR t.name LIKE ? ESCAPE '\\')") + args += [like, like, like] + if position: + conds.append("p.position=?") + args.append(position) + where = ("WHERE " + " AND ".join(conds)) if conds else "" + total = query_one(f"SELECT COUNT(*) AS c FROM players p LEFT JOIN teams t ON p.team_id=t.id {where}", args)["c"] + rows = query(f"""SELECT p.*, t.name AS team_name FROM players p LEFT JOIN teams t ON p.team_id=t.id + {where} ORDER BY p.season_pts DESC LIMIT ? OFFSET ?""", + args + [size, (page - 1) * size]) + return {"results": [_fmt_player(r) for r in rows], "total": total, "page": page, "size": size} + + # ================================================================== 比赛 _TEAM_PAT = None