Commit 049dc070 authored by 郭阔's avatar 郭阔

feat(latest): 最近抓取改为最近24小时每次运行各一张卡片

原先每源只显示最新一场,补跑+定时连跑时前一场被顶下,用户误以为覆盖。
现同源多场并列(按运行时间倒序,上限80张),卡片带运行类型(续采/修复);
文章明细提取拆为 _articles_from_data 纯函数供多场复用。
parent 5af8e7dd
......@@ -1400,12 +1400,9 @@ def dashboard():
fail_top=sorted(fail_top.items(), key=lambda kv: -kv[1])[:6])
def _latest_run_articles(name):
"""源最近一次运行的文章明细(标题/链接/状态/失败原因),供最近抓取页与调度中心详情抽屉共用。"""
runs = get_history_runs(name, include_data=True)
if not runs:
return []
biz, _legacy = get_business_result(runs[0]["data"])
def _articles_from_data(data):
"""从一次运行的归一化 JSON 提取文章明细(标题/链接/状态/失败原因)。"""
biz, _legacy = get_business_result(data)
if not biz:
return []
return [{
......@@ -1417,44 +1414,43 @@ def _latest_run_articles(name):
} for a in biz.get("articles", [])]
def _latest_run_articles(name):
"""源最近一次运行的文章明细,供调度中心详情弹窗用。"""
runs = get_history_runs(name, include_data=True)
return _articles_from_data(runs[0]["data"]) if runs else []
@app.route("/latest")
@require_auth
def latest_content():
"""最近抓取:每个源最近一次运行抓到的文章标题与状态,快速盘点内容。"""
"""最近抓取:最近 24 小时内每次运行各一张卡片(同源多场都展示,按时间倒序)。"""
skills = pl.skill_sources()
names = sorted((set(skills) | set(pl.list_schedules())) - {"digest"})
names = [n for n in names
if skills.get(n, {}).get("enabled", False)
or pl.schedule_state(n) == "active"]
cutoff = datetime.now() - timedelta(hours=24)
cards = []
for n in names:
runs = get_history_runs(n, include_data=True)
if not runs:
cards.append({"name": n, "display": skills.get(n, {}).get("name") or n,
"run_at": None, "articles": [], "succeeded": None,
"failed": None, "exhausted": False})
continue
run = runs[0]
biz, _legacy = get_business_result(run["data"])
articles = []
if biz:
for a in biz.get("articles", []):
articles.append({
"title": a.get("title") or a.get("url", ""),
"url": a.get("url", ""),
"status": a.get("status", ""),
})
cards.append({
"name": n,
"display": skills.get(n, {}).get("name") or n,
"run_at": run["run_at"],
"articles": articles,
"succeeded": run["succeeded_count"],
"failed": run["failed_count"],
"exhausted": bool(biz.get("source_exhausted")) if biz else False,
})
cards.sort(key=lambda c: c["run_at"] or "", reverse=True)
return render_template("latest.html", cards=cards)
display = skills.get(n, {}).get("name") or n
for run in get_history_runs(n, include_data=True):
try:
run_dt = datetime.strptime(run["run_at"], "%Y-%m-%d %H:%M:%S")
except ValueError:
continue
if run_dt < cutoff:
break # 按时间倒序,再往前的都不在窗口内
cards.append({
"name": n, "display": display,
"run_at": run["run_at"], "mode": run["mode"],
"articles": _articles_from_data(run["data"]),
"succeeded": run["succeeded_count"],
"failed": run["failed_count"],
"exhausted": (lambda b: bool(b.get("source_exhausted")) if b else False)(
get_business_result(run["data"])[0]),
})
cards.sort(key=lambda c: c["run_at"], reverse=True)
return render_template("latest.html", cards=cards[:80])
@app.route("/schedules")
......
......@@ -17,7 +17,7 @@
<h1>最近抓取</h1>
<p style="color:#666;font-size:13px">
每个源最近一次运行抓到的文章标题与状态,按运行时间倒序;点击标题打开原文链接。
最近 24 小时内每次运行各一张卡片(同源多场并列,如补跑+定时各一张),按运行时间倒序;点击标题打开原文链接。
带已取尽标记=该源近期无新文章(正常),空列表=本次未交付(看上次运行详情排查)。
</p>
......@@ -26,7 +26,7 @@
<summary>
<code>{{ c.name }}</code>
{% if c.display and c.display != c.name %}<span style="color:#888">{{ c.display }}</span>{% endif %}
<span class="runinfo">{{ c.run_at or '从未运行' }}</span>
<span class="runinfo">{{ c.run_at or '从未运行' }}{% if c.mode and c.mode != '常规采集' %} · {{ c.mode }}{% endif %}</span>
{% if c.succeeded is not none %}
<span class="badge ok">✓ {{ c.succeeded }}</span>
{% if c.failed %}<span class="badge fail">✗ {{ c.failed }}</span>{% endif %}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment