feat: 假单种子脚本、商家名称字段、返回随机顺序与时间
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
0
orders/management/__init__.py
Normal file
0
orders/management/__init__.py
Normal file
0
orders/management/commands/__init__.py
Normal file
0
orders/management/commands/__init__.py
Normal file
154
orders/management/commands/seed_fake_grab_orders.py
Normal file
154
orders/management/commands/seed_fake_grab_orders.py
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
"""写入抢单大厅假单种子数据。用法: python manage.py seed_fake_grab_orders --club-id xq --leixing-id 1"""
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from orders.models import FakeGrabOrder
|
||||||
|
|
||||||
|
DEFAULT_AVATAR = 'a_long/morentouxiang.jpg'
|
||||||
|
|
||||||
|
COMMON_TAIL = (
|
||||||
|
'下单凑七套,不卡保底,不要私藏变卖,私藏变卖老板必退款,'
|
||||||
|
'陪护也不能私藏,不能藏一丁点装备和变卖,不然必退款和罚款。'
|
||||||
|
)
|
||||||
|
|
||||||
|
# 7 个模板(各生成 2 条 = 14 条)
|
||||||
|
TEMPLATE_ROWS = [
|
||||||
|
{
|
||||||
|
'title': '2100W',
|
||||||
|
'description': f'打手选图保底2100W,{COMMON_TAIL}',
|
||||||
|
'amount': '35.00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': '4光子鸡',
|
||||||
|
'description': (
|
||||||
|
'单据4个光子鸡,不出,一直打,下单凑七套,装备和收益都归老板,'
|
||||||
|
'不卡保底,不要私藏变卖,私藏变卖老板必退款,陪护也不能私藏,'
|
||||||
|
'不能藏一丁点装备和变卖,不然必退款和罚款。'
|
||||||
|
),
|
||||||
|
'amount': '30.00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': '3金光',
|
||||||
|
'description': (
|
||||||
|
'单局出3个金光,下单凑七套,装备和收益都归老板,'
|
||||||
|
'不卡保底,不要私藏变卖,私藏变卖老板必退款,陪护也不能私藏,'
|
||||||
|
'不能藏一丁点装备和变卖,不然必退款和罚款。'
|
||||||
|
),
|
||||||
|
'amount': '20.00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': '1500W',
|
||||||
|
'description': f'打手选图保底1500W,{COMMON_TAIL}',
|
||||||
|
'amount': '25.00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': '300W',
|
||||||
|
'description': f'保底,300w以上,{COMMON_TAIL}',
|
||||||
|
'amount': '6.00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': '4金条',
|
||||||
|
'description': (
|
||||||
|
'单据4根,金条不出,一直打,下单凑七套,装备和收益都归老板,'
|
||||||
|
'不卡保底,不要私藏变卖,私藏变卖老板必退款,陪护也不能私藏,'
|
||||||
|
'不能藏一丁点装备和变卖,不然必退款和罚款。'
|
||||||
|
),
|
||||||
|
'amount': '18.00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': '1000W',
|
||||||
|
'description': f'打手选图保底1000W,{COMMON_TAIL}',
|
||||||
|
'amount': '15.00',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
MERCHANT_NAMES = [
|
||||||
|
'官方直营店',
|
||||||
|
'接单秒结',
|
||||||
|
'没实力的别接',
|
||||||
|
'骂老板4千家',
|
||||||
|
]
|
||||||
|
|
||||||
|
# 14 条:平台 5 + 商家 9;优质商家 6(仅商家单)
|
||||||
|
# 索引 0-13 对应 7 模板各 2 条
|
||||||
|
PLATFORM_INDEXES = {0, 1, 2, 3, 4}
|
||||||
|
PREMIUM_MERCHANT_INDEXES = {5, 6, 7, 8, 9, 10}
|
||||||
|
REMARK_INDEXES = {2, 5, 8, 11}
|
||||||
|
REMARK_TEXT = '打的好奖励鸡腿'
|
||||||
|
|
||||||
|
POOL_USER_IDS = ['3829104', '5829104', '1928374', '6649201', '7731045', '8812345']
|
||||||
|
|
||||||
|
|
||||||
|
def _gen_order_id(used):
|
||||||
|
while True:
|
||||||
|
oid = f'JD{int(time.time() * 1000)}{random.randint(1000, 9999)}'
|
||||||
|
if oid not in used:
|
||||||
|
used.add(oid)
|
||||||
|
return oid
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = '写入抢单大厅假单(7 模板 ×2 = 14 条,可重复执行会先清理同俱乐部+类型旧 JD 假单)'
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument('--club-id', default='xq', help='俱乐部 ID,默认 xq')
|
||||||
|
parser.add_argument('--leixing-id', type=int, default=1, help='商品类型 ID(与抢单大厅 Tab 一致)')
|
||||||
|
parser.add_argument('--no-clear', action='store_true', help='不清理旧 JD 假单,直接追加(可能 ID 冲突)')
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
club_id = (options['club_id'] or 'xq').strip()
|
||||||
|
leixing_id = int(options['leixing_id'])
|
||||||
|
now = timezone.now()
|
||||||
|
|
||||||
|
if not options['no_clear']:
|
||||||
|
deleted, _ = FakeGrabOrder.query.filter(
|
||||||
|
ClubID=club_id,
|
||||||
|
ProductTypeID=leixing_id,
|
||||||
|
OrderID__startswith='JD',
|
||||||
|
).delete()
|
||||||
|
self.stdout.write(f'已清理旧假单 {deleted} 条(club={club_id}, leixing={leixing_id})')
|
||||||
|
|
||||||
|
used_ids = set()
|
||||||
|
expanded = []
|
||||||
|
for tpl in TEMPLATE_ROWS:
|
||||||
|
expanded.append(tpl)
|
||||||
|
expanded.append(tpl)
|
||||||
|
|
||||||
|
created = 0
|
||||||
|
for idx, tpl in enumerate(expanded):
|
||||||
|
is_platform = idx in PLATFORM_INDEXES
|
||||||
|
is_premium = idx in PREMIUM_MERCHANT_INDEXES and not is_platform
|
||||||
|
remark = REMARK_TEXT if idx in REMARK_INDEXES else ''
|
||||||
|
|
||||||
|
merchant_name = ''
|
||||||
|
if not is_platform:
|
||||||
|
merchant_name = MERCHANT_NAMES[idx % len(MERCHANT_NAMES)]
|
||||||
|
|
||||||
|
dispatcher_id = random.choice(POOL_USER_IDS)
|
||||||
|
|
||||||
|
FakeGrabOrder.query.create(
|
||||||
|
OrderID=_gen_order_id(used_ids),
|
||||||
|
Amount=tpl['amount'],
|
||||||
|
ProductTypeID=leixing_id,
|
||||||
|
Description=tpl['description'],
|
||||||
|
Remark=remark,
|
||||||
|
DispatcherUserID=dispatcher_id,
|
||||||
|
DispatcherAvatar=DEFAULT_AVATAR,
|
||||||
|
MerchantNickname=merchant_name,
|
||||||
|
IsPremiumMerchant=is_premium,
|
||||||
|
Platform=1 if is_platform else 2,
|
||||||
|
ClubID=club_id,
|
||||||
|
SortOrder=100 - idx,
|
||||||
|
CreateTime=now,
|
||||||
|
UpdateTime=now,
|
||||||
|
)
|
||||||
|
created += 1
|
||||||
|
|
||||||
|
self.stdout.write(self.style.SUCCESS(
|
||||||
|
f'假单种子完成:新增 {created} 条 | club={club_id} leixing_id={leixing_id} '
|
||||||
|
f'(平台单 {len(PLATFORM_INDEXES)} 商家单 {created - len(PLATFORM_INDEXES)} '
|
||||||
|
f'优质商家 {len(PREMIUM_MERCHANT_INDEXES)})'
|
||||||
|
))
|
||||||
22
orders/migrations/0011_fakegraborder_merchantnickname.py
Normal file
22
orders/migrations/0011_fakegraborder_merchantnickname.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('orders', '0010_fakegraborder'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='fakegraborder',
|
||||||
|
name='MerchantNickname',
|
||||||
|
field=models.CharField(
|
||||||
|
blank=True,
|
||||||
|
db_column='shangjia_nicheng',
|
||||||
|
max_length=50,
|
||||||
|
null=True,
|
||||||
|
verbose_name='商家名称(假单展示)',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1067,6 +1067,10 @@ class FakeGrabOrder(QModel):
|
|||||||
max_length=500, null=True, blank=True,
|
max_length=500, null=True, blank=True,
|
||||||
db_column='paidan_touxiang', verbose_name='派单者头像(展示用默认头像)',
|
db_column='paidan_touxiang', verbose_name='派单者头像(展示用默认头像)',
|
||||||
)
|
)
|
||||||
|
MerchantNickname = models.CharField(
|
||||||
|
max_length=50, null=True, blank=True,
|
||||||
|
db_column='shangjia_nicheng', verbose_name='商家名称(假单展示)',
|
||||||
|
)
|
||||||
IsPremiumMerchant = models.BooleanField(
|
IsPremiumMerchant = models.BooleanField(
|
||||||
default=False,
|
default=False,
|
||||||
db_column='is_youzhi_shangjia', verbose_name='是否优质商家',
|
db_column='is_youzhi_shangjia', verbose_name='是否优质商家',
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
"""抢单大厅假单:无资格/封禁打手仅展示假数据。"""
|
"""抢单大厅假单:无资格/封禁打手仅展示假数据。"""
|
||||||
|
import random
|
||||||
|
from datetime import timedelta
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.utils import timezone
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from backend.utils import fmt_datetime, pick_leixing_id
|
from backend.utils import fmt_datetime, pick_leixing_id
|
||||||
@@ -36,14 +39,22 @@ def dashou_should_use_fake_pool(user):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _format_fake_row(row):
|
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 _format_fake_row(row, display_time=None):
|
||||||
"""字段与 DashouDingdanHuoquView 真实单列表保持一致。"""
|
"""字段与 DashouDingdanHuoquView 真实单列表保持一致。"""
|
||||||
avatar = DEFAULT_DISPATCHER_AVATAR
|
avatar = DEFAULT_DISPATCHER_AVATAR
|
||||||
platform = int(row.Platform or 1)
|
platform = int(row.Platform or 1)
|
||||||
oid = row.OrderID
|
oid = row.OrderID
|
||||||
price = float(row.Amount or 0)
|
price = float(row.Amount or 0)
|
||||||
ct = fmt_datetime(row.CreateTime)
|
ct = display_time or _random_display_time_str()
|
||||||
zid = (row.DispatcherUserID or '').strip()
|
zid = (row.DispatcherUserID or '').strip()
|
||||||
|
sj_name = (getattr(row, 'MerchantNickname', None) or '').strip()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'dingdan_id': oid,
|
'dingdan_id': oid,
|
||||||
@@ -59,7 +70,7 @@ def _format_fake_row(row):
|
|||||||
'beizhu': row.Remark or '',
|
'beizhu': row.Remark or '',
|
||||||
'creat_time': ct,
|
'creat_time': ct,
|
||||||
'create_time': ct,
|
'create_time': ct,
|
||||||
'sjnicheng': '',
|
'sjnicheng': sj_name if platform == 2 else '',
|
||||||
'sj_avatar': avatar if platform == 2 else '',
|
'sj_avatar': avatar if platform == 2 else '',
|
||||||
'zhiding_uid': zid,
|
'zhiding_uid': zid,
|
||||||
'zhiding_avatar': avatar,
|
'zhiding_avatar': avatar,
|
||||||
@@ -85,12 +96,14 @@ def build_fake_order_pool_response(request):
|
|||||||
if leixing_id is not None:
|
if leixing_id is not None:
|
||||||
qs = qs.filter(ProductTypeID=leixing_id)
|
qs = qs.filter(ProductTypeID=leixing_id)
|
||||||
|
|
||||||
qs = qs.order_by('-SortOrder', '-CreateTime')
|
rows = list(qs)
|
||||||
total = qs.count()
|
random.shuffle(rows)
|
||||||
offset = (page - 1) * page_size
|
|
||||||
rows = list(qs[offset:offset + page_size])
|
|
||||||
|
|
||||||
formatted_list = [_format_fake_row(r) for r in rows]
|
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
|
has_more = (page * page_size) < total
|
||||||
|
|
||||||
return Response({
|
return Response({
|
||||||
|
|||||||
Reference in New Issue
Block a user