# coding=utf-8 """ HTML 报告渲染模块 提供 HTML 格式的热点新闻报告生成功能 """ from datetime import datetime from typing import Dict, Optional, Callable from trendradar.report.helpers import html_escape def render_html_content( report_data: Dict, total_titles: int, is_daily_summary: bool = False, mode: str = "daily", update_info: Optional[Dict] = None, *, reverse_content_order: bool = False, get_time_func: Optional[Callable[[], datetime]] = None, ) -> str: """渲染HTML内容 Args: report_data: 报告数据字典,包含 stats, new_titles, failed_ids, total_new_count total_titles: 新闻总数 is_daily_summary: 是否为当日汇总 mode: 报告模式 ("daily", "current", "incremental") update_info: 更新信息(可选) reverse_content_order: 是否反转内容顺序(新增热点在前) get_time_func: 获取当前时间的函数(可选,默认使用 datetime.now) Returns: 渲染后的 HTML 字符串 """ html = """ 热点新闻分析
热点新闻分析
报告类型 """ # 处理报告类型显示 if is_daily_summary: if mode == "current": html += "当前榜单" elif mode == "incremental": html += "增量模式" else: html += "当日汇总" else: html += "实时分析" html += """
新闻总数 """ html += f"{total_titles} 条" # 计算筛选后的热点新闻数量 hot_news_count = sum(len(stat["titles"]) for stat in report_data["stats"]) html += """
热点新闻 """ html += f"{hot_news_count} 条" html += """
生成时间 """ # 使用提供的时间函数或默认 datetime.now if get_time_func: now = get_time_func() else: now = datetime.now() html += now.strftime("%m-%d %H:%M") html += """
""" # 处理失败ID错误信息 if report_data["failed_ids"]: html += """
⚠️ 请求失败的平台
    """ for id_value in report_data["failed_ids"]: html += f'
  • {html_escape(id_value)}
  • ' html += """
""" # 生成热点词汇统计部分的HTML stats_html = "" if report_data["stats"]: total_count = len(report_data["stats"]) for i, stat in enumerate(report_data["stats"], 1): count = stat["count"] # 确定热度等级 if count >= 10: count_class = "hot" elif count >= 5: count_class = "warm" else: count_class = "" escaped_word = html_escape(stat["word"]) stats_html += f"""
{escaped_word}
{count} 条
{i}/{total_count}
""" # 处理每个词组下的新闻标题,给每条新闻标上序号 for j, title_data in enumerate(stat["titles"], 1): is_new = title_data.get("is_new", False) new_class = "new" if is_new else "" stats_html += f"""
{j}
{html_escape(title_data["source_name"])}""" # 处理排名显示 ranks = title_data.get("ranks", []) if ranks: min_rank = min(ranks) max_rank = max(ranks) rank_threshold = title_data.get("rank_threshold", 10) # 确定排名等级 if min_rank <= 3: rank_class = "top" elif min_rank <= rank_threshold: rank_class = "high" else: rank_class = "" if min_rank == max_rank: rank_text = str(min_rank) else: rank_text = f"{min_rank}-{max_rank}" stats_html += f'{rank_text}' # 处理时间显示 time_display = title_data.get("time_display", "") if time_display: # 简化时间显示格式,将波浪线替换为~ simplified_time = ( time_display.replace(" ~ ", "~") .replace("[", "") .replace("]", "") ) stats_html += ( f'{html_escape(simplified_time)}' ) # 处理出现次数 count_info = title_data.get("count", 1) if count_info > 1: stats_html += f'{count_info}次' stats_html += """
""" # 处理标题和链接 escaped_title = html_escape(title_data["title"]) link_url = title_data.get("mobile_url") or title_data.get("url", "") if link_url: escaped_url = html_escape(link_url) stats_html += f'{escaped_title}' else: stats_html += escaped_title stats_html += """
""" stats_html += """
""" # 生成新增新闻区域的HTML new_titles_html = "" if report_data["new_titles"]: new_titles_html += f"""
本次新增热点 (共 {report_data['total_new_count']} 条)
""" for source_data in report_data["new_titles"]: escaped_source = html_escape(source_data["source_name"]) titles_count = len(source_data["titles"]) new_titles_html += f"""
{escaped_source} · {titles_count}条
""" # 为新增新闻也添加序号 for idx, title_data in enumerate(source_data["titles"], 1): ranks = title_data.get("ranks", []) # 处理新增新闻的排名显示 rank_class = "" if ranks: min_rank = min(ranks) if min_rank <= 3: rank_class = "top" elif min_rank <= title_data.get("rank_threshold", 10): rank_class = "high" if len(ranks) == 1: rank_text = str(ranks[0]) else: rank_text = f"{min(ranks)}-{max(ranks)}" else: rank_text = "?" new_titles_html += f"""
{idx}
{rank_text}
""" # 处理新增新闻的链接 escaped_title = html_escape(title_data["title"]) link_url = title_data.get("mobile_url") or title_data.get("url", "") if link_url: escaped_url = html_escape(link_url) new_titles_html += f'{escaped_title}' else: new_titles_html += escaped_title new_titles_html += """
""" new_titles_html += """
""" new_titles_html += """
""" # 根据配置决定内容顺序 if reverse_content_order: # 新增热点在前,热点词汇统计在后 html += new_titles_html + stats_html else: # 默认:热点词汇统计在前,新增热点在后 html += stats_html + new_titles_html html += """
""" return html