156 lines
5.0 KiB
Python
156 lines
5.0 KiB
Python
"""抢单大厅假单:无资格/封禁打手仅展示假数据。"""
|
||
import random
|
||
from datetime import timedelta
|
||
from decimal import Decimal
|
||
|
||
from django.core.exceptions import ObjectDoesNotExist
|
||
from django.db import transaction
|
||
from django.utils import timezone
|
||
from rest_framework.response import Response
|
||
|
||
from backend.utils import fmt_datetime, pick_leixing_id
|
||
from jituan.services.club_context import resolve_effective_club_id
|
||
from jituan.services.dashou_exam import user_has_active_member
|
||
from orders.models import FakeGrabOrder, FakeGrabOrderShuffleState
|
||
|
||
DEFAULT_DISPATCHER_AVATAR = 'beijing/morentouxiang.jpg'
|
||
SHUFFLE_STATE_PK = 1
|
||
|
||
|
||
def dashou_should_use_fake_pool(user):
|
||
"""
|
||
打手是否只能看假单:
|
||
- 账号封禁(zhanghaozhuangtai != 1)
|
||
- 或未开通有效会员 且 押金不大于 5
|
||
"""
|
||
try:
|
||
dashou = user.DashouProfile
|
||
except ObjectDoesNotExist:
|
||
return True
|
||
|
||
if dashou.zhanghaozhuangtai != 1:
|
||
return True
|
||
|
||
yajin = Decimal(str(dashou.yajin or 0))
|
||
if yajin > Decimal('5'):
|
||
return False
|
||
|
||
if user_has_active_member(user.UserUID):
|
||
return False
|
||
|
||
return True
|
||
|
||
|
||
def _random_display_time_str():
|
||
"""返回给前端的创建时间:当前请求时刻 2~5 分钟前的随机时间。"""
|
||
seconds_ago = random.randint(120, 300)
|
||
dt = timezone.now() - timedelta(seconds=seconds_ago)
|
||
return fmt_datetime(dt)
|
||
|
||
|
||
def _resolve_shuffle_epoch():
|
||
"""
|
||
全用户共用 id=1 一条记录:
|
||
- 已满 IntervalSeconds(默认120秒):更新 LastShuffleTime
|
||
- 未满:不更新,沿用上次时刻
|
||
同一窗口内所有用户用相同 seed,刷新不会变顺序。
|
||
"""
|
||
now = timezone.now()
|
||
with transaction.atomic():
|
||
state, created = FakeGrabOrderShuffleState.objects.select_for_update().get_or_create(
|
||
pk=SHUFFLE_STATE_PK,
|
||
defaults={
|
||
'LastShuffleTime': now - timedelta(days=1),
|
||
'IntervalSeconds': 120,
|
||
},
|
||
)
|
||
interval = max(1, int(state.IntervalSeconds or 120))
|
||
elapsed = (now - state.LastShuffleTime).total_seconds()
|
||
if created or elapsed >= interval:
|
||
state.LastShuffleTime = now
|
||
state.save(update_fields=['LastShuffleTime', 'UpdateTime'])
|
||
return int(state.LastShuffleTime.timestamp())
|
||
|
||
|
||
def _order_fake_rows(rows, shuffle_epoch):
|
||
"""按全局 epoch 固定打乱;2 分钟内所有人顺序一致。"""
|
||
base = sorted(list(rows), key=lambda r: (r.id or 0, r.OrderID or ''))
|
||
rng = random.Random(shuffle_epoch)
|
||
rng.shuffle(base)
|
||
return base
|
||
|
||
|
||
def _format_fake_row(row, display_time=None):
|
||
"""字段与 DashouDingdanHuoquView 真实单列表保持一致。"""
|
||
# 平台单用 tupian、商家单用 tupian + sj_avatar,统一默认头像
|
||
avatar = DEFAULT_DISPATCHER_AVATAR
|
||
platform = int(row.Platform or 1)
|
||
oid = row.OrderID
|
||
price = float(row.Amount or 0)
|
||
ct = display_time or _random_display_time_str()
|
||
zid = (row.DispatcherUserID or '').strip()
|
||
sj_name = (getattr(row, 'MerchantNickname', None) or '').strip()
|
||
|
||
return {
|
||
'dingdan_id': oid,
|
||
'zhuangtai': 1,
|
||
'pingtai': platform,
|
||
'dashou_fencheng': price,
|
||
'leixing_id': row.ProductTypeID or 0,
|
||
'tupian': avatar,
|
||
'yaoqiuleixing': 0,
|
||
'huiyuan_id': '',
|
||
'yajin': 0.0,
|
||
'jieshao': row.Description or '',
|
||
'beizhu': row.Remark or '',
|
||
'creat_time': ct,
|
||
'create_time': ct,
|
||
'sjnicheng': sj_name if platform == 2 else '',
|
||
'sj_avatar': avatar if platform == 2 else '',
|
||
'zhiding_uid': zid,
|
||
'zhiding_avatar': avatar,
|
||
'zhiding_nicheng': '',
|
||
'xuqiu_biaoqian': [],
|
||
'dashou_biaoqian': [],
|
||
'shangjia_biaoqian': [],
|
||
'shangjia_identity_biaoqian': [],
|
||
'zhiding_identity_biaoqian': [],
|
||
'shangjia_youzhi': bool(row.IsPremiumMerchant) if platform == 2 else False,
|
||
}
|
||
|
||
|
||
def build_fake_order_pool_response(request):
|
||
data = request.data
|
||
leixing_id = pick_leixing_id(data)
|
||
page = max(1, int(data.get('page', 1)))
|
||
page_size = max(1, min(int(data.get('page_size', 10)), 50))
|
||
|
||
club_id = resolve_effective_club_id(request, getattr(request, 'user', None))
|
||
|
||
qs = FakeGrabOrder.query.filter(ClubID=club_id)
|
||
if leixing_id is not None:
|
||
qs = qs.filter(ProductTypeID=leixing_id)
|
||
|
||
shuffle_epoch = _resolve_shuffle_epoch()
|
||
rows = _order_fake_rows(qs, shuffle_epoch)
|
||
|
||
total = len(rows)
|
||
offset = (page - 1) * page_size
|
||
page_rows = rows[offset:offset + page_size]
|
||
|
||
formatted_list = [_format_fake_row(r) for r in page_rows]
|
||
has_more = (page * page_size) < total
|
||
|
||
return Response({
|
||
'code': 200,
|
||
'msg': '获取成功',
|
||
'data': {
|
||
'list': formatted_list,
|
||
'has_more': has_more,
|
||
'total': total,
|
||
'current_page': page,
|
||
'page_size': page_size,
|
||
'total_pages': (total + page_size - 1) // page_size if page_size else 0,
|
||
},
|
||
})
|