From ceaca8bf4d279b547310e951cdc1fb8cbde24cad Mon Sep 17 00:00:00 2001 From: XingQue Date: Sat, 27 Jun 2026 00:38:03 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=97=A5=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E6=8E=92=E8=A1=8C=E6=A6=9C=E6=8E=A5=E5=8F=A3=20phbhqsj?= =?UTF-8?q?=EF=BC=8C=E9=85=8D=E7=BD=AE=E6=8E=A5=E5=8F=A3=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E6=8E=92=E8=A1=8C=E6=A6=9C=E7=B4=A0=E6=9D=90=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- peizhi/views.py | 9 +- yonghu/paihang_views.py | 289 ++++++++++++++++++++++++++++++++++++++++ yonghu/urls.py | 2 + 3 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 yonghu/paihang_views.py diff --git a/peizhi/views.py b/peizhi/views.py index cdc36c4..46d4fc1 100644 --- a/peizhi/views.py +++ b/peizhi/views.py @@ -88,7 +88,14 @@ class GetDynamicConfigView(APIView): }, "otherConfig": { "morentouxiang": morentouxiang, - "dashouguize": dashouguize + "dashouguize": dashouguize, + "paihangAssets": { + "basePath": "beijing/paihangbang/", + "pageBg": "page-bg.jpg", + "cardBg": "list-card-bg.png", + "emptyIcon": "empty.png", + "refreshIcon": "icon-refresh.png", + }, }, "kefu": { "link": kefu_link, diff --git a/yonghu/paihang_views.py b/yonghu/paihang_views.py new file mode 100644 index 0000000..026960a --- /dev/null +++ b/yonghu/paihang_views.py @@ -0,0 +1,289 @@ +""" +排行榜接口 — 基于 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': 'jiesuan_jine', + 'fields': ('paifa_dingdan_shu', 'paifa_jine', 'jiesuan_dingdan_shu', 'jiesuan_jine'), + 'int_fields': frozenset({'paifa_dingdan_shu', 'jiesuan_dingdan_shu'}), + }, +} + +TODAY_PROFILE_CONFIG = { + 'dashou': { + 'profile_model': UserDashou, + 'profile_sort_field': 'jinrishouyi', + 'field_map': { + 'jiedan_zongliang': 'jinrijiedan', + 'chengjiao_zongliang': 'jinrijiedan', + 'jiedan_zonge': 'jinrishouyi', + 'chengjiao_zonge': 'jinrishouyi', + }, + }, + 'guanshi': { + 'profile_model': UserGuanshi, + 'profile_sort_field': 'jinrichongzhi', + 'field_map': { + 'yaoqing_dashou_shu': None, + 'chongzhi_dashou_shu': 'jinrichongzhi', + 'shouru_zonge': None, + }, + }, + 'zuzhang': { + 'profile_model': UserZuzhang, + 'profile_sort_field': 'jinri_fenyong', + 'field_map': { + 'yaoqing_guanshi_shu': None, + 'fenyong_jine': 'jinri_fenyong', + 'shouru_zonge': 'jinri_fenyong', + }, + }, + 'shangjia': { + 'profile_model': UserShangjia, + 'profile_sort_field': 'jinriliushui', + 'field_map': { + 'paifa_dingdan_shu': 'jinridingdan', + 'paifa_jine': 'jinriliushui', + 'jiesuan_dingdan_shu': None, + 'jiesuan_jine': None, + }, + }, +} + +from yonghu.models import UserGuanshi, UserZuzhang # noqa: E402 — after ROLE_CONFIG + + +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 + ] + if rows: + return rows + today = date.today() + if start_date == today: + return self._query_today_from_profiles(shenfen) + 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 _query_today_from_profiles(self, shenfen): + cfg = ROLE_CONFIG[shenfen] + today_cfg = TODAY_PROFILE_CONFIG[shenfen] + profile_model = today_cfg['profile_model'] + profile_sort = today_cfg['profile_sort_field'] + field_map = today_cfg['field_map'] + id_field = cfg['id_field'] + fields = cfg['fields'] + + qs = profile_model.objects.filter( + **{f'{profile_sort}__gt': 0} + ).select_related('user').order_by(f'-{profile_sort}')[:MAX_RANK] + + rows = [] + for p in qs: + uid = p.user.yonghuid + row = {id_field: uid} + for f in fields: + profile_field = field_map.get(f) + if profile_field: + row[f] = getattr(p, profile_field) + else: + row[f] = 0 + rows.append(row) + return 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 diff --git a/yonghu/urls.py b/yonghu/urls.py index 8c23f2b..5d49da0 100644 --- a/yonghu/urls.py +++ b/yonghu/urls.py @@ -21,6 +21,7 @@ from .views import WechatMiniProgramLoginView, UserInfoUpdateView, DashouXinxiAP KaohePayView,KaohePayCallbackView, KaohePayPollView, KaohePayFailView, TixianAssetView from .tixian_shenhe_views import TixianZddkshApplyView +from .paihang_views import PhbHqsjView urlpatterns = [ @@ -69,6 +70,7 @@ urlpatterns = [ path('shangjiahuce', ShangjiaZhuceView.as_view(), name='商家注册'), path('paihangbang', PaihangbangGuanliQueryView.as_view(), name='管理查询排行榜'), path('adhqphrq', PaihangbangRiqiliebiaoView.as_view(), name='管理原获取排行榜日期'), + path('phbhqsj', PhbHqsjView.as_view(), name='排行榜数据-日统计'),