feat: 龙先生审核版游戏护航商品种子脚本

仅 lxs;shenhezhuangtai=2;正向陪伴文案;默认头像图;dry-run + 双确认。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-24 17:47:25 +08:00
parent d771add6e8
commit 12d01614e9

View File

@@ -0,0 +1,311 @@
# -*- coding: utf-8 -*-
"""
为龙先生电竞(lxs)写入审核专用(shenhezhuangtai=2)「游戏护航/陪伴」公共商品目录。
范围:
- 仅 club_id=lxs名称须含「龙先生」
- 全局审核类型:取 ShangpinLeixing 中 shenhezhuangtai=2 的第一条;若无则创建「娱乐护航」
- 创建若干审核专区30 个商品主要挂在第一个专区
- 商品图统一用默认头像相对路径 a_long/morentouxiang.jpg
- 文案仅正向「护航/陪伴/开黑」,绝不出现代练、代打、上分等
不碰:正常商品(shenhezhuangtai=1)、其它俱乐部、店铺商品。
用法:
python manage.py seed_lxs_shenhe_huhang_catalog
python manage.py seed_lxs_shenhe_huhang_catalog --apply --i-confirm-club=lxs
"""
from __future__ import annotations
from decimal import Decimal
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
ALLOWED_CLUB_ID = 'lxs'
NAME_HINT = '龙先生'
DEFAULT_AVATAR = 'a_long/morentouxiang.jpg'
SHENHE = 2 # 审核专用
# 专区(审核版)
ZONE_DEFS = [
{'mingzi': '休闲开黑', 'paixu': 30},
{'mingzi': '语音陪伴', 'paixu': 20},
{'mingzi': '团队协作', 'paixu': 10},
]
# 30 个正向护航/陪伴向商品(标题 + 介绍 + 价格),禁止代练代打语义
PRODUCT_DEFS = [
('王者荣耀·休闲开黑陪伴', '友好组队开黑,轻松娱乐,语音交流,快乐优先。', '19.90'),
('和平精英·小队同行', '休闲模式组队畅玩,互相配合,体验团队乐趣。', '19.90'),
('原神·探索同行', '一起探索地图与活动,聊天解谜,轻松愉快。', '29.90'),
('星穹铁道·剧情陪伴', '陪你体验剧情与活动关卡,节奏友好,交流顺畅。', '29.90'),
('无畏契约·娱乐五排', '娱乐局友好开黑,沟通协作,享受对局过程。', '25.90'),
('英雄联盟·娱乐双排', '休闲娱乐局陪伴,友好沟通,重在开心。', '25.90'),
('永劫无间·双人协作', '双人娱乐局同行,互相支援,体验动作乐趣。', '22.90'),
('三角洲行动·小队协作', '小队任务友好配合,沟通顺畅,快乐完成目标。', '29.90'),
('蛋仔派对·欢乐同乐', '休闲派对模式一起玩,轻松互动,气氛友好。', '15.90'),
('逆水寒·社交同游', '一起游历风景与活动,聊天社交,轻松惬意。', '29.90'),
('鸣潮·旅途陪伴', '结伴体验开放世界内容,节奏舒适,友好交流。', '29.90'),
('绝区零·日常同行', '日常内容一起体验,互相提醒,轻松完成。', '22.90'),
('崩坏3·活动陪伴', '活动关卡友好同行,沟通配合,享受剧情。', '19.90'),
('命运冠位指定·活动同行', '活动副本休闲体验,节奏友好,互相鼓励。', '19.90'),
('明日方舟·关卡陪伴', '关卡推图友好协助,讲解思路,轻松通关体验。', '22.90'),
('第五人格·娱乐开黑', '娱乐模式组队,友好沟通,享受对抗乐趣。', '19.90'),
('CS2·休闲约战', '休闲模式友好对局,语音交流,重在体验。', '25.90'),
('Dota2·娱乐组队', '娱乐局结伴开黑,沟通协作,快乐优先。', '25.90'),
('炉石传说·休闲对局', '休闲模式一起玩,交流构筑心得,气氛轻松。', '15.90'),
('金铲铲之战·娱乐对局', '娱乐模式畅玩,聊天互动,轻松愉快。', '15.90'),
('穿越火线·休闲开黑', '休闲模式组队,友好沟通,享受射击乐趣。', '19.90'),
('CFHD·娱乐同行', '娱乐局结伴,语音交流,过程友好。', '19.90'),
('NBA2K·友谊赛陪伴', '友谊赛模式一起打,轻松互动,享受比赛。', '22.90'),
('FIFA·友谊赛同行', '友谊赛友好对战,交流心得,气氛轻松。', '22.90'),
('我的世界·建造同行', '一起建造与探索,创意交流,氛围友好。', '19.90'),
('幻兽帕鲁·合作体验', '合作模式结伴体验,互相帮助,轻松有趣。', '19.90'),
('双人成行·合作通关', '合作解谜一起玩,沟通配合,欢乐通关。', '29.90'),
('It Takes Two·双人协作', '双人关卡友好协作,互动解谜,享受过程。', '29.90'),
('斯普拉遁·休闲对战', '休闲对战结伴,轻松交流,享受涂色乐趣。', '15.90'),
('动物森友会·岛上同游', '一起逛岛、装饰与活动,聊天放松,氛围温馨。', '19.90'),
]
class Command(BaseCommand):
help = '龙先生(lxs)审核版护航商品种子(默认 dry-run'
def add_arguments(self, parser):
parser.add_argument('--apply', action='store_true', help='真正写库')
parser.add_argument(
'--i-confirm-club',
type=str,
default='',
help='必须等于 lxs 才允许 --apply',
)
parser.add_argument(
'--club-id',
type=str,
default=ALLOWED_CLUB_ID,
help='仅允许 lxs',
)
def handle(self, *args, **options):
from jituan.models import Club
from products.models import Shangpin, ShangpinLeixing, ShangpinZhuanqu
club_id = (options.get('club_id') or '').strip()
apply = bool(options.get('apply'))
confirm = (options.get('i_confirm_club') or '').strip()
if club_id != ALLOWED_CLUB_ID:
raise CommandError(
f'安全拦截:只允许 club_id={ALLOWED_CLUB_ID!r},你传的是 {club_id!r}'
)
club = Club.query.filter(club_id=ALLOWED_CLUB_ID).first()
if not club:
raise CommandError(f'俱乐部 {ALLOWED_CLUB_ID} 不存在')
if NAME_HINT not in (club.name or ''):
raise CommandError(
f'安全拦截:{ALLOWED_CLUB_ID} 的 name={club.name!r} 不含「{NAME_HINT}'
)
if apply and confirm != ALLOWED_CLUB_ID:
raise CommandError(
'安全拦截:--apply 必须带 --i-confirm-club=lxs\n'
' python manage.py seed_lxs_shenhe_huhang_catalog --apply --i-confirm-club=lxs'
)
# 审核类型:第一条;没有则计划创建
leixing = (
ShangpinLeixing.query
.filter(shenhezhuangtai=SHENHE)
.order_by('id')
.first()
)
leixing_action = 'REUSE'
if not leixing:
leixing_action = 'CREATE'
leixing = None
# 专区计划
zone_plans = []
for zdef in ZONE_DEFS:
exist = ShangpinZhuanqu.query.filter(
club_id=ALLOWED_CLUB_ID,
mingzi=zdef['mingzi'],
shenhezhuangtai=SHENHE,
dianpu__isnull=True,
).first()
if exist and leixing and exist.leixing_id == leixing.id:
zone_plans.append({'def': zdef, 'action': 'SKIP', 'row': exist})
elif exist and not leixing:
# 类型尚未创建名称撞车则复用该专区apply 时再绑类型)
zone_plans.append({'def': zdef, 'action': 'SKIP', 'row': exist})
else:
zone_plans.append({'def': zdef, 'action': 'CREATE', 'row': None})
# 商品计划:全部挂第一个专区
first_zone_name = ZONE_DEFS[0]['mingzi']
product_plans = []
for title, intro, price in PRODUCT_DEFS:
# 预检:同 club + 同标题 + 审核态是否已有
exist_p = Shangpin.query.filter(
club_id=ALLOWED_CLUB_ID,
biaoqian=title,
shenhezhuangtai=SHENHE,
dianpu__isnull=True,
).first()
product_plans.append({
'title': title,
'intro': intro,
'price': price,
'action': 'SKIP' if exist_p else 'CREATE',
'exist_id': exist_p.id if exist_p else None,
})
mode = 'APPLY' if apply else 'DRY-RUN'
self.stdout.write(self.style.NOTICE(
f'\n===== {mode} 龙先生审核版护航商品 =====\n'
f'club={ALLOWED_CLUB_ID} ({club.name})\n'
f'审核类型: {leixing_action} '
f'{("id="+str(leixing.id)+" name="+repr(leixing.jieshao)) if leixing else "将创建「娱乐护航」"}\n'
f'默认图标: {DEFAULT_AVATAR}\n'
f'专区计划: create={sum(1 for z in zone_plans if z["action"]=="CREATE")} '
f'skip={sum(1 for z in zone_plans if z["action"]=="SKIP")}\n'
f'商品计划: create={sum(1 for p in product_plans if p["action"]=="CREATE")} '
f'skip={sum(1 for p in product_plans if p["action"]=="SKIP")} '
f'(共{len(product_plans)},挂专区「{first_zone_name}」)\n'
))
self.stdout.write('—— 专区 ——')
for z in zone_plans:
self.stdout.write(f' [{z["action"]}] {z["def"]["mingzi"]}')
self.stdout.write('—— 商品样例前8——')
for p in product_plans[:8]:
self.stdout.write(f' [{p["action"]}] {p["title"]} ¥{p["price"]}')
if len(product_plans) > 8:
self.stdout.write(f' ... 其余 {len(product_plans)-8} 个省略')
banned = ('代练', '代打', '上分', '上段', '包星', '定位赛代')
for p in product_plans:
blob = p['title'] + p['intro']
for b in banned:
if b in blob:
raise CommandError(f'文案含禁止词「{b}」: {p["title"]}')
if not apply:
self.stdout.write(self.style.WARNING(
'\n以上仅计划。确认后:\n'
' python manage.py seed_lxs_shenhe_huhang_catalog --apply --i-confirm-club=lxs\n'
))
return
stats = {
'leixing_created': 0,
'zones_created': 0,
'zones_skipped': 0,
'products_created': 0,
'products_skipped': 0,
}
with transaction.atomic():
if leixing is None:
leixing = ShangpinLeixing.query.create(
jieshao='娱乐护航',
tupian_url=DEFAULT_AVATAR,
paixu=0,
shenhezhuangtai=SHENHE,
yaoqiuleixing=None,
huiyuan_id=None,
yongjin=None,
)
stats['leixing_created'] = 1
elif leixing.shenhezhuangtai != SHENHE:
raise CommandError('解析到的类型不是审核专用,已中止')
zone_id_by_name = {}
for zp in zone_plans:
zdef = zp['def']
if zp['action'] == 'SKIP' and zp['row']:
# 若旧专区 leixing 不对,不改(只增不改);仅复用 id
zone_id_by_name[zdef['mingzi']] = zp['row'].id
stats['zones_skipped'] += 1
continue
exist = ShangpinZhuanqu.query.filter(
club_id=ALLOWED_CLUB_ID,
mingzi=zdef['mingzi'],
leixing_id=leixing.id,
shenhezhuangtai=SHENHE,
dianpu__isnull=True,
).first()
if exist:
zone_id_by_name[zdef['mingzi']] = exist.id
stats['zones_skipped'] += 1
continue
row = ShangpinZhuanqu.query.create(
mingzi=zdef['mingzi'],
leixing_id=leixing.id,
club_id=ALLOWED_CLUB_ID,
tupian_url=DEFAULT_AVATAR,
shenhezhuangtai=SHENHE,
paixu=int(zdef['paixu']),
shangjia_zhuangtai=True,
fengjin_zhuangtai=True,
dianpu=None,
dianpu_leixing=None,
)
zone_id_by_name[zdef['mingzi']] = row.id
stats['zones_created'] += 1
first_zq_id = zone_id_by_name.get(first_zone_name)
if not first_zq_id:
raise CommandError(f'第一个专区「{first_zone_name}」未就绪')
for i, pp in enumerate(product_plans):
if pp['action'] == 'SKIP':
stats['products_skipped'] += 1
continue
exist_p = Shangpin.query.filter(
club_id=ALLOWED_CLUB_ID,
biaoqian=pp['title'],
zhuanqu_id=first_zq_id,
shenhezhuangtai=SHENHE,
dianpu__isnull=True,
).first()
if exist_p:
stats['products_skipped'] += 1
continue
Shangpin.query.create(
biaoqian=pp['title'],
jiage=Decimal(pp['price']),
kucun=99999,
leixing_id=leixing.id,
zhuanqu_id=first_zq_id,
zhenshi_xiaoliang=0,
duiwai_xiaoliang=0,
jieshao=pp['intro'],
xiadan_xuzhi='请保持友好沟通,本服务为休闲娱乐陪伴,禁止不良言行。',
guize_tupian='',
tupian_url=DEFAULT_AVATAR,
yaoqiuleixing=leixing.yaoqiuleixing,
huiyuan_id=leixing.huiyuan_id,
yongjin=leixing.yongjin,
kaioi_ewai_dashou_fencheng=False,
ewai_dashou_fencheng=None,
paixu=1000 - i,
shenhezhuangtai=SHENHE,
shangjia_zhuangtai=True,
fengjin_zhuangtai=True,
shenhe_zhuangtai=True,
club_id=ALLOWED_CLUB_ID,
shi_zhuanpan=False,
dianpu=None,
dianpu_leixing=None,
)
stats['products_created'] += 1
self.stdout.write(self.style.SUCCESS(
f'\n完成: {stats}\n'
f'审核类型 id={leixing.id}{leixing.jieshao}」;'
f'商品均 shenhezhuangtai=2仅审核模式可见。'
))