feat: 抢单大厅假单池,仅改造 ddhq 接口

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-06-28 17:20:53 +08:00
parent 2003ee01a5
commit b050a6895b
4 changed files with 201 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('orders', '0009_penalty_bonus_lock_fields'),
]
operations = [
migrations.CreateModel(
name='FakeGrabOrder',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('OrderID', models.CharField(db_column='dingdan_id', db_index=True, max_length=32, unique=True, verbose_name='订单ID')),
('Amount', models.DecimalField(db_column='jine', decimal_places=2, max_digits=10, verbose_name='订单价格(展示为打手分红)')),
('ProductTypeID', models.IntegerField(db_column='leixing_id', verbose_name='订单类型ID')),
('Description', models.TextField(blank=True, db_column='jieshao', null=True, verbose_name='订单介绍')),
('Remark', models.TextField(blank=True, db_column='beizhu', null=True, verbose_name='订单备注')),
('DispatcherUserID', models.CharField(blank=True, db_column='paidan_yonghuid', max_length=32, null=True, verbose_name='派单者用户ID')),
('DispatcherAvatar', models.CharField(blank=True, db_column='paidan_touxiang', max_length=500, null=True, verbose_name='派单者头像(展示用默认头像)')),
('IsPremiumMerchant', models.BooleanField(db_column='is_youzhi_shangjia', default=False, verbose_name='是否优质商家')),
('Platform', models.IntegerField(db_column='fadan_pingtai', default=1, verbose_name='发单平台:1平台2商家')),
('ClubID', models.CharField(db_column='club_id', db_index=True, default='xq', max_length=16, verbose_name='所属俱乐部')),
('SortOrder', models.IntegerField(default=0, verbose_name='排序(大在前)')),
('CreateTime', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('UpdateTime', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
],
options={
'db_table': 'fake_grab_order',
'indexes': [models.Index(fields=['ClubID', 'ProductTypeID'], name='fake_grab_o_club_id_6a8f2a_idx')],
},
),
]

View File

@@ -1037,6 +1037,59 @@ class ChatSession(QModel):
return f'{self.User1ID} <-> {self.User2ID} ({self.Status})'
class FakeGrabOrder(QModel):
"""抢单大厅假单(仅展示,不可抢单结算)。"""
OrderID = models.CharField(
max_length=32, unique=True, db_index=True,
db_column='dingdan_id', verbose_name='订单ID',
)
Amount = models.DecimalField(
max_digits=10, decimal_places=2,
db_column='jine', verbose_name='订单价格(展示为打手分红)',
)
ProductTypeID = models.IntegerField(
db_column='leixing_id', verbose_name='订单类型ID',
)
Description = models.TextField(
null=True, blank=True,
db_column='jieshao', verbose_name='订单介绍',
)
Remark = models.TextField(
null=True, blank=True,
db_column='beizhu', verbose_name='订单备注',
)
DispatcherUserID = models.CharField(
max_length=32, null=True, blank=True,
db_column='paidan_yonghuid', verbose_name='派单者用户ID',
)
DispatcherAvatar = models.CharField(
max_length=500, null=True, blank=True,
db_column='paidan_touxiang', verbose_name='派单者头像(展示用默认头像)',
)
IsPremiumMerchant = models.BooleanField(
default=False,
db_column='is_youzhi_shangjia', verbose_name='是否优质商家',
)
Platform = models.IntegerField(
default=1,
db_column='fadan_pingtai', verbose_name='发单平台:1平台2商家',
)
ClubID = models.CharField(
max_length=16, default='xq', db_index=True,
db_column='club_id', verbose_name='所属俱乐部',
)
SortOrder = models.IntegerField(default=0, verbose_name='排序(大在前)')
CreateTime = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
UpdateTime = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'fake_grab_order'
indexes = [
models.Index(fields=['ClubID', 'ProductTypeID']),
]
# ===========================================================================
# 兼容别名(渐进迁移,全部迁移完成后可删除)
# ===========================================================================

View File

@@ -0,0 +1,107 @@
"""抢单大厅假单:无资格/封禁打手仅展示假数据。"""
from decimal import Decimal
from django.core.exceptions import ObjectDoesNotExist
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
DEFAULT_DISPATCHER_AVATAR = 'a_long/morentouxiang.jpg'
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 _format_fake_row(row):
"""字段与 DashouDingdanHuoquView 真实单列表保持一致。"""
avatar = DEFAULT_DISPATCHER_AVATAR
platform = int(row.Platform or 1)
oid = row.OrderID
price = float(row.Amount or 0)
ct = fmt_datetime(row.CreateTime)
zid = (row.DispatcherUserID 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_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)
qs = qs.order_by('-SortOrder', '-CreateTime')
total = qs.count()
offset = (page - 1) * page_size
rows = list(qs[offset:offset + page_size])
formatted_list = [_format_fake_row(r) for r in 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,
},
})

View File

@@ -3050,6 +3050,13 @@ class DashouDingdanHuoquView(APIView):
def post(self, request):
try:
from orders.services.fake_order_pool import (
dashou_should_use_fake_pool,
build_fake_order_pool_response,
)
if dashou_should_use_fake_pool(request.user):
return build_fake_order_pool_response(request)
# 1. 获取请求参数
data = request.data
leixing_id = pick_leixing_id(data)