feat: 转盘按商品重设计(库存、控奖、后台免填商品编号)

转盘即商品自动建绑;奖池支持库存;控奖指定用户必中;xq/xzj 普通点单路径不变。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-22 20:39:59 +08:00
parent 43ad221c67
commit dc4c0ad091
5 changed files with 394 additions and 50 deletions

View File

@@ -0,0 +1,50 @@
# 转盘奖品库存 + 运营控奖表
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('products', '0013_zhuanpan_and_zhuanqu_icon'),
]
operations = [
migrations.AddField(
model_name='zhuanpanjiangpin',
name='kucun',
field=models.IntegerField(
default=-1,
help_text='-1=不限0=不可抽中(控奖仍可强制);>0 抽中后减一',
verbose_name='剩余库存',
),
),
migrations.CreateModel(
name='ZhuanpanKongjiang',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('club_id', models.CharField(db_index=True, max_length=16, verbose_name='俱乐部')),
('huodong_id', models.PositiveIntegerField(db_index=True, verbose_name='活动ID')),
('yonghuid', models.CharField(db_index=True, max_length=32, verbose_name='用户UID')),
('jiangpin_id', models.PositiveIntegerField(db_index=True, verbose_name='指定奖品ID')),
('cishu', models.PositiveIntegerField(default=1, verbose_name='剩余次数')),
('qiyong', models.BooleanField(db_index=True, default=True, verbose_name='是否启用')),
('beizhu', models.CharField(blank=True, default='', max_length=200, verbose_name='备注')),
('CreateTime', models.DateTimeField(auto_now_add=True)),
('UpdateTime', models.DateTimeField(auto_now=True)),
],
options={
'verbose_name': '转盘控奖',
'verbose_name_plural': '转盘控奖',
'db_table': 'zhuanpan_kongjiang',
},
),
migrations.AddIndex(
model_name='zhuanpankongjiang',
index=models.Index(fields=['club_id', 'yonghuid', 'qiyong'], name='zhuanpan_kj_club_uid_qy_idx'),
),
migrations.AddIndex(
model_name='zhuanpankongjiang',
index=models.Index(fields=['huodong_id', 'yonghuid'], name='zhuanpan_kj_hd_uid_idx'),
),
]

View File

@@ -404,13 +404,13 @@ class ShangpinMeiriTongji(QModel):
# ===========================================================================
class ZhuanpanHuodong(QModel):
"""转盘活动:一个俱乐部可有多个;购票价格取关联商品 jiage。"""
"""转盘活动:与转盘商品 1:1;购票价格取关联商品 jiage。"""
id = models.AutoField(primary_key=True)
club_id = models.CharField(max_length=16, db_index=True, verbose_name='俱乐部')
mingzi = models.CharField(max_length=64, default='幸运转盘', verbose_name='活动名')
shangpin_id = models.PositiveIntegerField(
db_index=True, verbose_name='购票商品ID',
help_text='对应 Shangpin.id该商品建议 shi_zhuanpan=True',
db_index=True, verbose_name='转盘商品ID',
help_text='对应 Shangpin.id且 shi_zhuanpan=True;后台创建商品时自动绑定',
)
qiyong = models.BooleanField(default=True, db_index=True, verbose_name='是否启用')
beizhu = models.CharField(max_length=200, blank=True, default='', verbose_name='备注')
@@ -425,7 +425,7 @@ class ZhuanpanHuodong(QModel):
class ZhuanpanJiangpin(QModel):
"""转盘奖品格:权重越高越易中;shi_xiexie=True 表示谢谢参与(不生成订单"""
"""转盘奖品格:权重越高越易中;kucun=-1 不限shi_xiexie 不生成订单。"""
id = models.AutoField(primary_key=True)
huodong_id = models.PositiveIntegerField(db_index=True, verbose_name='活动ID')
mingzi = models.CharField(max_length=64, verbose_name='奖品名')
@@ -434,6 +434,10 @@ class ZhuanpanJiangpin(QModel):
null=True, blank=True, db_index=True, verbose_name='中奖后履约商品ID',
)
quanzhong = models.PositiveIntegerField(default=1, verbose_name='中奖权重')
kucun = models.IntegerField(
default=-1, verbose_name='剩余库存',
help_text='-1=不限0=不可抽中(控奖仍可强制);>0 抽中后减一',
)
paixu = models.PositiveSmallIntegerField(default=0, verbose_name='格子序号')
shi_xiexie = models.BooleanField(default=False, verbose_name='是否谢谢参与')
CreateTime = models.DateTimeField(auto_now_add=True)
@@ -446,6 +450,29 @@ class ZhuanpanJiangpin(QModel):
indexes = [models.Index(fields=['huodong_id', 'paixu'])]
class ZhuanpanKongjiang(QModel):
"""运营控奖:指定用户接下来若干次必中某奖。"""
id = models.AutoField(primary_key=True)
club_id = models.CharField(max_length=16, db_index=True, verbose_name='俱乐部')
huodong_id = models.PositiveIntegerField(db_index=True, verbose_name='活动ID')
yonghuid = models.CharField(max_length=32, db_index=True, verbose_name='用户UID')
jiangpin_id = models.PositiveIntegerField(db_index=True, verbose_name='指定奖品ID')
cishu = models.PositiveIntegerField(default=1, verbose_name='剩余次数')
qiyong = models.BooleanField(default=True, db_index=True, verbose_name='是否启用')
beizhu = models.CharField(max_length=200, blank=True, default='', verbose_name='备注')
CreateTime = models.DateTimeField(auto_now_add=True)
UpdateTime = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'zhuanpan_kongjiang'
verbose_name = '转盘控奖'
verbose_name_plural = verbose_name
indexes = [
models.Index(fields=['club_id', 'yonghuid', 'qiyong']),
models.Index(fields=['huodong_id', 'yonghuid']),
]
class ZhuanpanJihui(QModel):
"""转盘抽奖机会单:支付成功后待抽,不进抢单池;抽中后再写 Order。

View File

@@ -11,7 +11,7 @@ from .views import ShangpinHuoquView, ShangpinXiangqingHuoquView, DashouHuiyuanL
HuiyuanTypeListView, HuiyuanRecordListView, ZuzhangFenhongView, CzhqdyView, DsqrgmdhView, \
AlipayCzjiluNotifyView, CzjiluRepairView, \
ZhuanpanGoumai, ZhuanpanLunxun, ZhuanpanShibai, ZhuanpanHuitiao, ZhuanpanJiangpinList, \
ZhuanpanChoujiang, ZhuanpanWode, AdZhuanpanHuodongView, AdZhuanpanJiangpinView
ZhuanpanChoujiang, ZhuanpanWode, AdZhuanpanHuodongView, AdZhuanpanJiangpinView, AdZhuanpanKongjiangView
urlpatterns = [
#path('shangpinhuoqu/', ShangpinHuoquView.as_view(), name='获取商品数据商品类型和专区'),
@@ -51,6 +51,7 @@ urlpatterns = [
path('zhuanpanwode', ZhuanpanWode.as_view(), name='我的转盘机会'),
path('adzhuanpanhd', AdZhuanpanHuodongView.as_view(), name='后台转盘活动'),
path('adzhuanpanjp', AdZhuanpanJiangpinView.as_view(), name='后台转盘奖品'),
path('adzhuanpankj', AdZhuanpanKongjiangView.as_view(), name='后台转盘控奖'),
#path('sjhuitiao', ShangjiaHuitiao.as_view(), name='商家支付官方回调'), # 商家支付回调
path('sjshibai', ShangjiaShibai.as_view(), name='商家支付失败'), # 商家支付失败处理
path('sjcg', ShangjiaChenggong.as_view(), name='商家支付成功'), # 商家支付成功轮询

View File

@@ -67,6 +67,7 @@ from .zhuanpan_payment import (
ZhuanpanWode,
AdZhuanpanHuodongView,
AdZhuanpanJiangpinView,
AdZhuanpanKongjiangView,
)
from .shangpin_admin import (
ShangpinLeixingFabuView,

View File

@@ -39,7 +39,8 @@ from products.czjilu_types import (
close_unpaid_czjilu,
)
from products.models import (
Czjilu, Shangpin, ZhuanpanHuodong, ZhuanpanJiangpin, ZhuanpanJihui,
Czjilu, Shangpin, ShangpinLeixing, ShangpinZhuanqu,
ZhuanpanHuodong, ZhuanpanJiangpin, ZhuanpanJihui, ZhuanpanKongjiang,
)
from utils.money import yuan_to_fen
@@ -54,17 +55,74 @@ def _gen_czzp_id():
def _pick_jiangpin(jiangpin_list):
"""按权重抽奖,返回选中的奖品对象"""
total = sum(max(int(j.quanzhong or 0), 0) for j in jiangpin_list)
"""按权重抽奖仅库存未耗尽kucun==-1 或不限 / kucun>0"""
pool = [j for j in jiangpin_list if int(getattr(j, 'kucun', -1)) != 0]
if not pool:
raise ValueError('奖品库存已全部抽完')
total = sum(max(int(j.quanzhong or 0), 0) for j in pool)
if total <= 0:
return jiangpin_list[0]
return pool[0]
r = random.randint(1, total)
acc = 0
for j in jiangpin_list:
for j in pool:
acc += max(int(j.quanzhong or 0), 0)
if r <= acc:
return j
return jiangpin_list[-1]
return pool[-1]
def _consume_jiangpin_stock(jiangpin):
"""普通抽中或控奖命中后扣库存;-1 不限不扣0 不扣(控奖可强制)。"""
k = int(getattr(jiangpin, 'kucun', -1))
if k > 0:
jiangpin.kucun = k - 1
jiangpin.save(update_fields=['kucun', 'UpdateTime'])
def _take_kongjiang(club_id, huodong_id, yonghuid):
"""取一条可用控奖并扣减次数;返回奖品对象或 None。"""
row = (
ZhuanpanKongjiang.query.select_for_update()
.filter(
club_id=club_id,
huodong_id=huodong_id,
yonghuid=yonghuid,
qiyong=True,
cishu__gt=0,
)
.order_by('id')
.first()
)
if not row:
return None
prize = ZhuanpanJiangpin.query.filter(id=row.jiangpin_id, huodong_id=huodong_id).first()
if not prize:
row.qiyong = False
row.save(update_fields=['qiyong', 'UpdateTime'])
return None
row.cishu = max(int(row.cishu or 0) - 1, 0)
if row.cishu <= 0:
row.qiyong = False
row.save(update_fields=['cishu', 'qiyong', 'UpdateTime'])
return prize
def _serialize_huodong_row(h, ticket=None):
if ticket is None:
ticket = Shangpin.query.filter(id=h.shangpin_id).first()
return {
'id': h.id,
'mingzi': h.mingzi,
'shangpin_id': h.shangpin_id,
'qiyong': h.qiyong,
'beizhu': h.beizhu,
'biaoqian': (ticket.biaoqian if ticket else '') or h.mingzi,
'jiage': str(ticket.jiage) if ticket else '0',
'tupian_url': (ticket.tupian_url if ticket else '') or '',
'leixing_id': ticket.leixing_id if ticket else None,
'zhuanqu_id': ticket.zhuanqu_id if ticket else None,
'shangjia_zhuangtai': bool(ticket.shangjia_zhuangtai) if ticket else False,
}
def _create_pool_order_from_prize(jihui, jiangpin, request_user):
@@ -448,12 +506,19 @@ class ZhuanpanChoujiang(APIView):
}, status=400)
prizes = list(
ZhuanpanJiangpin.query.filter(huodong_id=jihui.huodong_id).order_by('paixu', 'id')
ZhuanpanJiangpin.query.select_for_update()
.filter(huodong_id=jihui.huodong_id)
.order_by('paixu', 'id')
)
if not prizes:
return Response({'code': 400, 'message': '奖品未配置'}, status=400)
win = _pick_jiangpin(prizes)
# 1) 控奖优先 2) 权重+库存
win = _take_kongjiang(jihui.club_id, jihui.huodong_id, jihui.yonghuid)
if win is None:
win = _pick_jiangpin(prizes)
_consume_jiangpin_stock(win)
dingdan_id = ''
if not win.shi_xiexie and win.shangpin_id:
dingdan_id = _create_pool_order_from_prize(jihui, win, request.user)
@@ -515,52 +580,140 @@ class ZhuanpanWode(APIView):
class AdZhuanpanHuodongView(APIView):
"""后台:转盘活动 list/save。POST action=list|save|toggle"""
"""后台:转盘商品(=活动) list / create_product / save / toggle / meta。
运营不再手填购票商品编号:创建时直接填名称/价格/类型,自动建 Shangpin+Huodong。
"""
permission_classes = [IsAuthenticated]
def post(self, request):
action = (request.data.get('action') or 'list').strip()
club_id = resolve_effective_club_id(request)
if action == 'list':
rows = list(ZhuanpanHuodong.query.filter(club_id=club_id).order_by('-id'))
if action == 'meta':
types = list(
ShangpinLeixing.query.order_by('id').values('id', 'jieshao')
)
zones = list(
ShangpinZhuanqu.query.filter(club_id=club_id)
.order_by('-paixu', 'id')
.values('id', 'mingzi', 'leixing_id')
)
# 履约商品:本俱乐部非转盘购票商品
goods = list(
Shangpin.query.filter(club_id=club_id, shi_zhuanpan=False)
.order_by('-paixu', '-id')
.values('id', 'biaoqian', 'jiage', 'tupian_url', 'leixing_id')[:500]
)
for g in goods:
g['jiage'] = str(g.get('jiage') or 0)
return Response({
'code': 0,
'data': [
{
'id': h.id,
'mingzi': h.mingzi,
'shangpin_id': h.shangpin_id,
'qiyong': h.qiyong,
'beizhu': h.beizhu,
}
for h in rows
],
'data': {'leixing': types, 'zhuanqu': zones, 'goods': goods},
})
if action == 'save':
hid = request.data.get('id')
mingzi = (request.data.get('mingzi') or '幸运转盘').strip()
shangpin_id = int(request.data.get('shangpin_id') or 0)
if action == 'list':
rows = list(ZhuanpanHuodong.query.filter(club_id=club_id).order_by('-id'))
sp_ids = [h.shangpin_id for h in rows]
tickets = {
s.id: s
for s in Shangpin.query.filter(id__in=sp_ids, club_id=club_id)
} if sp_ids else {}
return Response({
'code': 0,
'data': [_serialize_huodong_row(h, tickets.get(h.shangpin_id)) for h in rows],
})
if action == 'create_product':
biaoqian = (request.data.get('biaoqian') or request.data.get('mingzi') or '').strip()
mingzi = (request.data.get('mingzi') or biaoqian or '幸运转盘').strip()
try:
jiage = Decimal(str(request.data.get('jiage') or 0))
except Exception:
return Response({'code': 1, 'msg': '价格格式错误'})
if not biaoqian:
return Response({'code': 1, 'msg': '请填写转盘商品名称'})
if jiage <= 0:
return Response({'code': 1, 'msg': '价格必须大于 0'})
leixing_id = request.data.get('leixing_id')
if not leixing_id:
return Response({'code': 1, 'msg': '请选择商品类型'})
try:
leixing_id = int(leixing_id)
except (TypeError, ValueError):
return Response({'code': 1, 'msg': '商品类型无效'})
zhuanqu_id = request.data.get('zhuanqu_id') or None
if zhuanqu_id in ('', None):
zhuanqu_id = None
else:
zhuanqu_id = int(zhuanqu_id)
tupian_url = (request.data.get('tupian_url') or '').strip()
beizhu = (request.data.get('beizhu') or '').strip()
qiyong = bool(request.data.get('qiyong', True))
if not shangpin_id:
return Response({'code': 1, 'msg': '需要 shangpin_id'})
# 标记购票商品
Shangpin.query.filter(id=shangpin_id, club_id=club_id).update(shi_zhuanpan=True)
if hid:
h = ZhuanpanHuodong.query.filter(id=int(hid), club_id=club_id).first()
if not h:
return Response({'code': 1, 'msg': '活动不存在'})
h.mingzi = mingzi
h.shangpin_id = shangpin_id
h.beizhu = beizhu
h.qiyong = qiyong
h.save()
else:
h = ZhuanpanHuodong.query.create(
club_id=club_id, mingzi=mingzi, shangpin_id=shangpin_id,
beizhu=beizhu, qiyong=qiyong,
with transaction.atomic():
ticket = Shangpin.query.create(
biaoqian=biaoqian[:45],
jiage=jiage,
kucun=99999,
leixing_id=leixing_id,
zhuanqu_id=zhuanqu_id,
jieshao=beizhu or '转盘购票商品',
tupian_url=tupian_url,
club_id=club_id,
shi_zhuanpan=True,
shangjia_zhuangtai=True,
fengjin_zhuangtai=True,
shenhezhuangtai=1,
paixu=0,
)
return Response({'code': 0, 'data': {'id': h.id}})
h = ZhuanpanHuodong.query.create(
club_id=club_id,
mingzi=mingzi[:64],
shangpin_id=ticket.id,
beizhu=beizhu,
qiyong=qiyong,
)
return Response({'code': 0, 'data': _serialize_huodong_row(h, ticket)})
if action == 'save':
hid = request.data.get('id')
if not hid:
return Response({'code': 1, 'msg': '缺少 id新建请用 create_product'})
h = ZhuanpanHuodong.query.filter(id=int(hid), club_id=club_id).first()
if not h:
return Response({'code': 1, 'msg': '转盘不存在'})
ticket = Shangpin.query.filter(id=h.shangpin_id, club_id=club_id).first()
mingzi = (request.data.get('mingzi') or h.mingzi).strip()
biaoqian = (request.data.get('biaoqian') or (ticket.biaoqian if ticket else mingzi) or mingzi).strip()
beizhu = request.data.get('beizhu')
if beizhu is None:
beizhu = h.beizhu
else:
beizhu = str(beizhu).strip()
qiyong = bool(request.data.get('qiyong', h.qiyong))
tupian_url = request.data.get('tupian_url')
jiage_raw = request.data.get('jiage')
h.mingzi = mingzi[:64]
h.beizhu = beizhu
h.qiyong = qiyong
h.save()
if ticket:
ticket.biaoqian = biaoqian[:45]
ticket.shi_zhuanpan = True
if tupian_url is not None:
ticket.tupian_url = str(tupian_url).strip()
if jiage_raw is not None and str(jiage_raw).strip() != '':
try:
jv = Decimal(str(jiage_raw))
if jv > 0:
ticket.jiage = jv
except Exception:
return Response({'code': 1, 'msg': '价格格式错误'})
ticket.save()
return Response({'code': 0, 'data': _serialize_huodong_row(h, ticket)})
if action == 'toggle':
hid = int(request.data.get('id') or 0)
h = ZhuanpanHuodong.query.filter(id=hid, club_id=club_id).first()
@@ -568,12 +721,17 @@ class AdZhuanpanHuodongView(APIView):
return Response({'code': 1, 'msg': '不存在'})
h.qiyong = not h.qiyong
h.save(update_fields=['qiyong', 'UpdateTime'])
ticket = Shangpin.query.filter(id=h.shangpin_id, club_id=club_id).first()
if ticket:
ticket.shangjia_zhuangtai = h.qiyong
ticket.save(update_fields=['shangjia_zhuangtai', 'UpdateTime'])
return Response({'code': 0, 'data': {'qiyong': h.qiyong}})
return Response({'code': 1, 'msg': '未知 action'})
class AdZhuanpanJiangpinView(APIView):
"""后台:奖品 list/save/delete。"""
"""后台:奖品 list/save/delete(含库存;履约商品用下拉 id不手填语义"""
permission_classes = [IsAuthenticated]
def post(self, request):
@@ -582,10 +740,17 @@ class AdZhuanpanJiangpinView(APIView):
huodong_id = int(request.data.get('huodong_id') or 0)
huodong = ZhuanpanHuodong.query.filter(id=huodong_id, club_id=club_id).first()
if not huodong:
return Response({'code': 1, 'msg': '活动不存在或不属于当前俱乐部'})
return Response({'code': 1, 'msg': '转盘不存在或不属于当前俱乐部'})
if action == 'list':
rows = list(ZhuanpanJiangpin.query.filter(huodong_id=huodong_id).order_by('paixu', 'id'))
fulfill_ids = [p.shangpin_id for p in rows if p.shangpin_id]
name_map = {}
if fulfill_ids:
name_map = {
s.id: s.biaoqian
for s in Shangpin.query.filter(id__in=fulfill_ids, club_id=club_id)
}
return Response({
'code': 0,
'data': [
@@ -594,7 +759,9 @@ class AdZhuanpanJiangpinView(APIView):
'mingzi': p.mingzi,
'tupian_url': p.tupian_url,
'shangpin_id': p.shangpin_id,
'shangpin_biaoqian': name_map.get(p.shangpin_id, '') if p.shangpin_id else '',
'quanzhong': p.quanzhong,
'kucun': int(getattr(p, 'kucun', -1)),
'paixu': p.paixu,
'shi_xiexie': p.shi_xiexie,
}
@@ -603,11 +770,17 @@ class AdZhuanpanJiangpinView(APIView):
})
if action == 'save':
pid = request.data.get('id')
kucun_raw = request.data.get('kucun', -1)
try:
kucun = int(kucun_raw)
except (TypeError, ValueError):
kucun = -1
data = dict(
mingzi=(request.data.get('mingzi') or '').strip() or '奖品',
tupian_url=(request.data.get('tupian_url') or '').strip(),
shangpin_id=request.data.get('shangpin_id') or None,
quanzhong=int(request.data.get('quanzhong') or 1),
kucun=kucun,
paixu=int(request.data.get('paixu') or 0),
shi_xiexie=bool(request.data.get('shi_xiexie', False)),
)
@@ -615,6 +788,14 @@ class AdZhuanpanJiangpinView(APIView):
data['shangpin_id'] = None
else:
data['shangpin_id'] = int(data['shangpin_id'])
# 履约商品必须属于本俱乐部且不能是转盘购票商品
ful = Shangpin.query.filter(id=data['shangpin_id'], club_id=club_id).first()
if not ful:
return Response({'code': 1, 'msg': '履约商品不存在'})
if getattr(ful, 'shi_zhuanpan', False):
return Response({'code': 1, 'msg': '不能把转盘购票商品设为履约商品'})
if data['shi_xiexie']:
data['shangpin_id'] = None
if pid:
p = ZhuanpanJiangpin.query.filter(id=int(pid), huodong_id=huodong_id).first()
if not p:
@@ -628,5 +809,89 @@ class AdZhuanpanJiangpinView(APIView):
if action == 'delete':
pid = int(request.data.get('id') or 0)
ZhuanpanJiangpin.query.filter(id=pid, huodong_id=huodong_id).delete()
ZhuanpanKongjiang.query.filter(jiangpin_id=pid, huodong_id=huodong_id).delete()
return Response({'code': 0})
return Response({'code': 1, 'msg': '未知 action'})
class AdZhuanpanKongjiangView(APIView):
"""后台控奖:指定用户必中某奖若干次。"""
permission_classes = [IsAuthenticated]
def post(self, request):
action = (request.data.get('action') or 'list').strip()
club_id = resolve_effective_club_id(request)
huodong_id = int(request.data.get('huodong_id') or 0)
huodong = ZhuanpanHuodong.query.filter(id=huodong_id, club_id=club_id).first()
if not huodong:
return Response({'code': 1, 'msg': '转盘不存在或不属于当前俱乐部'})
if action == 'list':
rows = list(
ZhuanpanKongjiang.query.filter(huodong_id=huodong_id, club_id=club_id)
.order_by('-id')[:200]
)
jp_ids = [r.jiangpin_id for r in rows]
jp_map = {
p.id: p.mingzi
for p in ZhuanpanJiangpin.query.filter(id__in=jp_ids, huodong_id=huodong_id)
} if jp_ids else {}
return Response({
'code': 0,
'data': [
{
'id': r.id,
'yonghuid': r.yonghuid,
'jiangpin_id': r.jiangpin_id,
'jiangpin_mingzi': jp_map.get(r.jiangpin_id, ''),
'cishu': r.cishu,
'qiyong': r.qiyong,
'beizhu': r.beizhu,
}
for r in rows
],
})
if action == 'save':
yonghuid = str(request.data.get('yonghuid') or '').strip()
jiangpin_id = int(request.data.get('jiangpin_id') or 0)
cishu = int(request.data.get('cishu') or 1)
beizhu = (request.data.get('beizhu') or '').strip()
qiyong = bool(request.data.get('qiyong', True))
if not yonghuid:
return Response({'code': 1, 'msg': '请填写用户 UID'})
if cishu < 1:
return Response({'code': 1, 'msg': '次数至少为 1'})
prize = ZhuanpanJiangpin.query.filter(id=jiangpin_id, huodong_id=huodong_id).first()
if not prize:
return Response({'code': 1, 'msg': '奖品不存在'})
kid = request.data.get('id')
if kid:
row = ZhuanpanKongjiang.query.filter(
id=int(kid), huodong_id=huodong_id, club_id=club_id
).first()
if not row:
return Response({'code': 1, 'msg': '控奖记录不存在'})
row.yonghuid = yonghuid
row.jiangpin_id = jiangpin_id
row.cishu = cishu
row.beizhu = beizhu
row.qiyong = qiyong
row.save()
else:
row = ZhuanpanKongjiang.query.create(
club_id=club_id,
huodong_id=huodong_id,
yonghuid=yonghuid,
jiangpin_id=jiangpin_id,
cishu=cishu,
beizhu=beizhu,
qiyong=qiyong,
)
return Response({'code': 0, 'data': {'id': row.id}})
if action == 'delete':
kid = int(request.data.get('id') or 0)
ZhuanpanKongjiang.query.filter(
id=kid, huodong_id=huodong_id, club_id=club_id
).delete()
return Response({'code': 0})
return Response({'code': 1, 'msg': '未知 action'})