""" 一键写入微信小程序审核专用商品(shenhezhuangtai=2)。 内容定位:正能量电竞休闲社区服务,不含代练/代打/上分/护航等敏感表述。 用法: python manage.py seed_audit_shangpin python manage.py seed_audit_shangpin --dry-run python manage.py seed_audit_shangpin --force # 删除本脚本写入的审核数据后重建 审核展示开关(小程序点单页)在 xcx_sys_peizhi.shangpin_shenhe_mode: 1 = 正常商品(shenhezhuangtai=1) 2 = 审核商品(shenhezhuangtai=2) """ from decimal import Decimal from django.core.management.base import BaseCommand from django.db import transaction from shangpin.models import Shangpin, ShangpinLeixing, ShangpinZhuanqu # 小程序点单/头像拼接用的相对路径(与 peizhi GetDynamicConfig otherConfig.morentouxiang 默认一致) FALLBACK_DEFAULT_AVATAR = 'beijing/morentouxiang.jpg' def get_default_avatar_relative_url(): """ 默认头像相对 URL: 1. 优先读后台 tupianpeizhi 表 leixing=2(默认头像图片配置) 2. 否则用 beijing/morentouxiang.jpg(小程序动态配置默认值) """ try: from peizhi.models import Tupianpeizhi row = Tupianpeizhi.objects.filter(leixing=2).only('tupian').first() if row and row.tupian: return str(row.tupian).strip().lstrip('/') except Exception: pass return FALLBACK_DEFAULT_AVATAR AUDIT_TYPE_NAME = '电竞休闲体验' ZONES = [ ('萌新入门', 300), ('休闲娱乐', 200), ('团队社交', 100), ] ORDER_NOTICE = ( '【服务说明】本平台倡导健康、文明、积极的电竞娱乐文化。' '本商品为陪伴交流、科普讲解或休闲娱乐体验,不提供代练、代打、' '代上分、账号托管等非正规服务。未成年人请在监护人指导下合理消费。' ) # (专区名, 标题, 价格, 对外销量, 排序权重, 介绍) PRODUCTS = [ ('萌新入门', '新手友好入门体验', '19.90', 128, 2000, '面向新朋友的轻松入门体验,了解基础操作与文明游戏礼仪,氛围轻松无压力。'), ('萌新入门', '游戏礼仪小课堂', '9.90', 256, 1990, '学习友好沟通、尊重队友、拒绝辱骂,共建文明电竞社区环境。'), ('萌新入门', '萌新问答互助时段', '16.60', 88, 1980, '有疑问随时交流,老手耐心解答,帮助你更快熟悉平台与游戏规则。'), ('萌新入门', '健康游戏习惯科普', '6.60', 312, 1970, '科普合理作息与用眼健康,倡导适度游戏、劳逸结合的正向生活方式。'), ('萌新入门', '电竞文化科普讲解', '15.90', 145, 1960, '了解电子竞技发展历程与职业精神,感受积极向上的电竞文化魅力。'), ('休闲娱乐', '休闲语音陪伴开黑', '29.90', 520, 1950, '轻松组队聊天、分享趣事,主打陪伴与放松,不承诺任何段位或战绩结果。'), ('休闲娱乐', '周末放松娱乐局', '35.90', 430, 1940, '低压娱乐对局体验,重在过程开心,适合工作之余放松心情。'), ('休闲娱乐', '友谊组队活动票', '19.90', 367, 1930, '结识志同道合的小伙伴,一起享受游戏乐趣,友谊第一、比赛第二。'), ('休闲娱乐', '正能量互动体验包', '32.00', 278, 1920, '传递鼓励与支持,营造互相尊重、积极向上的互动氛围。'), ('休闲娱乐', '赛事热点讨论会', '26.00', 156, 1910, '围绕热门赛事交流观赛心得与战术理解,纯讨论分享,不涉及任何代打服务。'), ('团队社交', '团队配合趣味体验', '49.90', 203, 1900, '通过趣味协作任务培养默契,锻炼沟通表达能力,体验团队合作乐趣。'), ('团队社交', '团队破冰小游戏', '22.00', 189, 1890, '适合新成员快速融入,轻松破冰、认识队友,提升社群归属感。'), ('团队社交', '语音互动陪伴30分钟', '28.00', 402, 1880, '30分钟语音陪伴交流,可聊天、可娱乐,内容健康阳光、拒绝低俗。'), ('团队社交', '友谊第一体验套餐', '38.00', 167, 1870, '强调尊重与包容,享受一起游戏的快乐,传递体育精神与友谊价值。'), ('团队社交', '文明电竞社群入门', '20.00', 233, 1860, '了解社群规范与文明公约,做有礼貌、有担当的电竞爱好者。'), ('休闲娱乐', '观赛解说体验票', '39.90', 98, 1850, '专业视角解读精彩赛事瞬间,提升观赛体验,纯观赏与讲解性质。'), ('萌新入门', '正向沟通陪练体验', '25.90', 174, 1840, '练习清晰表达与耐心倾听,提升团队协作中的沟通效率与友好度。'), ('团队社交', '健康生活游戏倡议', '8.80', 445, 1830, '倡导合理安排游戏时间,关注身心健康,做理性、成熟的电竞玩家。'), ('休闲娱乐', '电竞精神主题分享', '18.80', 121, 1820, '分享坚持、拼搏、尊重对手的电竞精神,传递青春正能量。'), ('团队社交', '社群文明公约学习', '12.90', 298, 1810, '学习平台文明公约与社区守则,共同维护清朗、健康的交流空间。'), ] AUDIT_PRODUCT_TITLES = [row[1] for row in PRODUCTS] class Command(BaseCommand): help = '写入审核专用商品数据(类型+专区+商品,shenhezhuangtai=2)' def add_arguments(self, parser): parser.add_argument('--dry-run', action='store_true', help='只预览,不写库') parser.add_argument('--force', action='store_true', help='删除本脚本创建的审核数据后重建') def handle(self, *args, **options): dry_run = options['dry_run'] force = options['force'] if force and not dry_run: self._delete_seed_data() existing = Shangpin.objects.filter( biaoqian__in=AUDIT_PRODUCT_TITLES, shenhezhuangtai=2, ).count() if existing >= len(PRODUCTS) and not force: self.stdout.write(self.style.WARNING( f'已存在 {existing} 条审核种子商品,跳过。如需重建请加 --force' )) return if dry_run: avatar_url = get_default_avatar_relative_url() self.stdout.write(self.style.NOTICE('【预览模式】将写入以下结构:')) self.stdout.write(f' 商品图标相对路径: {avatar_url}') self.stdout.write(f' 类型 1 个: {AUDIT_TYPE_NAME} (shenhezhuangtai=2)') self.stdout.write(f' 专区 {len(ZONES)} 个') self.stdout.write(f' 商品 {len(PRODUCTS)} 个 (shenhezhuangtai=2)') for z, title, price, *_ in PRODUCTS[:5]: self.stdout.write(f' - [{z}] {title} ¥{price}') self.stdout.write(' ...') return with transaction.atomic(): default_image = get_default_avatar_relative_url() leixing, _ = ShangpinLeixing.objects.get_or_create( jieshao=AUDIT_TYPE_NAME, shenhezhuangtai=2, defaults={ 'tupian_url': default_image, 'paixu': 9999, 'is_cross_enabled': False, 'is_special_type': False, }, ) # 已存在类型时同步图标为当前默认头像 if leixing.tupian_url != default_image: leixing.tupian_url = default_image leixing.save(update_fields=['tupian_url']) zone_map = {} for name, paixu in ZONES: zone, _ = ShangpinZhuanqu.objects.get_or_create( mingzi=name, leixing_id=leixing.id, shenhezhuangtai=2, defaults={'paixu': paixu}, ) zone_map[name] = zone created = 0 skipped = 0 for zone_name, title, price, sales, sort_weight, desc in PRODUCTS: zhuanqu = zone_map[zone_name] exists_qs = Shangpin.objects.filter( biaoqian=title, shenhezhuangtai=2, zhuanqu_id=zhuanqu.id, ) if exists_qs.exists(): exists_qs.update(tupian_url=default_image) skipped += 1 continue Shangpin.objects.create( biaoqian=title, jiage=Decimal(price), kucun=999, leixing_id=leixing.id, zhuanqu_id=zhuanqu.id, zhenshi_xiaoliang=0, duiwai_xiaoliang=sales, jieshao=desc, xiadan_xuzhi=ORDER_NOTICE, tupian_url=default_image, yaoqiuleixing=None, huiyuan_id=None, yongjin=None, kaioi_ewai_dashou_fencheng=False, ewai_dashou_fencheng=None, paixu=sort_weight, shenhezhuangtai=2, ) created += 1 self.stdout.write(self.style.SUCCESS( f'完成:类型 id={leixing.id},专区 {len(zone_map)} 个,' f'新建商品 {created} 个,跳过已存在 {skipped} 个,图标={default_image}。' )) self.stdout.write('请将 xcx_sys_peizhi.shangpin_shenhe_mode 设为 2 后,小程序点单页即展示审核商品。') def _delete_seed_data(self): """仅删除本脚本商品标题列表中的审核商品,以及关联审核类型/专区。""" deleted_products, _ = Shangpin.objects.filter( biaoqian__in=AUDIT_PRODUCT_TITLES, shenhezhuangtai=2, ).delete() deleted_zones, _ = ShangpinZhuanqu.objects.filter( mingzi__in=[z[0] for z in ZONES], shenhezhuangtai=2, ).delete() deleted_types, _ = ShangpinLeixing.objects.filter( jieshao=AUDIT_TYPE_NAME, shenhezhuangtai=2, ).delete() self.stdout.write(self.style.WARNING( f'--force 已清理:商品 {deleted_products},专区 {deleted_zones},类型 {deleted_types}' ))