219 lines
7.6 KiB
Python
219 lines
7.6 KiB
Python
"""
|
||
排行榜接口 — 基于 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 backend.models import (
|
||
DashouRiTongji,
|
||
GuanshiRiTongji,
|
||
ZuzhangRiTongji,
|
||
ShangjiaRiTongji,
|
||
)
|
||
from users.models import UserDashou, UserShangjia, UserBoss
|
||
from gvsdsdk.models import User
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
MAX_RANK = 50
|
||
|
||
RIQI_OPTIONS = frozenset({'今日', '本周', '本月', '总榜', '昨日', '上周', '上月'})
|
||
SHENFEN_OPTIONS = frozenset({'dashou', 'guanshi', 'zuzhang', 'shangjia'})
|
||
|
||
ROLE_CONFIG = {
|
||
'dashou': {
|
||
'model': DashouRiTongji,
|
||
'sort_field': 'chengjiao_zonge',
|
||
'fields': ('jiedan_zongliang', 'chengjiao_zongliang', 'jiedan_zonge', 'chengjiao_zonge'),
|
||
'int_fields': frozenset({'jiedan_zongliang', 'chengjiao_zongliang'}),
|
||
},
|
||
'guanshi': {
|
||
'model': GuanshiRiTongji,
|
||
'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,
|
||
'sort_field': 'shouru_zonge',
|
||
'fields': ('yaoqing_guanshi_shu', 'fenyong_jine', 'shouru_zonge'),
|
||
'int_fields': frozenset({'yaoqing_guanshi_shu'}),
|
||
},
|
||
'shangjia': {
|
||
'model': ShangjiaRiTongji,
|
||
'sort_field': 'jiesuan_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):
|
||
"""根据前端 riqi 参数返回 (start_date, end_date) 闭区间。"""
|
||
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
|
||
|
||
请求参数:
|
||
shenfen: dashou | guanshi | zuzhang | shangjia
|
||
riqi: 今日 | 本周 | 本月 | 总榜 | 昨日 | 上周 | 上月
|
||
|
||
响应 data.list[](最多50条,已按各身份排序字段降序):
|
||
mingci, yonghuid, nicheng, touxiang + 各身份统计字段
|
||
"""
|
||
|
||
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']
|
||
|
||
result_list = []
|
||
for idx, row in enumerate(rows):
|
||
yonghuid = row['yonghuid']
|
||
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': 200,
|
||
'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']
|
||
annotate_kwargs = {f: Sum(f) for f in fields}
|
||
|
||
if all_time:
|
||
rows = (
|
||
model.objects
|
||
.values('yonghuid')
|
||
.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]
|
||
return [
|
||
{'yonghuid': r.yonghuid, **{f: getattr(r, f) for f in fields}}
|
||
for r in qs
|
||
]
|
||
|
||
rows = (
|
||
model.objects
|
||
.filter(riqi__gte=start_date, riqi__lte=end_date)
|
||
.values('yonghuid')
|
||
.annotate(**annotate_kwargs)
|
||
.order_by(f'-{sort_field}')[:MAX_RANK]
|
||
)
|
||
return list(rows)
|
||
|
||
def _load_user_display(self, rows, shenfen):
|
||
yonghuids = [r['yonghuid'] for r in rows if r.get('yonghuid')]
|
||
if not yonghuids:
|
||
return {}, {}
|
||
|
||
users = User.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
|