diff --git a/api.py b/api.py index 5df96fd..10480c3 100644 --- a/api.py +++ b/api.py @@ -191,15 +191,10 @@ def api_playoffs(): def api_news(): q = request.args.get("q", "") kind = request.args.get("kind", "") - limit = int(request.args.get("limit", 20)) - if q: - r = tools.search_news(q, limit=limit) - return jsonify(r.get("results", [])) - from db import query - rows = query("""SELECT id,title,author,source,publish_time,tags,kind,substr(content,1,160) AS summary - FROM news WHERE (?='' OR kind=?) ORDER BY publish_time DESC, id DESC LIMIT ?""", - (kind, kind, limit)) - return jsonify(rows) + tag = request.args.get("tag", "") + page = max(1, int(request.args.get("page", 1))) + size = min(30, max(1, int(request.args.get("size", 10)))) + return jsonify(tools.list_news(q, kind=kind, tag=tag, page=page, size=size)) @app.route("/api/news/") diff --git a/static/app.js b/static/app.js index ab10f35..b81677a 100644 --- a/static/app.js +++ b/static/app.js @@ -92,7 +92,12 @@ function loadView(v) { $$("#view-games .btn.small").forEach((x) => x.classList.toggle("active", x.dataset.status === "")); loadGames(); } - else if (v === "news") loadNews(""); + else if (v === "news") { + newsPage = 1; newsQ = ""; newsKind = ""; newsTag = ""; + $("#search-news").value = ""; + $$("#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 === "standings") { if ($("#season-select").options.length) { loadStandings(); loadPlayoffs(); } @@ -411,6 +416,7 @@ function renderPager(d, key) { function goPage(key, p) { if (key === "players") { playersPage = p; loadPlayers(); } else if (key === "games") { gamesPage = p; loadGames(); } + else if (key === "news") { newsPage = p; loadNews(); } } $("#btn-players").addEventListener("click", () => { playersQ = $("#search-players").value.trim(); playersPage = 1; loadPlayers(); }); @@ -497,8 +503,10 @@ async function openGame(id) { } /* ================= 新闻 ================= */ -async function loadNews(q) { - const news = await getJSON(`/api/news?q=${encodeURIComponent(q)}&limit=30`); +let newsPage = 1, newsQ = "", newsKind = "", newsTag = ""; +async function loadNews() { + const d = await getJSON(`/api/news?q=${encodeURIComponent(newsQ)}&kind=${newsKind}&tag=${encodeURIComponent(newsTag)}&page=${newsPage}&size=10`); + const news = d.results || []; $("#list-news").innerHTML = news.map((n) => `
@@ -507,10 +515,19 @@ async function loadNews(q) {
🕐 ${esc(n.publish_time)} · ${esc(n.source)}${n.author ? " · " + esc(n.author) : ""}
${esc(n.summary || n.content || "")}…
-
`).join(""); + `).join("") || '
没有符合条件的新闻
'; + renderPager(d, "news"); } -$("#btn-news").addEventListener("click", () => loadNews($("#search-news").value.trim())); +$("#btn-news").addEventListener("click", () => { newsQ = $("#search-news").value.trim(); newsPage = 1; loadNews(); }); $("#search-news").addEventListener("keydown", (e) => { if (e.key === "Enter") $("#btn-news").click(); }); +$$("#view-news .btn.small").forEach((b) => b.addEventListener("click", () => { + $$("#view-news .btn.small").forEach((x) => x.classList.remove("active")); + b.classList.add("active"); + newsKind = b.dataset.kind; + newsTag = b.dataset.tag; + newsPage = 1; + loadNews(); +})); async function openNews(id) { const n = await getJSON(`/api/news/${id}`); openModal(` diff --git a/static/index.html b/static/index.html index 4173756..d0cc86e 100644 --- a/static/index.html +++ b/static/index.html @@ -82,8 +82,18 @@
-
+
+ + + + + + + + +
+
diff --git a/tools.py b/tools.py index 39186c3..b275dc9 100644 --- a/tools.py +++ b/tools.py @@ -351,6 +351,28 @@ def player_game_logs(player_id, limit=10): return out +# ================================================================== 新闻列表(前台分页版) +def list_news(q="", kind="", tag="", page=1, size=10): + """前台新闻列表:关键词 + 类型(kind) + 话题标签(tag) + 分页""" + conds, args = [], [] + if q: + like = f"%{fuzzy(q)}%" + conds.append("(title LIKE ? ESCAPE '\\' OR content LIKE ? ESCAPE '\\' OR tags LIKE ? ESCAPE '\\')") + args += [like, like, like] + if kind: + conds.append("kind=?") + args.append(kind) + if tag: + conds.append("tags LIKE ? ESCAPE '\\'") + args.append(f"%{fuzzy(tag)}%") + where = ("WHERE " + " AND ".join(conds)) if conds else "" + total = query_one(f"SELECT COUNT(*) AS c FROM news {where}", args)["c"] + rows = query(f"""SELECT id,title,author,source,publish_time,tags,kind,substr(content,1,160) AS summary + FROM news {where} ORDER BY publish_time DESC, id DESC LIMIT ? OFFSET ?""", + args + [size, (page - 1) * size]) + return {"results": rows, "total": total, "page": page, "size": size} + + # ================================================================== 新闻(SQL 关键词 + 向量语义 + 可选 rerank 融合) def search_news(query_text, limit=5): q = (query_text or "").strip()