Files
along_django/yonghu/paihang_views.py

215 lines
7.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
排行榜接口 — 基于 houtai 日统计表聚合(文赫电竞)
POST /yonghu/phbhqsj
"""
import logging
from datetime import date, timedelta
from decimal import Decimal
from django.db.models import Sum
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from houtai.models import (
DashouRiTongji,
GuanshiRiTongji,
ZuzhangRiTongji,
ShangjiaRiTongji,
)
from yonghu.models import UserMain, UserDashou, UserShangjia, UserBoss
logger = logging.getLogger(__name__)
MAX_RANK = 50
RIQI_OPTIONS = frozenset({'今日', '本周', '本月', '总榜', '昨日', '上周', '上月'})
SHENFEN_OPTIONS = frozenset({'dashou', 'guanshi', 'zuzhang', 'shangjia'})
ROLE_CONFIG = {
'dashou': {
'model': DashouRiTongji,
'id_field': 'yonghuid',
'sort_field': 'chengjiao_zonge',
'fields': ('jiedan_zongliang', 'chengjiao_zongliang', 'jiedan_zonge', 'chengjiao_zonge'),
'int_fields': frozenset({'jiedan_zongliang', 'chengjiao_zongliang'}),
},
'guanshi': {
'model': GuanshiRiTongji,
'id_field': 'yonghuid',
'sort_field': 'shouru_zonge',
'fields': ('yaoqing_dashou_shu', 'chongzhi_dashou_shu', 'shouru_zonge'),
'int_fields': frozenset({'yaoqing_dashou_shu', 'chongzhi_dashou_shu'}),
},
'zuzhang': {
'model': ZuzhangRiTongji,
'id_field': 'yonghuid',
'sort_field': 'shouru_zonge',
'fields': ('yaoqing_guanshi_shu', 'fenyong_jine', 'shouru_zonge'),
'int_fields': frozenset({'yaoqing_guanshi_shu'}),
},
'shangjia': {
'model': ShangjiaRiTongji,
'id_field': 'yonghuid',
'sort_field': 'paifa_jine',
'fields': ('paifa_dingdan_shu', 'paifa_jine', 'jiesuan_dingdan_shu', 'jiesuan_jine'),
'int_fields': frozenset({'paifa_dingdan_shu', 'jiesuan_dingdan_shu'}),
},
}
def _resolve_date_range(riqi: str):
today = date.today()
if riqi == '今日':
return today, today
if riqi == '昨日':
d = today - timedelta(days=1)
return d, d
if riqi == '本周':
monday = today - timedelta(days=today.weekday())
return monday, today
if riqi == '上周':
this_monday = today - timedelta(days=today.weekday())
last_sunday = this_monday - timedelta(days=1)
last_monday = last_sunday - timedelta(days=6)
return last_monday, last_sunday
if riqi == '本月':
return today.replace(day=1), today
if riqi == '上月':
first_this_month = today.replace(day=1)
last_day_prev = first_this_month - timedelta(days=1)
return last_day_prev.replace(day=1), last_day_prev
return None
def _fmt_value(val, is_int: bool):
if val is None:
return 0 if is_int else 0.0
if is_int:
return int(val)
if isinstance(val, Decimal):
return float(val.quantize(Decimal('0.01')))
return float(val)
class PhbHqsjView(APIView):
"""POST /yonghu/phbhqsj — 新排行榜(日统计表聚合)"""
permission_classes = [IsAuthenticated]
def post(self, request):
shenfen = (request.data.get('shenfen') or '').strip()
riqi = (request.data.get('riqi') or '').strip()
if shenfen not in SHENFEN_OPTIONS:
return Response({
'code': 400,
'msg': '参数错误shenfen 必须为 dashou/guanshi/zuzhang/shangjia',
'data': {'list': []},
})
if riqi not in RIQI_OPTIONS:
return Response({
'code': 400,
'msg': '参数错误riqi 必须为 今日/本周/本月/总榜/昨日/上周/上月',
'data': {'list': []},
})
try:
if riqi == '总榜':
rows = self._query_rank_rows(shenfen, all_time=True)
else:
date_range = _resolve_date_range(riqi)
if date_range is None:
return Response({
'code': 400,
'msg': '参数错误:无效的日期范围',
'data': {'list': []},
})
rows = self._query_rank_rows(shenfen, date_range[0], date_range[1])
nick_map, avatar_map = self._load_user_display(rows, shenfen)
cfg = ROLE_CONFIG[shenfen]
int_fields = cfg['int_fields']
id_field = cfg['id_field']
result_list = []
for idx, row in enumerate(rows):
yonghuid = row[id_field]
item = {
'mingci': idx + 1,
'yonghuid': yonghuid,
'nicheng': nick_map.get(yonghuid, '用户'),
'touxiang': avatar_map.get(yonghuid, '') or '',
}
for field in cfg['fields']:
item[field] = _fmt_value(row.get(field), field in int_fields)
result_list.append(item)
return Response({
'code': 0,
'msg': '获取成功',
'data': {'list': result_list},
})
except Exception as e:
logger.error('排行榜查询失败 shenfen=%s riqi=%s: %s', shenfen, riqi, e, exc_info=True)
return Response({
'code': 500,
'msg': '服务器内部错误',
'data': {'list': []},
})
def _query_rank_rows(self, shenfen, start_date=None, end_date=None, all_time=False):
cfg = ROLE_CONFIG[shenfen]
model = cfg['model']
sort_field = cfg['sort_field']
fields = cfg['fields']
id_field = cfg['id_field']
annotate_kwargs = {f: Sum(f) for f in fields}
if all_time:
rows = (
model.objects
.values(id_field)
.annotate(**annotate_kwargs)
.order_by(f'-{sort_field}')[:MAX_RANK]
)
return list(rows)
if start_date == end_date:
qs = model.objects.filter(riqi=start_date).order_by(f'-{sort_field}')[:MAX_RANK]
rows = [
{id_field: getattr(r, id_field), **{f: getattr(r, f) for f in fields}}
for r in qs
]
return rows
rows = (
model.objects
.filter(riqi__gte=start_date, riqi__lte=end_date)
.values(id_field)
.annotate(**annotate_kwargs)
.order_by(f'-{sort_field}')[:MAX_RANK]
)
return list(rows)
def _load_user_display(self, rows, shenfen):
id_field = ROLE_CONFIG[shenfen]['id_field']
yonghuids = [r[id_field] for r in rows if r.get(id_field)]
if not yonghuids:
return {}, {}
users = UserMain.objects.filter(yonghuid__in=yonghuids)
avatar_map = {u.yonghuid: u.avatar or '' for u in users}
nick_map = {}
if shenfen == 'dashou':
for p in UserDashou.objects.filter(user__yonghuid__in=yonghuids).select_related('user'):
nick_map[p.user.yonghuid] = p.nicheng or '用户'
elif shenfen == 'shangjia':
for p in UserShangjia.objects.filter(user__yonghuid__in=yonghuids).select_related('user'):
nick_map[p.user.yonghuid] = p.nicheng or '用户'
else:
for b in UserBoss.objects.filter(user__yonghuid__in=yonghuids).select_related('user'):
nick_map[b.user.yonghuid] = b.nickname or '用户'
return nick_map, avatar_map