From ec5501fa3be2c23b08f6490cdc29b7472f283ce6 Mon Sep 17 00:00:00 2001 From: 16337 <1633794139@qq.com> Date: Fri, 3 Apr 2026 16:48:29 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=9A=E6=97=A5=E6=8A=A5?= =?UTF-8?q?=E5=8D=A1=E7=89=87=E6=89=93=E7=A3=A8=E7=BB=86=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 高发设备/告警热点只取 top2,名称超8字截断,防止文字溢出 - 已完成和待处理合并为一行,减少行数更紧凑 - 待处理为0时显示「✅ 全部清零」,有遗留才显示遗留数 - 误报率非0时才显示,0%不占位 - 副标题:清零时正面鼓励,有超时时⚠提醒 - 底部新增「查看详情」跳转链接 --- app/services/daily_report_service.py | 52 +++++++++++++++++++--------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/app/services/daily_report_service.py b/app/services/daily_report_service.py index e95774b..574ab4f 100644 --- a/app/services/daily_report_service.py +++ b/app/services/daily_report_service.py @@ -66,12 +66,15 @@ def _format_change(current: int, previous: int) -> str: return f"前日{previous}条,持平" -def _top_summary(counter: Counter, mapping: Optional[Dict[str, str]] = None, top_n: int = 3) -> str: +def _top_summary(counter: Counter, mapping: Optional[Dict[str, str]] = None, top_n: int = 3, max_len: int = 0) -> str: + """汇总 Counter 前 N 名。max_len > 0 时截断每个名称。""" if not counter: return "暂无数据" parts = [] for key, count in counter.most_common(top_n): name = mapping.get(key, key) if mapping else key + if max_len and len(name) > max_len: + name = name[:max_len] + ".." parts.append(f"{name} {count}") return ",".join(parts) @@ -293,6 +296,9 @@ async def _build_daily_report_data() -> Optional[Dict]: "areas": _top_summary(area_counter), "cameras": _top_summary(camera_counter), "cleaning_types": _top_summary(cleaning_type_count, CLEANING_TYPE_NAMES), + # 卡片专用:截断名称,只取 top2 防溢出 + "cameras_short": _top_summary(camera_counter, top_n=2, max_len=8), + "alarm_types_short": _top_summary(alarm_type_count, ALARM_TYPE_NAMES, top_n=2), }, "top_overdue": top_overdue, } @@ -305,31 +311,40 @@ def _build_template_card(report: Dict) -> Dict: tops = report["tops"] click_url = settings.wechat.service_base_url or "https://work.weixin.qq.com" - # 大号数字:昨日新增 + # 大号数字 emphasis_desc = f"昨日新增({report['change_str']})" - # 键值对列表(最多 6 条,挑最重要的) + # 待处理文案 + if s["backlog_count"] == 0: + pending_val = "0 ✅ 全部清零" + elif s["carry_over_count"] > 0: + pending_val = f"{s['backlog_count']}(遗留{s['carry_over_count']})" + else: + pending_val = str(s["backlog_count"]) + + # 键值对(最多 6 条,用短名称防截断) kv_list = [ {"keyname": "安保 / 保洁", "value": f"{s['security_count']} / {s['clean_count']}"}, - {"keyname": "已完成", "value": f"{s['completed_count']}"}, - {"keyname": "待处理", "value": f"{s['backlog_count']}(遗留 {s['carry_over_count']})" if s['backlog_count'] > 0 else "0 全部清零"}, + {"keyname": "已完成 / 待处理", "value": f"{s['completed_count']} / {pending_val}"}, {"keyname": "首响 / 完结", "value": f"{s['avg_resp']} / {s['avg_close']}"}, ] - # 第5条:最高发告警类型 - if tops["alarm_types"] != "暂无数据": - kv_list.append({"keyname": "告警热点", "value": tops["alarm_types"]}) + if tops["alarm_types_short"] != "暂无数据": + kv_list.append({"keyname": "告警热点", "value": tops["alarm_types_short"]}) - # 第6条:高发设备 - if tops["cameras"] != "暂无数据": - kv_list.append({"keyname": "高发设备", "value": tops["cameras"]}) + if tops["cameras_short"] != "暂无数据": + kv_list.append({"keyname": "高发设备", "value": tops["cameras_short"]}) - # 副标题 - sub_title = "" - if report["top_overdue"]: - sub_title = f"需关注:{report['top_overdue'][0]}" - elif s["backlog_count"] == 0: - sub_title = "昨日工单全部处理完毕,运营良好" + if s["false_alarm_rate"] != "0%": + kv_list.append({"keyname": "误报率", "value": s["false_alarm_rate"]}) + + # 副标题(一句话总结) + if s["backlog_count"] == 0: + sub_title = "昨日工单全部清零,运营状态良好" + elif report["top_overdue"]: + sub_title = f"⚠ 需关注:{report['top_overdue'][0]}" + else: + sub_title = f"当前 {s['backlog_count']} 条待处理" card = { "card_type": "text_notice", @@ -346,6 +361,9 @@ def _build_template_card(report: Dict) -> Dict: }, "sub_title_text": sub_title, "horizontal_content_list": kv_list, + "jump_list": [ + {"type": 1, "title": "查看详情", "url": click_url}, + ], "card_action": { "type": 1, "url": click_url,