125 lines
4.1 KiB
Python
125 lines
4.1 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
统计分析 API(需要登录):
|
||
- GET /api/stats -> 总览统计
|
||
- GET /api/stats/daily -> 按日统计
|
||
"""
|
||
from datetime import timedelta
|
||
|
||
from django.db.models import Count, Q
|
||
from django.utils import timezone
|
||
from rest_framework.decorators import api_view
|
||
|
||
from server.core.response import api_success
|
||
from server.models import ContactRecord, BossAccount, TaskLog
|
||
from server.core.worker_manager import worker_manager
|
||
|
||
GREETED_STATUS = "新打招呼"
|
||
|
||
|
||
@api_view(["GET"])
|
||
def stats_overview(request):
|
||
"""总览统计数据。"""
|
||
period = request.query_params.get("period", "all")
|
||
now = timezone.now()
|
||
|
||
# 根据时间段过滤
|
||
date_filter = Q()
|
||
if period == "today":
|
||
date_filter = Q(contacted_at__date=now.date())
|
||
elif period == "week":
|
||
date_filter = Q(contacted_at__gte=now - timedelta(days=7))
|
||
elif period == "month":
|
||
date_filter = Q(contacted_at__gte=now - timedelta(days=30))
|
||
|
||
contacts_qs = ContactRecord.objects.filter(date_filter)
|
||
total_contacts = contacts_qs.count()
|
||
total_greeted = contacts_qs.filter(reply_status=GREETED_STATUS).count()
|
||
total_replied = contacts_qs.filter(reply_status="已回复").count()
|
||
total_wechat = contacts_qs.filter(wechat_exchanged=True).count()
|
||
|
||
# 今日数据
|
||
today_filter = Q(contacted_at__date=now.date())
|
||
today_contacts = ContactRecord.objects.filter(today_filter).count()
|
||
today_greeted = ContactRecord.objects.filter(today_filter, reply_status=GREETED_STATUS).count()
|
||
today_replied = ContactRecord.objects.filter(today_filter, reply_status="已回复").count()
|
||
today_wechat = ContactRecord.objects.filter(today_filter, wechat_exchanged=True).count()
|
||
|
||
# 账号统计
|
||
total_accounts = BossAccount.objects.count()
|
||
logged_in_accounts = BossAccount.objects.filter(is_logged_in=True).count()
|
||
|
||
# Worker 统计
|
||
all_workers = worker_manager.get_all_workers()
|
||
online_workers = [w for w in all_workers if w.online]
|
||
|
||
# 任务统计
|
||
total_task_logs = TaskLog.objects.count()
|
||
|
||
reply_rate = round(total_replied / max(total_contacts, 1) * 100, 1)
|
||
wechat_rate = round(total_wechat / max(total_replied, 1) * 100, 1)
|
||
|
||
return api_success({
|
||
"period": period,
|
||
"contacts": {
|
||
"total": total_contacts,
|
||
"today": today_contacts,
|
||
"greeted": total_greeted,
|
||
"today_greeted": today_greeted,
|
||
"replied": total_replied,
|
||
"today_replied": today_replied,
|
||
"reply_rate": reply_rate,
|
||
},
|
||
"greetings": {
|
||
"total": total_greeted,
|
||
"today": today_greeted,
|
||
},
|
||
"wechat": {
|
||
"total": total_wechat,
|
||
"today": today_wechat,
|
||
"success_rate": wechat_rate,
|
||
},
|
||
"accounts": {
|
||
"total": total_accounts,
|
||
"logged_in": logged_in_accounts,
|
||
},
|
||
"workers": {
|
||
"total": len(all_workers),
|
||
"online": len(online_workers),
|
||
},
|
||
"tasks": {
|
||
"total_logs": total_task_logs,
|
||
},
|
||
})
|
||
|
||
|
||
@api_view(["GET"])
|
||
def stats_daily(request):
|
||
"""按日统计最近 N 天数据。"""
|
||
try:
|
||
days = int(request.query_params.get("days", 7))
|
||
except (TypeError, ValueError):
|
||
days = 7
|
||
days = max(1, min(days, 180))
|
||
now = timezone.now()
|
||
|
||
daily_data = []
|
||
for i in range(days - 1, -1, -1):
|
||
day = (now - timedelta(days=i)).date()
|
||
day_filter = Q(contacted_at__date=day)
|
||
qs = ContactRecord.objects.filter(day_filter)
|
||
total = qs.count()
|
||
greeted = qs.filter(reply_status=GREETED_STATUS).count()
|
||
replied = qs.filter(reply_status="已回复").count()
|
||
wechat = qs.filter(wechat_exchanged=True).count()
|
||
daily_data.append({
|
||
"date": f"{day.isoformat()}T00:00:00",
|
||
"contacts": total,
|
||
"greeted": greeted,
|
||
"replied": replied,
|
||
"wechat": wechat,
|
||
"reply_rate": round(replied / max(total, 1) * 100, 1),
|
||
})
|
||
|
||
return api_success(daily_data)
|