From 5016d5f3f19a767342568ca7cf4f40275d3db2d9 Mon Sep 17 00:00:00 2001 From: hz4th_coder Date: Tue, 18 Aug 2026 00:20:43 +0800 Subject: [PATCH] =?UTF-8?q?v1.2.13=20=E4=BA=BA=E7=89=A9=E9=A1=B5=E5=A2=9E?= =?UTF-8?q?=E5=BC=BA=EF=BC=9A=E5=88=86=E9=A1=B5=E6=8E=A7=E4=BB=B6(12?= =?UTF-8?q?=E6=9D=A1/=E9=A1=B5)=EF=BC=8C=E4=B8=8E=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E7=AD=9B=E9=80=89/=E6=90=9C=E7=B4=A2=E7=BB=84=E5=90=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api.py | 9 +++------ static/app.js | 26 +++++++++++++++++--------- static/index.html | 1 + tools.py | 22 ++++++++++++++++++++++ 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/api.py b/api.py index 10480c3..2d17032 100644 --- a/api.py +++ b/api.py @@ -211,12 +211,9 @@ def api_news_detail(nid): def api_persons(): q = request.args.get("q", "") role = request.args.get("role", "") - limit = int(request.args.get("limit", 50)) - r = tools.search_persons(q, limit=limit) - results = r.get("results", []) - if role: - results = [p for p in results if p["role"] == role] - return jsonify(results) + page = max(1, int(request.args.get("page", 1))) + size = min(30, max(1, int(request.args.get("size", 12)))) + return jsonify(tools.list_persons(q, role=role, page=page, size=size)) @app.route("/api/persons/") diff --git a/static/app.js b/static/app.js index b81677a..3188bc5 100644 --- a/static/app.js +++ b/static/app.js @@ -98,7 +98,12 @@ function loadView(v) { $$("#view-news .btn.small").forEach((x) => x.classList.toggle("active", !x.dataset.kind && !x.dataset.tag)); loadNews(); } - else if (v === "persons") loadPersons(""); + else if (v === "persons") { + personsPage = 1; personsQ = ""; personsRole = ""; + $("#search-persons").value = ""; + $$("#view-persons .btn.small").forEach((x) => x.classList.toggle("active", x.dataset.role === "")); + loadPersons(); + } else if (v === "standings") { if ($("#season-select").options.length) { loadStandings(); loadPlayoffs(); } else loadSeasons(); @@ -417,6 +422,7 @@ function goPage(key, p) { if (key === "players") { playersPage = p; loadPlayers(); } else if (key === "games") { gamesPage = p; loadGames(); } else if (key === "news") { newsPage = p; loadNews(); } + else if (key === "persons") { personsPage = p; loadPersons(); } } $("#btn-players").addEventListener("click", () => { playersQ = $("#search-players").value.trim(); playersPage = 1; loadPlayers(); }); @@ -539,24 +545,26 @@ async function openNews(id) { } /* ================= 人物 ================= */ -let personRoleFilter = ""; -async function loadPersons(q) { - const persons = await getJSON(`/api/persons?q=${encodeURIComponent(q)}&limit=60`); - const list = persons.filter((p) => !personRoleFilter || p.role === personRoleFilter); - $("#grid-persons").innerHTML = list.map((p) => ` +let personsPage = 1, personsQ = "", personsRole = ""; +async function loadPersons() { + const d = await getJSON(`/api/persons?q=${encodeURIComponent(personsQ)}&role=${personsRole}&page=${personsPage}&size=12`); + const persons = d.results || []; + $("#grid-persons").innerHTML = persons.map((p) => `

${esc(p.name)} ${esc(p.name_en || "")}

${esc(p.role_cn)}${esc(p.title || "")}${p.team ? " · " + esc(p.team) : ""}
${esc((p.bio || "").slice(0, 60))}…
`).join(""); + renderPager(d, "persons"); } $$("#view-persons .btn.small").forEach((b) => b.addEventListener("click", () => { $$("#view-persons .btn.small").forEach((x) => x.classList.remove("active")); b.classList.add("active"); - personRoleFilter = b.dataset.role; - loadPersons($("#search-persons").value.trim()); + personsRole = b.dataset.role; + personsPage = 1; + loadPersons(); })); -$("#btn-persons").addEventListener("click", () => loadPersons($("#search-persons").value.trim())); +$("#btn-persons").addEventListener("click", () => { personsQ = $("#search-persons").value.trim(); personsPage = 1; loadPersons(); }); $("#search-persons").addEventListener("keydown", (e) => { if (e.key === "Enter") $("#btn-persons").click(); }); async function openPerson(id) { const p = await getJSON(`/api/persons/${id}`); diff --git a/static/index.html b/static/index.html index d0cc86e..50ca668 100644 --- a/static/index.html +++ b/static/index.html @@ -107,6 +107,7 @@
+
diff --git a/tools.py b/tools.py index b275dc9..b533786 100644 --- a/tools.py +++ b/tools.py @@ -433,6 +433,28 @@ def search_persons(query_text, limit=MAX_SHOW): "bio": r["bio"], "achievements": r["achievements"]} for r in rows]} +# ================================================================== 人物列表(前台分页版) +def list_persons(q="", role="", page=1, size=12): + """前台人物列表:关键词 + 角色筛选 + 分页""" + conds, args = [], [] + if q: + like = f"%{fuzzy(q)}%" + conds.append("(p.name LIKE ? ESCAPE '\\' OR p.name_en LIKE ? ESCAPE '\\' OR p.role_cn LIKE ? ESCAPE '\\' OR t.name LIKE ? ESCAPE '\\' OR p.bio LIKE ? ESCAPE '\\')") + args += [like] * 5 + if role: + conds.append("p.role=?") + args.append(role) + where = ("WHERE " + " AND ".join(conds)) if conds else "" + total = query_one(f"SELECT COUNT(*) AS c FROM persons 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 persons p LEFT JOIN teams t ON p.team_id=t.id + {where} ORDER BY p.id LIMIT ? OFFSET ?""", args + [size, (page - 1) * size]) + return {"results": [ + {"id": r["id"], "name": r["name"], "name_en": r["name_en"], "role": r["role"], + "role_cn": r["role_cn"], "title": r["title"], "team": r["team_name"], + "bio": r["bio"], "achievements": r["achievements"]} for r in rows], + "total": total, "page": page, "size": size} + + # ================================================================== 知识百科(纯向量检索) def search_knowledge(query_text, limit=3): q = (query_text or "").strip()