{% extends "base.html" %} {% block title %}{{ name }} — News Harvester{% endblock %} {% block extra_head %} {% if auto_refresh or agent_running %} {% endif %} {% endblock %} {% block content %} {# ── 页头:源名 + 状态 + 排期 ───────────────────────────── #}

{{ name }}

{% if agent_running %} ● 运行中 {% elif business_result %} {{ '上次成功' if business_result.status == 'SUCCESS' else '上次失败' }} {% else %} 无运行记录 {% endif %} {% if run_time and run_time != '-' %} 每天 {{ run_time }} 自动采集 {% endif %}
{% if agent_running and run_phase %}
{% set stages = ['采集中', '摘要生成', '推送/收尾', '完成'] %} {% set cur = stages.index(run_phase) if run_phase in stages else 0 %} {% for st in stages %}
{{ st }}
{% if not loop.last %}
{% endif %} {% endfor %}
当前阶段:{{ run_phase }} {% if run_elapsed is not none %} · 已运行 {{ run_elapsed }} 分钟{% endif %} · 采集中(浏览器)→ 摘要生成 → 推送/收尾 · 页面每 10 秒自动刷新
{% endif %} {% if continue_status and continue_status.running %}
{{ continue_status.mode | replace('resume', '续采') | replace('repair', '修复') }}任务运行中… (启动于 {{ continue_status.start }}) 页面每 10 秒自动刷新
{% endif %} {# ── 主要操作 ──────────────────────────────────────────── #}
{# ── 运行概览(合并原 Timer 信息 / 最近运行 / JSON 元数据 的高频字段) ── #}

运行概览

状态
{{ state_label }}
上次运行
{{ last_trigger }}
下次触发
{{ next_trigger }}
{% if log_info %}
上次成本
{{ log_info.get('cost', '-') }}
上次耗时
{{ log_info.get('duration', '-') }}
Provider
{{ log_info.get('provider', '-') }}
{% endif %}
{% if log_info and log_info.get('session') %}

Session: {{ log_info.session }} {% if log_info.get('turns') %} · Turns {{ log_info.get('turns') }}{% endif %} {% if json_meta and json_meta.get('duration_api') %} · API {{ json_meta.duration_api }} ms{% endif %}

{% endif %} {# ── 采集结果 ──────────────────────────────────────────── #} {% if business_result %}

采集结果{% if result_time %} {{ result_time }}{% endif %}

结果状态
{{ '成功' if business_result.status == 'SUCCESS' else '失败' }}
成功 / 失败 / 目标
{{ business_result.succeeded_count }} / {{ business_result.failed_count }} / {{ business_result.requested_count }}
{% for failure in business_result.failures %}

{{ failure.type }} · {{ failure.message }} {% if failure.url %}({{ failure.url }}){% endif %}

{% endfor %} {% for warning in business_result.warnings %}

提示:{{ warning }}

{% endfor %} {% if business_result.source_exhausted %}

已无更多新文章:{{ business_result.exhaustion_reason }}

{% endif %}
{% for article in business_result.articles %} {% set archive = article.archive if article.archive is defined else {} %} {% set archive_props = archive.get('properties', {}) %} {% endfor %}
文章状态正文长度分类 / 标签失败原因
{% if article.url.startswith('https://') or article.url.startswith('http://') %}{{ article.title or article.url }}{% else %}{{ article.title }}{% endif %}
预览归档原文与属性 {% if archive.get('loaded') %}
{{ archive.get('body', '') }}
查看 Obsidian 属性
{{ archive_props | tojson(indent=2) }}
{% elif article.body is defined %}

{{ article.summary | default('') }}

{{ article.body }}
{% else %}

未能读取归档原文{% if archive.get('error') %}:{{ archive.error }}{% endif %}

{% endif %}

归档:{{ article.archive_path or '未归档' }}

{{ '成功' if article.status == 'SUCCESS' else '失败' }} {% if archive.get('body_length') is not none %}{{ archive.body_length }} 字符{% elif article.body_length is defined %}{{ article.body_length }} 字符{% else %}—{% endif %} {{ archive_props.get('category', article.category | default('')) }}
{{ archive_props.get('tags', article.tags | default([])) | join(' · ') }}
{{ article.failure_type or '—' }}{% if article.failure_reason %}
{{ article.failure_reason }}{% endif %}{% for evidence in article.quality_evidence %}{% if evidence != article.failure_reason %}
{{ evidence }}{% endif %}{% endfor %}
查看统一 JSON
{{ business_result | tojson(indent=2) }}
{% elif legacy_result is not none %}

历史采集结果

此记录使用旧版文本格式,未经过新版正文质量核验。

{{ legacy_result }}
{% endif %} {# ── 历史执行记录(高频,提前) ──────────────────────────── #}

历史执行记录

{% if history_runs %}
{% for run in history_runs %} {% endfor %}
运行时间类型状态文章(成功 / 失败 / 目标)Provider耗时
{{ run.run_at }} {{ run.mode }} {{ '成功' if run.status == 'SUCCESS' else '失败' if run.status == 'FAILED' else '旧版记录' if run.status == 'LEGACY' else run.status }} {% if run.requested_count is not none %}{{ run.succeeded_count }} / {{ run.failed_count }} / {{ run.requested_count }}{% else %}—{% endif %} {{ run.provider }} {{ run.duration }} 查看
{% else %}

暂无历史执行记录

{% endif %} {# ── 次要操作 ──────────────────────────────────────────── #}
编辑配置
返回列表
{# ── 折叠区:日志 / Claude 明细 / 配置 ───────────────────── #} {% if log_info %}
运行日志 (.last.log)
{{ log_info.raw }}
{% endif %} {% if json_meta %}
Claude 运行明细
is_error
{{ json_meta.is_error }}
Terminal
{{ json_meta.terminal }}
Turns
{{ json_meta.turns }}
API 耗时
{{ json_meta.duration_api }} ms
{% if json_meta.usage %}

Token 用量

{% for k, v in json_meta.usage.items() %} {% endfor %}
类型Token 数
{{ k }}{{ v }}
{% endif %} {% if json_meta.permission_denials %}

权限拒绝 ({{ json_meta.permission_denials|length }} 次)

{{ json_meta.permission_denials | tojson(indent=2) }}
{% endif %}

来源: {{ json_info.path }}

{% endif %}
栏目配置{% if conf %} ({{ name }}.conf){% endif %} {% if conf %}
{% for k, v in conf.items() %} {% endfor %}
{{ k }}{{ v }}
{% else %}

无独立配置,继承 default.conf

{% endif %}
{% endblock %}