fix: 排行榜昵称与管事/组长统计字段对齐

管事/组长不再展示 openid,改读业务昵称;俱乐部榜补充无效/有效邀请与收益字段;管事按有效人数、组长按收益总额排序。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-07 21:49:36 +08:00
parent bfd5a63cb4
commit 1e3d65e0e4
5 changed files with 168 additions and 93 deletions

124
rank/display_utils.py Normal file
View File

@@ -0,0 +1,124 @@
"""排行榜展示名与星之界扩展统计字段。"""
from __future__ import annotations
from django.db.models import Sum
from backend.models import ManagerDailyStats
from users.business_models import User
from users.models import UserBoss, UserDashou, UserGuanshi, UserShangjia
def is_openid_like(value: str) -> bool:
if not value or not isinstance(value, str):
return False
s = value.strip()
# 微信 openid 常见形态
return s.startswith('o') and len(s) >= 20
def resolve_rank_nickname(shenfen: str, user: User, profile_nick: str = '') -> str:
"""展示名:优先业务昵称,禁止把 openid 当昵称。"""
nick = (profile_nick or '').strip()
if nick and not is_openid_like(nick):
return nick
phone = (user.Phone or '').strip()
if phone:
return phone
uname = (user.UserName or '').strip()
if uname and not is_openid_like(uname):
return uname
defaults = {
'dashou': '打手',
'guanshi': '管事',
'zuzhang': '组长',
'shangjia': '商家',
}
return defaults.get(shenfen, '用户')
def load_rank_nicknames(shenfen: str, yonghuids: list) -> dict:
if not yonghuids:
return {}
users = {u.UserUID: u for u in User.objects.filter(UserUID__in=yonghuids)}
nick_map = {}
if shenfen == 'dashou':
for p in UserDashou.objects.filter(user__UserUID__in=yonghuids).select_related('user'):
u = p.user
nick_map[u.UserUID] = resolve_rank_nickname('dashou', u, p.nicheng)
elif shenfen == 'shangjia':
for p in UserShangjia.objects.filter(user__UserUID__in=yonghuids).select_related('user'):
u = p.user
nick_map[u.UserUID] = resolve_rank_nickname('shangjia', u, p.nicheng)
elif shenfen in ('guanshi', 'zuzhang'):
boss_map = {}
for b in UserBoss.objects.filter(user__UserUID__in=yonghuids).select_related('user'):
boss_map[b.user.UserUID] = b.nickname
for uid in yonghuids:
u = users.get(uid)
if not u:
nick_map[uid] = '用户'
continue
nick_map[uid] = resolve_rank_nickname(shenfen, u, boss_map.get(uid, ''))
else:
for uid in yonghuids:
u = users.get(uid)
nick_map[uid] = resolve_rank_nickname(shenfen, u) if u else '用户'
for uid in yonghuids:
nick_map.setdefault(uid, '用户')
return nick_map
def apply_guanshi_wuxiao_fields(stats: dict) -> dict:
invited = int(stats.get('yaoqing_dashou_shu') or 0)
valid = int(stats.get('chongzhi_dashou_shu') or 0)
stats['wuxiao_yaoqing_dashou_shu'] = max(0, invited - valid)
return stats
def count_youxiao_guanshi_for_zuzhang(zuzhang_uid, start_date=None, end_date=None) -> int:
"""组长旗下有充值打手记录的管事人数。"""
guanshi_uids = list(
UserGuanshi.objects.filter(yaoqingren=zuzhang_uid)
.values_list('user__UserUID', flat=True)
)
if not guanshi_uids:
return 0
qs = ManagerDailyStats.objects.filter(ManagerID__in=guanshi_uids)
if start_date and end_date:
qs = qs.filter(Date__gte=start_date, Date__lte=end_date)
qs = (
qs.values('ManagerID')
.annotate(total_rc=Sum('RechargedPlayerCount'))
.filter(total_rc__gt=0)
)
return qs.count()
def apply_zuzhang_wuxiao_fields(stats: dict, zuzhang_uid, start_date=None, end_date=None) -> dict:
invited = int(stats.get('yaoqing_guanshi_shu') or 0)
youxiao = count_youxiao_guanshi_for_zuzhang(zuzhang_uid, start_date, end_date)
stats['youxiao_guanshi_shu'] = youxiao
stats['wuxiao_yaoqing_guanshi_shu'] = max(0, invited - youxiao)
return stats
def enrich_extra_rank_fields(shenfen: str, stats_map: dict, riqi: str = '') -> dict:
"""为管事/组长补充无效/有效邀请等展示字段。"""
from rank.reward_services import _resolve_date_range_for_display
start_date, end_date = None, None
if riqi and riqi != '总榜':
dr = _resolve_date_range_for_display(riqi)
if dr:
start_date, end_date = dr
for uid, stats in stats_map.items():
if not stats:
stats_map[uid] = stats = {}
if shenfen == 'guanshi':
apply_guanshi_wuxiao_fields(stats)
elif shenfen == 'zuzhang':
apply_zuzhang_wuxiao_fields(stats, uid, start_date, end_date)
return stats_map

View File

@@ -47,7 +47,7 @@ OPEN_RIQI_PERIOD_MAP = {
DEFAULT_SORT_FIELD = {
'dashou': 'chengjiao_zongliang',
'guanshi': 'chongzhi_dashou_shu',
'zuzhang': 'yaoqing_guanshi_shu',
'zuzhang': 'shouru_zonge',
'shangjia': 'jiesuan_jine',
}
@@ -82,7 +82,7 @@ SORT_FIELD_LABELS = {
'chengjiao_zonge': '成交总额',
'jiedan_zongliang': '接单量',
'jiedan_zonge': '接单总额',
'chongzhi_dashou_shu': '有效打手',
'chongzhi_dashou_shu': '有效',
'shouru_zonge': '收益总额',
'yaoqing_dashou_shu': '邀请打手数',
'yaoqing_guanshi_shu': '邀请管事数',
@@ -388,14 +388,14 @@ def _enrich_today_profiles(shenfen: str, yonghuids: list) -> dict:
'CompletedAmount': 'jinrishouyi',
}),
'guanshi': (UserGuanshi, {
'InvitedPlayerCount': None,
'InvitedPlayerCount': 'yaogingshuliang',
'RechargedPlayerCount': 'jinrichongzhi',
'TotalIncome': None,
'TotalIncome': 'chongzhifenrun',
}),
'zuzhang': (UserZuzhang, {
'InvitedManagerCount': None,
'InvitedManagerCount': 'yaoqing_zongshu',
'CommissionAmount': 'jinri_fenyong',
'TotalIncome': 'jinri_fenyong',
'TotalIncome': 'fenyong_zonge',
}),
'shangjia': (UserShangjia, {
'AssignedOrderCount': 'jinridingdan',
@@ -443,6 +443,11 @@ def enrich_rank_stats(shenfen: str, yonghuids: list, riqi: str, club_id: str = '
result = {uid: {} for uid in yonghuids}
def _finish():
from rank.display_utils import enrich_extra_rank_fields
enrich_extra_rank_fields(shenfen, result, riqi)
return result
def _fill_from_row(uid, row_data):
for f in fields:
key = response_field_map.get(f, f)
@@ -458,11 +463,11 @@ def enrich_rank_stats(shenfen: str, yonghuids: list, riqi: str, club_id: str = '
uid = r[id_field]
if uid in result:
_fill_from_row(uid, r)
return result
return _finish()
date_range = _resolve_date_range_for_display(riqi)
if not date_range:
return result
return _finish()
start_date, end_date = date_range
if start_date == end_date:
@@ -474,10 +479,13 @@ def enrich_rank_stats(shenfen: str, yonghuids: list, riqi: str, club_id: str = '
continue
row_data = {f: getattr(r, f) for f in fields}
_fill_from_row(uid, row_data)
return result
return _finish()
if riqi == '今日':
return _enrich_today_profiles(shenfen, yonghuids)
return result
today = _enrich_today_profiles(shenfen, yonghuids)
for uid, row in today.items():
result[uid] = {**result.get(uid, {}), **row}
return _finish()
return _finish()
rows = (
model.objects.filter(Date__gte=start_date, Date__lte=end_date, **base_filter)
@@ -488,7 +496,7 @@ def enrich_rank_stats(shenfen: str, yonghuids: list, riqi: str, club_id: str = '
uid = r[id_field]
if uid in result:
_fill_from_row(uid, r)
return result
return _finish()
def load_user_club_map(yonghuids: list) -> dict:

View File

@@ -22,6 +22,7 @@ from rank.reward_services import (
)
from users.business_models import User
from users.models import UserDashou, UserShangjia
from rank.display_utils import load_rank_nicknames
logger = logging.getLogger(__name__)
@@ -41,16 +42,8 @@ def _resolve_club_id(request, data_club_id=''):
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}
nick_map = load_rank_nicknames(shenfen, yonghuids)
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

View File

@@ -19,6 +19,7 @@ from backend.models import (
)
from users.models import UserDashou, UserShangjia, UserGuanshi, UserZuzhang
from users.business_models import User
from rank.display_utils import load_rank_nicknames
logger = logging.getLogger(__name__)
@@ -96,18 +97,18 @@ TODAY_PROFILE_CONFIG = {
'profile_model': UserGuanshi,
'profile_sort_field': 'jinrichongzhi',
'field_map': {
'InvitedPlayerCount': None,
'InvitedPlayerCount': 'yaogingshuliang',
'RechargedPlayerCount': 'jinrichongzhi',
'TotalIncome': None,
'TotalIncome': 'chongzhifenrun',
},
},
'zuzhang': {
'profile_model': UserZuzhang,
'profile_sort_field': 'jinri_fenyong',
'profile_sort_field': 'fenyong_zonge',
'field_map': {
'InvitedManagerCount': None,
'InvitedManagerCount': 'yaoqing_zongshu',
'CommissionAmount': 'jinri_fenyong',
'TotalIncome': 'jinri_fenyong',
'TotalIncome': 'fenyong_zonge',
},
},
'shangjia': {
@@ -313,16 +314,5 @@ class PhbHqsjView(APIView):
users = User.objects.filter(UserUID__in=yonghuids)
avatar_map = {u.UserUID: u.Avatar or '' for u in users}
nick_map = {u.UserUID: u.UserName or u.Phone 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
nick_map = load_rank_nicknames(shenfen, yonghuids)
return nick_map, avatar_map

View File

@@ -55,7 +55,7 @@ XZJ_ROLE_CONFIG = {
'guanshi': {
'model': ManagerDailyStats,
'id_field': 'ManagerID',
'sort_field': 'InvitedPlayerCount',
'sort_field': 'RechargedPlayerCount',
'fields': ('InvitedPlayerCount', 'RechargedPlayerCount', 'TotalIncome'),
'int_fields': frozenset({'InvitedPlayerCount', 'RechargedPlayerCount'}),
'response_field_map': {
@@ -63,14 +63,14 @@ XZJ_ROLE_CONFIG = {
'RechargedPlayerCount': 'chongzhi_dashou_shu',
'TotalIncome': 'shouru_zonge',
},
'sort_response_key': 'yaoqing_dashou_shu',
'sort_response_key': 'chongzhi_dashou_shu',
'wuxiao_field': 'wuxiao_yaoqing_dashou_shu',
'youxiao_field': 'chongzhi_dashou_shu',
},
'zuzhang': {
'model': LeaderDailyStats,
'id_field': 'LeaderID',
'sort_field': 'InvitedManagerCount',
'sort_field': 'TotalIncome',
'fields': ('InvitedManagerCount', 'CommissionAmount', 'TotalIncome'),
'int_fields': frozenset({'InvitedManagerCount'}),
'response_field_map': {
@@ -78,7 +78,7 @@ XZJ_ROLE_CONFIG = {
'CommissionAmount': 'fenyong_jine',
'TotalIncome': 'shouru_zonge',
},
'sort_response_key': 'yaoqing_guanshi_shu',
'sort_response_key': 'shouru_zonge',
'wuxiao_field': 'wuxiao_yaoqing_guanshi_shu',
'youxiao_field': 'youxiao_guanshi_shu',
},
@@ -109,7 +109,7 @@ XZJ_TODAY_PROFILE = {
},
'guanshi': {
'profile_model': UserGuanshi,
'profile_sort_field': 'yaogingshuliang',
'profile_sort_field': 'jinrichongzhi',
'field_map': {
'InvitedPlayerCount': 'yaogingshuliang',
'RechargedPlayerCount': 'jinrichongzhi',
@@ -118,11 +118,11 @@ XZJ_TODAY_PROFILE = {
},
'zuzhang': {
'profile_model': UserZuzhang,
'profile_sort_field': 'yaoqing_zongshu',
'profile_sort_field': 'fenyong_zonge',
'field_map': {
'InvitedManagerCount': 'yaoqing_zongshu',
'CommissionAmount': 'jinri_fenyong',
'TotalIncome': 'jinri_fenyong',
'TotalIncome': 'fenyong_zonge',
},
},
'shangjia': {
@@ -138,40 +138,11 @@ XZJ_TODAY_PROFILE = {
# UserZuzhang 用于今日组长 profile 回退
def _apply_guanshi_wuxiao(item):
invited = int(item.get('yaoqing_dashou_shu') or 0)
valid = int(item.get('chongzhi_dashou_shu') or 0)
item['wuxiao_yaoqing_dashou_shu'] = max(0, invited - valid)
return item
def _count_youxiao_guanshi_for_zuzhang(zuzhang_uid, start_date=None, end_date=None):
"""组长旗下有充值打手记录的管事人数。"""
guanshi_uids = list(
UserGuanshi.objects.filter(yaoqingren=zuzhang_uid)
.values_list('user__UserUID', flat=True)
from rank.display_utils import (
apply_guanshi_wuxiao_fields,
apply_zuzhang_wuxiao_fields,
load_rank_nicknames,
)
if not guanshi_uids:
return 0
qs = ManagerDailyStats.objects.filter(ManagerID__in=guanshi_uids)
if start_date and end_date:
qs = qs.filter(Date__gte=start_date, Date__lte=end_date)
qs = (
qs.values('ManagerID')
.annotate(total_rc=Sum('RechargedPlayerCount'))
.filter(total_rc__gt=0)
)
return qs.count()
def _apply_zuzhang_wuxiao(item, start_date=None, end_date=None):
zuzhang_uid = item.get('yonghuid')
invited = int(item.get('yaoqing_guanshi_shu') or 0)
youxiao = _count_youxiao_guanshi_for_zuzhang(zuzhang_uid, start_date, end_date)
item['youxiao_guanshi_shu'] = youxiao
item['wuxiao_yaoqing_guanshi_shu'] = max(0, invited - youxiao)
return item
class XzjPhbHqsjView(APIView):
"""
@@ -237,9 +208,9 @@ class XzjPhbHqsjView(APIView):
item[response_key] = _fmt_value(row.get(field), field in int_fields)
if shenfen == 'guanshi':
_apply_guanshi_wuxiao(item)
apply_guanshi_wuxiao_fields(item)
elif shenfen == 'zuzhang':
_apply_zuzhang_wuxiao(item, start_date, end_date)
apply_zuzhang_wuxiao_fields(item, yonghuid, start_date, end_date)
result_list.append(item)
@@ -324,16 +295,5 @@ class XzjPhbHqsjView(APIView):
users = User.objects.filter(UserUID__in=yonghuids)
avatar_map = {u.UserUID: u.Avatar or '' for u in users}
nick_map = {}
if shenfen == 'dashou':
for p in UserDashou.objects.filter(user__UserUID__in=yonghuids).select_related('user'):
nick_map[p.user.UserUID] = p.nicheng or '用户'
elif shenfen == 'shangjia':
for p in UserShangjia.objects.filter(user__UserUID__in=yonghuids).select_related('user'):
nick_map[p.user.UserUID] = p.nicheng or '用户'
else:
for b in UserBoss.objects.filter(user__UserUID__in=yonghuids).select_related('user'):
nick_map[b.user.UserUID] = b.nickname or '用户'
nick_map = load_rank_nicknames(shenfen, yonghuids)
return nick_map, avatar_map