diff --git a/app/services/daily_report_service.py b/app/services/daily_report_service.py
index 2aa9b73..b98650d 100644
--- a/app/services/daily_report_service.py
+++ b/app/services/daily_report_service.py
@@ -38,6 +38,17 @@ def _format_duration(minutes: float) -> str:
return f"{minutes / 60:.1f}小时"
+def _format_age(minutes: int) -> str:
+ """把分钟数格式化为人类友好的时长"""
+ if minutes < 60:
+ return f"{minutes}分钟"
+ hours = minutes / 60
+ if hours < 24:
+ return f"{hours:.1f}小时"
+ days = hours / 24
+ return f"{days:.1f}天"
+
+
def _format_ratio(numerator: int, denominator: int) -> str:
if denominator <= 0:
return "0%"
@@ -246,8 +257,9 @@ async def _build_daily_report_data() -> Optional[Dict]:
top_overdue = []
for order in overdue_orders[:3]:
age_minutes = max(int((now - order.create_time).total_seconds() / 60), 0)
+ order_type_label = "安保" if order.order_type == "SECURITY" else "保洁"
top_overdue.append(
- f"{order.order_code or order.id}|{_location_name(order)}|挂起 {age_minutes} 分钟"
+ f"{_location_name(order)}({order_type_label},已挂起{_format_age(age_minutes)})"
)
report = {
@@ -288,56 +300,65 @@ async def _build_daily_report_data() -> Optional[Dict]:
def _build_markdown(report: Dict) -> str:
- """构建单条企微 markdown 日报"""
+ """构建单条企微 markdown 日报(领导视角,简洁直观)"""
if report.get("empty"):
return (
f"**{report['title']}**\n\n"
- f">系统运行平稳,昨日无新增工单\n"
- f">当前无待处理工单"
+ f">昨日系统运行平稳,无新增工单\n"
+ f">当前无待处理事项"
)
s = report["summary"]
+ backlog = s["backlog_count"]
lines = [
f"**{report['title']}**",
"",
- # ── 核心数字 ──
+ # ── 总览 ──
f">昨日新增 {s['yesterday_total']} 条({report['change_str']})",
- f">安保 {s['security_count']}|"
- f"保洁 {s['clean_count']}|"
- f"完成 {s['completed_count']}|"
- f"取消 {s['cancelled_count']}|"
- f"误报率 {s['false_alarm_rate']}",
- f">当前待处理 {s['backlog_count']} 条"
- f"(遗留 {s['carry_over_count']})",
- "",
- # ── 效率指标 ──
- f"**响应效率**",
- f">平均首响 {s['avg_resp']}|"
- f"平均完结 {s['avg_close']}",
+ f">安保 {s['security_count']}|保洁 {s['clean_count']}|"
+ f"已完成 {s['completed_count']}|误报 {s['false_alarm_rate']}",
]
- # ── 风险分布 ──
- tops = report["tops"]
- has_risk = any(v != "暂无数据" for v in tops.values())
- if has_risk:
- lines.append("")
- lines.append("**风险分布**")
- if tops["alarm_types"] != "暂无数据":
- lines.append(f">告警类型:{tops['alarm_types']}")
- if tops["cleaning_types"] != "暂无数据":
- lines.append(f">保洁类型:{tops['cleaning_types']}")
- if tops["areas"] != "暂无数据":
- lines.append(f">高发区域:{tops['areas']}")
- if tops["cameras"] != "暂无数据":
- lines.append(f">高发摄像头:{tops['cameras']}")
+ # 待处理:0 用绿色,>0 用橙色警示
+ if backlog == 0:
+ lines.append(f">待处理 0 条,全部清零")
+ else:
+ lines.append(
+ f">待处理 {backlog} 条"
+ f"(其中遗留 {s['carry_over_count']})"
+ )
- # ── 超时跟进 ──
+ # ── 效率 ──
+ lines.append("")
+ lines.append(
+ f">响应效率:首响 {s['avg_resp']}"
+ f"|完结 {s['avg_close']}"
+ )
+
+ # ── 风险分布(仅有数据时展示)──
+ tops = report["tops"]
+ risk_items = []
+ if tops["alarm_types"] != "暂无数据":
+ risk_items.append(f">告警类型|{tops['alarm_types']}")
+ if tops["cleaning_types"] != "暂无数据":
+ risk_items.append(f">保洁类型|{tops['cleaning_types']}")
+ if tops["areas"] != "暂无数据":
+ risk_items.append(f">高发区域|{tops['areas']}")
+ if tops["cameras"] != "暂无数据":
+ risk_items.append(f">高发设备|{tops['cameras']}")
+
+ if risk_items:
+ lines.append("")
+ lines.append("**热点分布**")
+ lines.extend(risk_items)
+
+ # ── 超时跟进(仅有遗留时展示)──
if report["top_overdue"]:
lines.append("")
- lines.append(f"**超时未处理 {s['carry_over_count']} 条**")
- for idx, item in enumerate(report["top_overdue"], 1):
- lines.append(f">{idx}. {item}")
+ lines.append(f"**需关注({s['carry_over_count']}条超时)**")
+ for item in report["top_overdue"]:
+ lines.append(f">{item}")
return "\n".join(lines)