Files
Django/rank/reward_views.py
XingQue 5ef4ff7c91 feat: 排行榜奖励按俱乐部分奖与手动领取
- 新增奖励方案/档位/结算/领取四表与懒结算服务
- 小程序 phbjlxx/phbjllq/phbjlphb 新接口,phbhqsj 零改动
- 后台 phbjhq/phbjbc/phbjjl 与 phbj666 权限菜单

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 17:40:56 +08:00

236 lines
8.9 KiB
Python
Raw 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.
"""排行榜奖励 — 小程序 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,
list_my_pending_claims,
query_club_rank_rows,
query_group_rank_rows,
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 = get_user_club_id(request.user) or getattr(request.user, 'ClubID', None) or ''
if not cid:
cid = resolve_club_id_from_request(request) or 'xq'
return cid
def _load_display_maps(yonghuids, shenfen):
users = User.objects.filter(UserUID__in=yonghuids)
nick_map = {u.UserUID: u.UserName or u.Phone or '用户' 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):
yonghuids = [r['yonghuid'] for r in rows]
nick_map, avatar_map = _load_display_maps(yonghuids, shenfen)
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),
'metric_value': int(metric) if is_int else float(metric),
'metric_label': sort_label,
}
# 兼容 fighter-rank 现有字段
if is_int:
item['chengjiao_zongliang'] = int(metric)
else:
item['chengjiao_zonge'] = float(metric)
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})
result = claim_reward(claim_id, request.user)
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_models import RankRewardScheme
from rank.reward_services import RIQI_TO_PERIOD, SORT_FIELD_REGISTRY
if not sort_field:
period_type = RIQI_TO_PERIOD.get(riqi)
if period_type and fanwei == 'club':
scheme = RankRewardScheme.query.filter(
club_id=club_id, shenfen=shenfen, period_type=period_type, enabled=True,
).first()
if scheme:
sort_field = scheme.sort_field
if not sort_field:
defaults = {
'dashou': 'chengjiao_zongliang',
'guanshi': 'chongzhi_dashou_shu',
'zuzhang': 'yaoqing_guanshi_shu',
'shangjia': 'jiesuan_jine',
}
sort_field = defaults.get(shenfen, 'chengjiao_zongliang')
if sort_field not in (SORT_FIELD_REGISTRY.get(shenfen) or {}):
return Response({'code': 400, 'msg': '排序指标无效', 'data': {'list': []}})
sort_label = SORT_FIELD_LABELS.get(sort_field, sort_field)
if fanwei == 'club':
rows = query_club_rank_rows(club_id, shenfen, sort_field, riqi)
else:
rows = query_group_rank_rows(shenfen, sort_field, riqi)
result_list = _format_rank_list(rows, shenfen, sort_field, sort_label)
reward = build_reward_payload(club_id, shenfen, riqi, request.user.UserUID)
# 给每行附加该 club 奖励金额(仅 club 方案启用且已结算)
rank_rewards = reward.get('rank_rewards') or {}
for item in result_list:
item['reward_amount'] = rank_rewards.get(item['mingci'], 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}})