feat: 打手赠送会员(免费接单)独立表与抢单资格

新增 dashou_zengsong_huiyuan,与购买会员分离;抢单/抢单池认赠送有效会员;后台送/改期/移除接口,送时积分非10则改为10并写操作日志。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-17 02:14:07 +08:00
parent a1a49261a5
commit cb89720260
7 changed files with 538 additions and 3 deletions

View File

@@ -14,7 +14,8 @@ from .view import (GetRolePermissionView,
FineApplyView, PunishDashouView,
FaKuanTongJiView, FaKuanLieBiaoView, FaKuanChuLiView, FaKuanChuangJianView, FaKuanPingTaiShenHeView,
HqbkxxView,BkxgView,CaiwuView,CwhybkhqView, HybkjtsjView, SzxxView, CwddhqlxView, CwhqjtddsjView,
CwqtczhqView, KhpzhqView, ChzsgcView,KhgglView, ShgxgsjView, KhjlglView, KhjlczView, ZxkfghdsView)
CwqtczhqView, KhpzhqView, ChzsgcView,KhgglView, ShgxgsjView, KhjlglView, KhjlczView, ZxkfghdsView,
DashouGiftHuiyuanSaveView, DashouGiftHuiyuanRemoveView)
from config.views import MiniappScriptHoutaiListView, MiniappScriptHoutaiModifyView
from rank.reward_houtai_views import RankRewardHoutaiListView, RankRewardHoutaiSaveView, RankRewardHoutaiClaimsView
@@ -30,6 +31,8 @@ urlpatterns = [
path('kefuhqdslb', KefuGetDashouListView.as_view(), name='客服获取打手数据'),
path('kefuhqdsxq', KefuGetDashouDetailView.as_view(), name='客服获取打手具体信息'),
path('kefuxgds', KefuUpdateDashouView.as_view(), name='客服修改打手数据'),
path('dszsonghy', DashouGiftHuiyuanSaveView.as_view(), name='打手赠送会员'),
path('dsycsonghy', DashouGiftHuiyuanRemoveView.as_view(), name='移除打手赠送会员'),
path('hqsjgllb', KefuGetShangjiaListView.as_view(), name='后台获取商家列表'),
path('hthqsjxq', KefuGetShangjiaDetailView.as_view(), name='后台获取商家详情'),
path('xgsjxx', KefuUpdateShangjiaView.as_view(), name='后台修改商家数据'),

View File

@@ -36,6 +36,7 @@ from .views.kefu import (
KefuGetDashouListView, KefuGetDashouDetailView, KefuUpdateDashouView,
KefuGetShangjiaListView, KefuGetShangjiaDetailView, KefuUpdateShangjiaView,
KefuChatPermissionsView,
DashouGiftHuiyuanSaveView, DashouGiftHuiyuanRemoveView,
)
from .views.products import (
GetProductBaseDataView, GetProductListView, SaveProductOrderView,
@@ -96,6 +97,7 @@ __all__ = [
'GetAdminRolesView', 'GetAdminUserListView', 'ModifyAdminUserView', 'AddAdminUserView',
# kefu
'KefuGetDashouListView', 'KefuGetDashouDetailView', 'KefuUpdateDashouView',
'DashouGiftHuiyuanSaveView', 'DashouGiftHuiyuanRemoveView',
'KefuGetShangjiaListView', 'KefuGetShangjiaDetailView', 'KefuUpdateShangjiaView',
'KefuChatPermissionsView',
# products

View File

@@ -304,6 +304,7 @@ class KefuGetDashouDetailView(APIView):
'data': {
'user_info': user_info,
'member_list': member_list,
'gift_member_list': [],
'all_members': all_members,
'permissions': permissions,
}
@@ -369,11 +370,15 @@ class KefuGetDashouDetailView(APIView):
# 7. 查询所有会员类型(用于前端添加会员)
all_members = list(Huiyuan.query.all().values('huiyuan_id', 'jieshao'))
from jituan.services.gift_huiyuan import list_gift_huiyuan_for_admin
gift_member_list = list_gift_huiyuan_for_admin(uid)
return Response({
'code': 0,
'data': {
'user_info': user_info,
'member_list': member_list,
'gift_member_list': gift_member_list,
'all_members': all_members,
'permissions': permissions, # 返回当前客服的权限列表
}
@@ -1150,6 +1155,223 @@ class KefuChatPermissionsView(APIView):
})
class DashouGiftHuiyuanSaveView(APIView):
"""
赠送会员 / 改期(免费接单资格,写入 dashou_zengsong_huiyuan
POST /houtai/dszsonghy
Body: {
phone, dashou_id, huiyuan_id,
daoqi_time: 'YYYY-MM-DD''YYYY-MM-DD HH:MM:SS',
id?: 已有记录ID改期时建议传
}
"""
permission_classes = [IsAuthenticated]
parser_classes = [JSONParser]
def post(self, request):
from jituan.services.gift_huiyuan import (
has_gift_huiyuan_permission,
parse_gift_daoqi_time,
upsert_gift_huiyuan,
update_gift_huiyuan_daoqi,
)
from products.models import Huiyuan as HuiyuanModel
phone = (request.data.get('phone') or request.data.get('username') or '').strip()
dashou_id = (request.data.get('dashou_id') or request.data.get('uid') or '').strip()
huiyuan_id = (request.data.get('huiyuan_id') or '').strip()
record_id = request.data.get('id')
raw_daoqi = request.data.get('daoqi_time')
kefu, permissions = verify_kefu_permission(request, phone or None)
if kefu is None:
return permissions
if not has_gift_huiyuan_permission(permissions):
return Response({'code': 403, 'msg': '无赠送会员权限(需打手基础管理或加积分权限)'})
if not dashou_id:
return Response({'code': 400, 'msg': '缺少打手ID'})
daoqi_time, err = parse_gift_daoqi_time(raw_daoqi)
if err:
return Response({'code': 400, 'msg': err})
try:
dashou_user = User.query.get(UserUID=dashou_id)
except User.DoesNotExist:
return Response({'code': 404, 'msg': '打手不存在'})
denied = forbid_if_user_out_of_scope(request, dashou_user)
if denied:
return denied
try:
dashou_user.DashouProfile
except ObjectDoesNotExist:
return Response({'code': 404, 'msg': '该用户不是打手'})
song_ren = getattr(kefu.user, 'Phone', None) or phone
operator = song_ren
# 有记录ID只改期
if record_id not in (None, ''):
try:
rid = int(record_id)
except (TypeError, ValueError):
return Response({'code': 400, 'msg': '无效的记录ID'})
rec, err = update_gift_huiyuan_daoqi(
record_id=rid,
yonghu_id=dashou_id,
daoqi_time=daoqi_time,
song_ren=song_ren,
)
if err:
return Response({'code': 400, 'msg': err})
try:
hy_name = HuiyuanModel.query.get(huiyuan_id=rec.huiyuan_id).jieshao
except HuiyuanModel.DoesNotExist:
hy_name = rec.huiyuan_id
write_xiugai_log(
yonghuid=dashou_id,
xiugaiid=operator,
leixing=XIUGAI_LEIXING_DASHOU,
huiyuan_id=rec.huiyuan_id,
qitashuoming=(
f'【后台】修改赠送会员到期时间会员ID={rec.huiyuan_id}{hy_name}'
f'新到期={rec.daoqi_time.strftime("%Y-%m-%d %H:%M:%S")}'
f'打手ID={dashou_id},操作人={operator}'
),
)
return Response({
'code': 0,
'msg': '改期成功',
'data': {
'id': rec.id,
'huiyuan_id': rec.huiyuan_id,
'daoqi_time': rec.daoqi_time.strftime('%Y-%m-%d %H:%M:%S'),
},
})
if not huiyuan_id:
return Response({'code': 400, 'msg': '缺少会员ID'})
rec, created, jifen_info, err = upsert_gift_huiyuan(
yonghu_id=dashou_id,
huiyuan_id=huiyuan_id,
daoqi_time=daoqi_time,
song_ren=song_ren,
)
if err:
return Response({'code': 400, 'msg': err})
try:
hy_name = HuiyuanModel.query.get(huiyuan_id=huiyuan_id).jieshao
except HuiyuanModel.DoesNotExist:
hy_name = huiyuan_id
if jifen_info:
write_xiugai_log(
yonghuid=dashou_id,
xiugaiid=operator,
leixing=XIUGAI_LEIXING_DASHOU,
jifen=jifen_info['after'],
yjifen=jifen_info['before'],
qitashuoming=(
f'【后台】送会员时整改积分:{jifen_info["before"]}{jifen_info["after"]}'
f'原积分={jifen_info["before"]},整改后={jifen_info["after"]}'
f'打手ID={dashou_id},操作人={operator}(送会员免费接单)'
),
)
action_label = '赠送' if created else '更新到期时间'
write_xiugai_log(
yonghuid=dashou_id,
xiugaiid=operator,
leixing=XIUGAI_LEIXING_DASHOU,
huiyuan_id=huiyuan_id,
qitashuoming=(
f'【后台】{action_label}赠送会员免费接单会员ID={huiyuan_id}{hy_name}'
f'到期={rec.daoqi_time.strftime("%Y-%m-%d %H:%M:%S")}'
f'打手ID={dashou_id},操作人={operator}(写入赠送会员表,非购买会员)'
),
)
return Response({
'code': 0,
'msg': '赠送成功' if created else '到期时间已更新',
'data': {
'id': rec.id,
'huiyuan_id': rec.huiyuan_id,
'daoqi_time': rec.daoqi_time.strftime('%Y-%m-%d %H:%M:%S'),
'created': created,
'jifen_adjusted': bool(jifen_info),
'jifen': jifen_info,
},
})
class DashouGiftHuiyuanRemoveView(APIView):
"""
移除赠送会员
POST /houtai/dsycsonghy
Body: { phone, dashou_id, id? , huiyuan_id? }
"""
permission_classes = [IsAuthenticated]
parser_classes = [JSONParser]
def post(self, request):
from jituan.services.gift_huiyuan import (
has_gift_huiyuan_permission,
remove_gift_huiyuan,
)
phone = (request.data.get('phone') or request.data.get('username') or '').strip()
dashou_id = (request.data.get('dashou_id') or request.data.get('uid') or '').strip()
record_id = request.data.get('id')
huiyuan_id = (request.data.get('huiyuan_id') or '').strip()
kefu, permissions = verify_kefu_permission(request, phone or None)
if kefu is None:
return permissions
if not has_gift_huiyuan_permission(permissions):
return Response({'code': 403, 'msg': '无移除赠送会员权限'})
if not dashou_id:
return Response({'code': 400, 'msg': '缺少打手ID'})
try:
dashou_user = User.query.get(UserUID=dashou_id)
except User.DoesNotExist:
return Response({'code': 404, 'msg': '打手不存在'})
denied = forbid_if_user_out_of_scope(request, dashou_user)
if denied:
return denied
rid = None
if record_id not in (None, ''):
try:
rid = int(record_id)
except (TypeError, ValueError):
return Response({'code': 400, 'msg': '无效的记录ID'})
ok, err = remove_gift_huiyuan(
record_id=rid,
yonghu_id=dashou_id if not rid else None,
huiyuan_id=huiyuan_id if not rid else None,
)
if err:
return Response({'code': 400, 'msg': err})
operator = getattr(kefu.user, 'Phone', None) or phone
write_xiugai_log(
yonghuid=dashou_id,
xiugaiid=operator,
leixing=XIUGAI_LEIXING_DASHOU,
huiyuan_id=huiyuan_id or '',
qitashuoming=(
f'【后台】移除赠送会员免费接单记录ID={rid or "-"}'
f'会员ID={huiyuan_id or "-"}打手ID={dashou_id},操作人={operator}'
),
)
return Response({'code': 0, 'msg': '移除成功'})

View File

@@ -0,0 +1,240 @@
"""后台赠送会员(免费接单):与购买会员 Huiyuangoumai 分离。"""
from datetime import datetime, time
from django.db import transaction
from django.utils import timezone
from django.utils.dateparse import parse_datetime, parse_date
from products.models import Huiyuan
from users.models import DashouZengsongHuiyuan, UserDashou
GIFT_HUIYUAN_PERMS = frozenset({
'000001', '001aa', '001bb', '001cc', '001dd', '001ee',
})
TARGET_JIFEN_ON_GIFT = 10
def has_gift_huiyuan_permission(permissions):
return any(p in (permissions or []) for p in GIFT_HUIYUAN_PERMS)
def _gift_record_active(record, now=None):
if not record or not record.daoqi_time:
return False
from jituan.services.huiyuan_bundle import _normalize_datetime_for_compare
now = _normalize_datetime_for_compare(now or timezone.now())
daoqi = _normalize_datetime_for_compare(record.daoqi_time)
return daoqi > now
def parse_gift_daoqi_time(raw):
"""
解析到期时间。
支持:'YYYY-MM-DD HH:MM:SS' / ISO / 'YYYY-MM-DD'(当天 23:59:59
"""
if raw is None or str(raw).strip() == '':
return None, '请填写到期时间'
text = str(raw).strip()
dt = parse_datetime(text.replace('/', '-'))
if dt is None:
d = parse_date(text.replace('/', '-'))
if d is None:
try:
dt = datetime.strptime(text, '%Y-%m-%d %H:%M:%S')
except ValueError:
try:
d = datetime.strptime(text, '%Y-%m-%d').date()
except ValueError:
return None, '到期时间格式错误,请用 YYYY-MM-DD 或 YYYY-MM-DD HH:MM:SS'
dt = datetime.combine(d, time(23, 59, 59))
else:
dt = datetime.combine(d, time(23, 59, 59))
if timezone.is_naive(dt) and timezone.is_aware(timezone.now()):
dt = timezone.make_aware(dt, timezone.get_current_timezone())
elif (not timezone.is_naive(dt)) and (not timezone.is_aware(timezone.now())):
dt = timezone.make_naive(dt, timezone.get_current_timezone())
if dt <= timezone.now():
return None, '到期时间必须晚于当前时间'
return dt, None
def list_gift_huiyuan_for_admin(yonghu_id):
"""后台详情:全部赠送记录(含已过期),附会员名。"""
records = list(
DashouZengsongHuiyuan.query.filter(yonghu_id=yonghu_id).order_by('-daoqi_time')
)
if not records:
return []
name_map = {
h.huiyuan_id: h.jieshao
for h in Huiyuan.query.filter(
huiyuan_id__in=[r.huiyuan_id for r in records]
).only('huiyuan_id', 'jieshao')
}
now = timezone.now()
out = []
for r in records:
active = _gift_record_active(r, now=now)
out.append({
'id': r.id,
'huiyuan_id': r.huiyuan_id,
'huiyuan_name': name_map.get(r.huiyuan_id, f'会员{r.huiyuan_id}'),
'daoqi_time': r.daoqi_time.strftime('%Y-%m-%d %H:%M:%S') if r.daoqi_time else '',
'song_ren': r.song_ren or '',
'song_time': r.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if r.CreateTime else '',
'is_active': active,
})
return out
def user_has_gift_huiyuan_access(yonghu_id, required_huiyuan_id, club_id=None):
"""抢单资格:赠送会员是否覆盖所需会员类型(支持总会员展开)。"""
from jituan.services.huiyuan_bundle import (
huiyuan_ids_match,
is_bundle_huiyuan,
normalize_huiyuan_id,
resolve_bundle_included_ids,
_included_huiyuan_id_set,
)
req = normalize_huiyuan_id(required_huiyuan_id)
if not req:
return True
req_set = {req, req.lstrip('0') or '0'}
now = timezone.now()
for rec in DashouZengsongHuiyuan.query.filter(yonghu_id=yonghu_id):
if not _gift_record_active(rec, now=now):
continue
if huiyuan_ids_match(rec.huiyuan_id, req):
return True
if is_bundle_huiyuan(rec.huiyuan_id):
included = resolve_bundle_included_ids(
rec.huiyuan_id,
club_id=club_id,
yonghu_id=yonghu_id,
)
if req_set & _included_huiyuan_id_set(included):
return True
return False
def build_gift_clumber_items(yonghu_id, club_id=None):
"""抢单池 clumber未过期赠送会员条目。"""
from jituan.services.huiyuan_bundle import (
_append_bundle_sub_clumber,
_append_clumber_id_variants,
format_legacy_daoqi,
is_bundle_huiyuan,
resolve_bundle_included_ids,
_resolve_user_club_id,
)
items = []
seen = set()
effective_club = _resolve_user_club_id(yonghu_id, club_id)
now = timezone.now()
for rec in DashouZengsongHuiyuan.query.filter(yonghu_id=yonghu_id):
if not _gift_record_active(rec, now=now):
continue
try:
hy = Huiyuan.query.get(huiyuan_id=rec.huiyuan_id)
ming = hy.jieshao or f'会员{rec.huiyuan_id}'
except Huiyuan.DoesNotExist:
ming = f'会员{rec.huiyuan_id}'
base = {
'huiyuanming': ming,
'daoqi': format_legacy_daoqi(rec.daoqi_time),
'huiyuan_zhuangtai': 1,
'shifou_daoqi': False,
'is_gift': True,
}
if is_bundle_huiyuan(rec.huiyuan_id):
base['is_bundle'] = True
base['bundle_huiyuan_id'] = rec.huiyuan_id
base['included_huiyuan_ids'] = resolve_bundle_included_ids(
rec.huiyuan_id,
club_id=effective_club,
yonghu_id=yonghu_id,
)
_append_clumber_id_variants(items, seen, base, rec.huiyuan_id)
_append_bundle_sub_clumber(items, seen, base)
return items
def upsert_gift_huiyuan(*, yonghu_id, huiyuan_id, daoqi_time, song_ren):
"""
赠送或改期。同一打手同一会员类型仅一条记录。
返回 (record, created, jifen_changed_info_or_None, error_msg)
jifen_changed_info = {'before': x, 'after': 10} 若调整了积分
"""
huiyuan_id = str(huiyuan_id or '').strip()
if not huiyuan_id:
return None, False, None, '缺少会员ID'
if not Huiyuan.query.filter(huiyuan_id=huiyuan_id).exists():
return None, False, None, '会员类型不存在'
jifen_info = None
with transaction.atomic():
try:
dashou = UserDashou.objects.select_for_update().select_related('user').get(
user__UserUID=yonghu_id
)
except UserDashou.DoesNotExist:
return None, False, None, '打手不存在'
before_jifen = int(dashou.jifen or 0)
if before_jifen != TARGET_JIFEN_ON_GIFT:
dashou.jifen = TARGET_JIFEN_ON_GIFT
dashou.save(update_fields=['jifen'])
jifen_info = {'before': before_jifen, 'after': TARGET_JIFEN_ON_GIFT}
locked_qs = DashouZengsongHuiyuan.objects.select_for_update().filter(
yonghu_id=yonghu_id, huiyuan_id=huiyuan_id
)
existing = locked_qs.first()
if existing:
existing.daoqi_time = daoqi_time
existing.song_ren = song_ren
existing.save(update_fields=['daoqi_time', 'song_ren', 'UpdateTime'])
return existing, False, jifen_info, None
record = DashouZengsongHuiyuan.query.create(
yonghu_id=yonghu_id,
huiyuan_id=huiyuan_id,
daoqi_time=daoqi_time,
song_ren=song_ren,
)
return record, True, jifen_info, None
def update_gift_huiyuan_daoqi(*, record_id, yonghu_id, daoqi_time, song_ren):
"""按记录 ID 改期。"""
try:
rec = DashouZengsongHuiyuan.query.get(id=record_id)
except DashouZengsongHuiyuan.DoesNotExist:
return None, '赠送会员记录不存在'
if str(rec.yonghu_id) != str(yonghu_id):
return None, '记录与打手不匹配'
rec.daoqi_time = daoqi_time
if song_ren:
rec.song_ren = song_ren
rec.save(update_fields=['daoqi_time', 'song_ren', 'UpdateTime'])
return rec, None
def remove_gift_huiyuan(*, record_id=None, yonghu_id=None, huiyuan_id=None):
"""按记录 ID或 (yonghu_id, huiyuan_id) 移除。"""
qs = DashouZengsongHuiyuan.query
if record_id:
deleted, _ = qs.filter(id=record_id).delete()
if not deleted:
return False, '赠送会员记录不存在'
return True, None
yonghu_id = str(yonghu_id or '').strip()
huiyuan_id = str(huiyuan_id or '').strip()
if not yonghu_id or not huiyuan_id:
return False, '缺少记录ID或会员ID'
deleted, _ = qs.filter(yonghu_id=yonghu_id, huiyuan_id=huiyuan_id).delete()
if not deleted:
return False, '赠送会员记录不存在'
return True, None

View File

@@ -231,6 +231,10 @@ def user_has_huiyuan_access(yonghu_id, required_huiyuan_id, club_id=None):
if _czjilu_grants_huiyuan_access(yonghu_id, req, club_id):
return True
from jituan.services.gift_huiyuan import user_has_gift_huiyuan_access
if user_has_gift_huiyuan_access(yonghu_id, req, club_id=club_id):
return True
return False
@@ -498,26 +502,33 @@ def _build_clumber_from_paid_czjilu(yonghu_id, club_id=None):
def _finalize_clumber_for_legacy_client(items):
"""老端只认 huiyuanid去掉 is_trial 等内部字段。"""
"""老端只认 huiyuanid去掉 is_trial / is_gift 等内部字段。"""
cleaned = []
for it in items or []:
row = dict(it)
row.pop('is_trial', None)
row.pop('is_gift', None)
cleaned.append(row)
return cleaned
def ensure_grab_pool_clumber(yonghu_id, club_id=None):
"""
dddhq / dashouxinxi只读 huiyuangoumai + 有效期内充值单 生成 clumber(体验=正式)
dddhq / dashouxinxi只读 huiyuangoumai + 有效期内充值单 + 赠送会员 生成 clumber。
总会员展开子会员虚拟条目供老端 clumber 比对;不写库、不补开通。
"""
from jituan.services.gift_huiyuan import build_gift_clumber_items
effective_club = _resolve_user_club_id(yonghu_id, club_id)
items = _build_user_clumber_core(yonghu_id, club_id=effective_club)
items = _merge_clumber_extra_items(
items,
_build_clumber_from_paid_czjilu(yonghu_id, club_id=effective_club),
)
items = _merge_clumber_extra_items(
items,
build_gift_clumber_items(yonghu_id, club_id=effective_club),
)
items = _finalize_clumber_for_legacy_client(items)
return bool(items), items

View File

@@ -0,0 +1,33 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0004_user_shangjia_youzhi'),
]
operations = [
migrations.CreateModel(
name='DashouZengsongHuiyuan',
fields=[
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='记录ID')),
('yonghu_id', models.CharField(db_index=True, max_length=7, verbose_name='打手用户ID')),
('huiyuan_id', models.CharField(db_index=True, max_length=6, verbose_name='会员ID')),
('daoqi_time', models.DateTimeField(db_index=True, verbose_name='到期时间')),
('song_ren', models.CharField(max_length=30, verbose_name='赠送人账号')),
('CreateTime', models.DateTimeField(auto_now_add=True, verbose_name='赠送时间')),
('UpdateTime', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
],
options={
'verbose_name': '打手赠送会员',
'verbose_name_plural': '打手赠送会员',
'db_table': 'dashou_zengsong_huiyuan',
'indexes': [
models.Index(fields=['yonghu_id', 'huiyuan_id'], name='dashou_zeng_yonghu__7a1c01_idx'),
models.Index(fields=['yonghu_id', 'daoqi_time'], name='dashou_zeng_yonghu__8b2d02_idx'),
],
'unique_together': {('yonghu_id', 'huiyuan_id')},
},
),
]

View File

@@ -553,7 +553,31 @@ class Xiugaijilu(QModel):
return f"修改记录-用户{self.yonghuid}"
class DashouZengsongHuiyuan(QModel):
"""
后台赠送会员(免费接单资格),与 Huiyuangoumai 购买会员完全分离。
仅用于抢单/抢单池资格;不参与提现正式会员校验。
"""
id = models.AutoField(primary_key=True, verbose_name='记录ID')
yonghu_id = models.CharField(max_length=7, db_index=True, verbose_name='打手用户ID')
huiyuan_id = models.CharField(max_length=6, db_index=True, verbose_name='会员ID')
daoqi_time = models.DateTimeField(db_index=True, verbose_name='到期时间')
song_ren = models.CharField(max_length=30, verbose_name='赠送人账号')
CreateTime = models.DateTimeField(auto_now_add=True, verbose_name='赠送时间')
UpdateTime = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'dashou_zengsong_huiyuan'
verbose_name = '打手赠送会员'
verbose_name_plural = verbose_name
unique_together = [['yonghu_id', 'huiyuan_id']]
indexes = [
models.Index(fields=['yonghu_id', 'huiyuan_id']),
models.Index(fields=['yonghu_id', 'daoqi_time']),
]
def __str__(self):
return f"赠送会员-用户{self.yonghu_id}-会员{self.huiyuan_id}"
# yonghu/models.py - 新增排行榜模型