"""排行榜奖励 — 小程序 API(不修改 phbhqsj)。""" import logging from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView from jituan.models import Club from jituan.services.club_user import get_user_club_id from rank.reward_services import ( BALANCE_FIELD_MAP, OPEN_RIQI, SORT_FIELD_LABELS, build_reward_payload, claim_reward, enrich_rank_stats, list_my_pending_claims, query_club_rank_rows, query_group_rank_rows, resolve_sort_field_for_display, sort_field_options_for_shenfen, ) from users.business_models import User from users.models import UserDashou, UserShangjia logger = logging.getLogger(__name__) SHENFEN_OPTIONS = frozenset({'dashou', 'guanshi', 'zuzhang', 'shangjia'}) RIQI_OPTIONS = frozenset({'今日', '本周', '本月', '总榜', '昨日', '上周', '上月'}) def _resolve_club_id(request, data_club_id=''): from jituan.services.club_context import resolve_club_id_from_request cid = (data_club_id or '').strip() if not cid: cid = resolve_club_id_from_request(request) or '' if not cid: cid = get_user_club_id(request.user) or getattr(request.user, 'ClubID', None) or '' return cid or 'xq' def _load_display_maps(yonghuids, shenfen): users = User.objects.filter(UserUID__in=yonghuids) nick_map = {u.UserUID: (u.UserName or u.Phone or u.UserUID) for u in users} avatar_map = {u.UserUID: u.Avatar or '' for u in users} if shenfen == 'dashou': for p in UserDashou.objects.filter(user__UserUID__in=yonghuids).select_related('user'): if p.nicheng: nick_map[p.user.UserUID] = p.nicheng elif shenfen == 'shangjia': for p in UserShangjia.objects.filter(user__UserUID__in=yonghuids).select_related('user'): if p.nicheng: nick_map[p.user.UserUID] = p.nicheng return nick_map, avatar_map def _format_rank_list(rows, shenfen, sort_field, sort_label, riqi='', club_id=''): yonghuids = [r['yonghuid'] for r in rows] nick_map, avatar_map = _load_display_maps(yonghuids, shenfen) stats_map = enrich_rank_stats(shenfen, yonghuids, riqi, club_id or '') club_map = {} try: from rank.reward_services import load_user_club_map club_map = load_user_club_map(yonghuids) except Exception: pass club_names = {} if club_map: cids = set(club_map.values()) - {''} for c in Club.query.filter(club_id__in=cids): club_names[c.club_id] = c.name result = [] for idx, row in enumerate(rows): uid = row['yonghuid'] cid = club_map.get(uid, '') metric = row['metric'] is_int = row.get('is_int', False) item = { 'mingci': idx + 1, 'yonghuid': uid, 'nicheng': nick_map.get(uid, '用户'), 'touxiang': avatar_map.get(uid, '') or '', 'club_id': cid, 'club_name': club_names.get(cid, cid), 'sort_field': sort_field, 'metric_value': int(metric) if is_int else float(metric), 'metric_label': sort_label, 'metric_is_int': is_int, } extra = stats_map.get(uid) or {} for k, v in extra.items(): item[k] = v item[sort_field] = item['metric_value'] result.append(item) return result class PhbJlXxView(APIView): """POST /yonghu/phbjlxx 奖励规则 + 我的待领/已领(按俱乐部分奖)""" permission_classes = [IsAuthenticated] def post(self, request): shenfen = (request.data.get('shenfen') or 'dashou').strip() riqi = (request.data.get('riqi') or '上周').strip() club_id = _resolve_club_id(request, request.data.get('club_id')) if shenfen not in SHENFEN_OPTIONS: return Response({'code': 400, 'msg': '身份参数错误', 'data': None}) if riqi not in RIQI_OPTIONS: return Response({'code': 400, 'msg': '周期参数错误', 'data': None}) uid = request.user.UserUID payload = build_reward_payload(club_id, shenfen, riqi, uid) payload['balance_hint'] = BALANCE_FIELD_MAP.get(shenfen, '') return Response({'code': 200, 'msg': 'success', 'data': payload}) class PhbJlWdView(APIView): """POST /yonghu/phbjlwd 我的全部待领取""" permission_classes = [IsAuthenticated] def post(self, request): club_id = _resolve_club_id(request, request.data.get('club_id')) items = list_my_pending_claims(request.user.UserUID, club_id) return Response({'code': 200, 'msg': 'success', 'data': {'list': items, 'total': len(items)}}) class PhbJlLqView(APIView): """POST /yonghu/phbjllq 领取奖励""" permission_classes = [IsAuthenticated] def post(self, request): claim_id = request.data.get('claim_id') if not claim_id: return Response({'code': 400, 'msg': '缺少 claim_id', 'data': None}) try: claim_id = int(claim_id) except (TypeError, ValueError): return Response({'code': 400, 'msg': 'claim_id 无效', 'data': None}) shenfen = (request.data.get('shenfen') or '').strip() result = claim_reward(claim_id, request.user, request_shenfen=shenfen) if not result.get('ok'): return Response({'code': 400, 'msg': result.get('msg', '领取失败'), 'data': None}) return Response({ 'code': 200, 'msg': result.get('msg', '领取成功'), 'data': { 'amount': result.get('amount'), 'shenfen': result.get('shenfen'), 'duplicate': result.get('duplicate', False), }, }) class PhbJlPhbView(APIView): """ POST /yonghu/phbjlphb 俱乐部榜 / 集团榜(展示用);分奖仍只按 club 方案。 fanwei: jituan | club """ permission_classes = [IsAuthenticated] def post(self, request): shenfen = (request.data.get('shenfen') or 'dashou').strip() riqi = (request.data.get('riqi') or '今日').strip() fanwei = (request.data.get('fanwei') or 'jituan').strip() club_id = _resolve_club_id(request, request.data.get('club_id')) sort_field = (request.data.get('sort_field') or '').strip() if shenfen not in SHENFEN_OPTIONS: return Response({'code': 400, 'msg': '身份参数错误', 'data': {'list': []}}) if riqi not in RIQI_OPTIONS: return Response({'code': 400, 'msg': '周期参数错误', 'data': {'list': []}}) from rank.reward_services import SORT_FIELD_REGISTRY scheme_sort, sort_label = resolve_sort_field_for_display(club_id, shenfen, riqi) if not sort_field: sort_field = scheme_sort elif sort_field not in (SORT_FIELD_REGISTRY.get(shenfen) or {}): return Response({'code': 400, 'msg': '排序指标无效', 'data': {'list': []}}) else: sort_label = SORT_FIELD_LABELS.get(sort_field, sort_field) if fanwei == 'club': rows = query_club_rank_rows(club_id, shenfen, sort_field, riqi) enrich_club = club_id else: rows = query_group_rank_rows(shenfen, sort_field, riqi) enrich_club = '' result_list = _format_rank_list( rows, shenfen, sort_field, sort_label, riqi=riqi, club_id=enrich_club, ) reward = build_reward_payload(club_id, shenfen, riqi, request.user.UserUID) # 仅俱乐部榜展示各行奖金(集团总榜名次与俱乐部分奖名次不同,不可混用) rank_rewards = reward.get('rank_rewards') or {} tier_rewards = reward.get('tier_rewards') or {} tiers = reward.get('tiers') or [] if fanwei == 'club' and (reward.get('scheme_enabled') or tiers): for item in result_list: mc = item['mingci'] settled = rank_rewards.get(mc) preview = tier_rewards.get(mc, 0) item['reward_amount'] = settled if settled else preview item['reward_is_preview'] = not settled and preview > 0 return Response({ 'code': 200, 'msg': '获取成功', 'data': { 'list': result_list, 'fanwei': fanwei, 'club_id': club_id, 'sort_field': sort_field, 'sort_label': sort_label, 'reward': reward, }, }) class PhbJlClubListView(APIView): """POST /yonghu/phbjljlb 有奖励方案的俱乐部列表(展示筛选用)""" permission_classes = [IsAuthenticated] def post(self, request): from rank.reward_models import RankRewardScheme cids = RankRewardScheme.query.filter(enabled=True).values_list('club_id', flat=True).distinct() clubs = [] for c in Club.query.filter(club_id__in=list(cids)).order_by('sort_order', 'club_id'): clubs.append({'club_id': c.club_id, 'name': c.name}) my_club = _resolve_club_id(request) return Response({'code': 200, 'msg': 'success', 'data': {'clubs': clubs, 'my_club_id': my_club}})