feat: 管事自助更换组长(配额、记录、小程序与后台接口)

This commit is contained in:
XingQue
2026-07-31 10:10:12 +08:00
parent 1cc3f07480
commit 62f121f438
9 changed files with 579 additions and 5 deletions

View File

@@ -6,7 +6,7 @@ from .view import (GetRolePermissionView,
ModifyAdminUserView, KefuGetDashouListView, KefuGetDashouDetailView, KefuUpdateDashouView, KefuGetShangjiaListView,
KefuGetShangjiaDetailView, KefuUpdateShangjiaView, KefuAddShangjiaView, GetProductBaseDataView, GetProductListView, SaveProductOrderView,
AddProductView, DeleteProductView, GetProductDetailView, UpdateProductView, UpdateZhiKanShenheView, UpdateMemberView, GetMemberListView,
AddMemberView, GetGuanliListView, GetGuanliDetailView, PromoteGuanshiToZuzhangView, ChangeInviterView, UpdateGuanliView, GetWithdrawSettingsView,
AddMemberView, GetGuanliListView, GetGuanliDetailView, PromoteGuanshiToZuzhangView, ChangeInviterView, UpdateGuanliView, GuanshiChangeLeaderQuotaView, GuanshiChangeLeaderLogView, GetWithdrawSettingsView,
UpdateWithdrawSettingsView, GetZuzhangListView, GetZuzhangDetailView, UpdateZuzhangView, GetOperationLogListView, GetProductTypeZoneView,
ModifyProductTypeZoneView, GetRateView, ModifyRateView, PopupNoticeListAPIView, PopupNoticeModifyAPIView,ShopListView,
ShopModifyView, ShopPublicTypeAndAuditView, ShopListForProductView, ShopProductModifyView,
@@ -56,6 +56,8 @@ urlpatterns = [
path('hthqgsxq', GetGuanliDetailView.as_view(), name='后台获取管事详情信息'),
path('htgssjzz', PromoteGuanshiToZuzhangView.as_view(), name='后台管事升级组长'),
path('htghyqr', ChangeInviterView.as_view(), name='后台更换邀请人'),
path('htgs_huan_zz_quota', GuanshiChangeLeaderQuotaView.as_view(), name='后台管事换组长次数'),
path('htgs_huan_zz_logs', GuanshiChangeLeaderLogView.as_view(), name='后台管事换组长记录'),
path('htxggsxx', UpdateGuanliView.as_view(), name='后台更新管事数据'),
path('hqczrz', GetOperationLogListView.as_view(), name='后台操作日志列表'),
path('hthqtxpz', GetWithdrawSettingsView.as_view(), name='后台获取提现配置'),

View File

@@ -51,7 +51,7 @@ from .views.members import (
)
from .views.guanli import (
GetGuanliListView, GetGuanliDetailView, PromoteGuanshiToZuzhangView,
UpdateGuanliView,
UpdateGuanliView, GuanshiChangeLeaderQuotaView, GuanshiChangeLeaderLogView,
)
from .views.withdraw_settings import (
GetWithdrawSettingsView, UpdateWithdrawSettingsView,
@@ -113,7 +113,7 @@ __all__ = [
'MemberCardImageUploadView', 'MemberRechargeRecordsView', 'MemberBundleCreateView',
# guanli
'GetGuanliListView', 'GetGuanliDetailView', 'PromoteGuanshiToZuzhangView',
'UpdateGuanliView',
'UpdateGuanliView', 'GuanshiChangeLeaderQuotaView', 'GuanshiChangeLeaderLogView',
# withdraw_settings
'GetWithdrawSettingsView', 'UpdateWithdrawSettingsView',
# zuzhang

View File

@@ -387,6 +387,19 @@ class GetGuanliDetailView(APIView):
# 注意:首次分红定制只存储有定制记录的会员,没有定制的会员使用默认值(前端通过会员表展示)
# 额外次数分红按次数返回
from jituan.services.club_context import resolve_club_id_from_request, resolve_club_scope
from jituan.constants import DATA_SCOPE_ALL
from jituan.services.club_user import get_user_club_id
from users.services.change_leader import get_or_create_quota, quota_payload, list_change_logs
if resolve_club_scope(request) == DATA_SCOPE_ALL:
quota_club = get_user_club_id(user)
else:
quota_club = resolve_club_id_from_request(request)
quota = get_or_create_quota(quota_club, yonghuid)
change_leader_quota = quota_payload(quota)
change_leader_logs = list_change_logs(quota_club, yonghuid, page=1, page_size=20)
return Response({
'code': 0,
'data': {
@@ -398,6 +411,8 @@ class GetGuanliDetailView(APIView):
'extra_dividend_map': extra_map,
'all_members': all_members,
'is_zuzhang': is_zuzhang,
'change_leader_quota': change_leader_quota,
'change_leader_logs': change_leader_logs,
}
})
@@ -855,7 +870,117 @@ class UpdateGuanliView(APIView):
return Response({'code': 0, 'msg': '修改成功'})
def _admin_quota_club_id(request, user):
from jituan.services.club_context import resolve_club_id_from_request, resolve_club_scope
from jituan.constants import DATA_SCOPE_ALL
from jituan.services.club_user import get_user_club_id
if resolve_club_scope(request) == DATA_SCOPE_ALL:
return get_user_club_id(user)
return resolve_club_id_from_request(request)
class GuanshiChangeLeaderQuotaView(APIView):
"""
后台设置/追加管事换组长次数
POST /houtai/htgs_huan_zz_quota
参数username, yonghuid,
action=set|add,
total_quotaset或 add_countadd
权限4400a
"""
permission_classes = []
parser_classes = [JSONParser]
def post(self, request):
username = request.data.get('username', '').strip()
yonghuid = request.data.get('yonghuid', '').strip()
action = (request.data.get('action') or 'add').strip().lower()
if not username:
return Response({'code': 401, 'msg': '缺少username'})
if not yonghuid:
return Response({'code': 400, 'msg': '缺少用户ID'})
kefu, permissions = verify_kefu_permission(request, username)
if kefu is None:
return permissions
if '4400a' not in permissions and '000001' not in permissions:
return Response({'code': 403, 'msg': '无权限修改换组长次数需要4400a'})
try:
user = User.query.select_related('GuanshiProfile').get(UserUID=yonghuid)
_ = user.GuanshiProfile
except User.DoesNotExist:
return Response({'code': 404, 'msg': '管事不存在'})
except UserGuanshi.DoesNotExist:
return Response({'code': 404, 'msg': '用户不是管事'})
denied = forbid_if_user_out_of_scope(request, user)
if denied:
return denied
from users.services.change_leader import set_total_quota, add_quota
club_id = _admin_quota_club_id(request, user)
if action == 'set':
result = set_total_quota(club_id, yonghuid, request.data.get('total_quota'))
else:
result = add_quota(
club_id,
yonghuid,
request.data.get('add_count') or request.data.get('add'),
)
if not result.get('ok'):
return Response({'code': result.get('code', 400), 'msg': result.get('msg', '失败')})
return Response({'code': 0, 'msg': result.get('msg', 'ok'), 'data': result.get('data')})
class GuanshiChangeLeaderLogView(APIView):
"""
后台查询管事换组长记录
POST /houtai/htgs_huan_zz_logs
参数username, yonghuid, page, page_size
权限4400a-f 任一
"""
permission_classes = []
parser_classes = [JSONParser]
def post(self, request):
username = request.data.get('username', '').strip()
yonghuid = request.data.get('yonghuid', '').strip()
if not username:
return Response({'code': 401, 'msg': '缺少username'})
if not yonghuid:
return Response({'code': 400, 'msg': '缺少用户ID'})
kefu, permissions = verify_kefu_permission(request, username)
if kefu is None:
return permissions
required_perms = {'4400a', '4400b', '4400c', '4400d', '4400e', '4400f', '000001'}
if not any(p in permissions for p in required_perms):
return Response({'code': 403, 'msg': '您没有权限查看换组长记录'})
try:
user = User.query.select_related('GuanshiProfile').get(UserUID=yonghuid)
_ = user.GuanshiProfile
except User.DoesNotExist:
return Response({'code': 404, 'msg': '管事不存在'})
except UserGuanshi.DoesNotExist:
return Response({'code': 404, 'msg': '用户不是管事'})
denied = forbid_if_user_out_of_scope(request, user)
if denied:
return denied
from users.services.change_leader import list_change_logs
club_id = _admin_quota_club_id(request, user)
data = list_change_logs(
club_id,
yonghuid,
page=request.data.get('page', 1),
page_size=request.data.get('page_size', 20),
)
return Response({'code': 0, 'data': data})

View File

@@ -0,0 +1,55 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0009_user_shangjia_teyue'),
]
operations = [
migrations.CreateModel(
name='GuanshiChangeLeaderQuota',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('club_id', models.CharField(db_index=True, max_length=16, verbose_name='俱乐部ID')),
('guanshi_uid', models.CharField(db_index=True, max_length=7, verbose_name='管事UserUID')),
('total_quota', models.IntegerField(default=1, verbose_name='总次数')),
('used_count', models.IntegerField(default=0, 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': 'guanshi_change_leader_quota',
'indexes': [
models.Index(fields=['club_id', 'guanshi_uid'], name='guanshi_cha_club_id_b8a1f0_idx'),
],
'unique_together': {('club_id', 'guanshi_uid')},
},
),
migrations.CreateModel(
name='GuanshiChangeLeaderLog',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('club_id', models.CharField(db_index=True, max_length=16, verbose_name='俱乐部ID')),
('guanshi_uid', models.CharField(db_index=True, max_length=7, verbose_name='管事UserUID')),
('guanshi_name', models.CharField(blank=True, default='', max_length=50, verbose_name='管事昵称')),
('old_zuzhang_uid', models.CharField(blank=True, default='', max_length=7, verbose_name='原组长UID')),
('new_zuzhang_uid', models.CharField(db_index=True, max_length=7, verbose_name='新组长UID')),
('new_invite_code', models.CharField(blank=True, default='', max_length=40, verbose_name='提交的邀请码')),
('source', models.CharField(default='miniapp', max_length=20, verbose_name='来源')),
('operator', models.CharField(blank=True, default='', max_length=64, verbose_name='操作人')),
('CreateTime', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='更换时间')),
],
options={
'verbose_name': '管事换组长记录',
'verbose_name_plural': '管事换组长记录',
'db_table': 'guanshi_change_leader_log',
'indexes': [
models.Index(fields=['club_id', 'guanshi_uid', '-CreateTime'], name='guanshi_cha_club_id_9c2e1a_idx'),
],
},
),
]

View File

@@ -714,6 +714,51 @@ class UserSensitiveData(QModel):
return f'敏感数据-{self.user_uuid_id}'
# ==================== 管事更换组长:配额 / 记录 ====================
class GuanshiChangeLeaderQuota(QModel):
"""管事自助更换组长次数配额(按俱乐部 + 管事 UID"""
club_id = models.CharField(max_length=16, db_index=True, verbose_name='俱乐部ID')
guanshi_uid = models.CharField(max_length=7, db_index=True, verbose_name='管事UserUID')
total_quota = models.IntegerField(default=1, verbose_name='总次数')
used_count = models.IntegerField(default=0, verbose_name='已用次数')
CreateTime = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
UpdateTime = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'guanshi_change_leader_quota'
verbose_name = '管事换组长配额'
verbose_name_plural = verbose_name
unique_together = [['club_id', 'guanshi_uid']]
indexes = [
models.Index(fields=['club_id', 'guanshi_uid']),
]
@property
def remain_quota(self):
return max(0, int(self.total_quota or 0) - int(self.used_count or 0))
class GuanshiChangeLeaderLog(QModel):
"""管事更换组长记录"""
club_id = models.CharField(max_length=16, db_index=True, verbose_name='俱乐部ID')
guanshi_uid = models.CharField(max_length=7, db_index=True, verbose_name='管事UserUID')
guanshi_name = models.CharField(max_length=50, blank=True, default='', verbose_name='管事昵称')
old_zuzhang_uid = models.CharField(max_length=7, blank=True, default='', verbose_name='原组长UID')
new_zuzhang_uid = models.CharField(max_length=7, db_index=True, verbose_name='新组长UID')
new_invite_code = models.CharField(max_length=40, blank=True, default='', verbose_name='提交的邀请码')
source = models.CharField(max_length=20, default='miniapp', verbose_name='来源') # miniapp / admin
operator = models.CharField(max_length=64, blank=True, default='', verbose_name='操作人')
CreateTime = models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='更换时间')
class Meta:
db_table = 'guanshi_change_leader_log'
verbose_name = '管事换组长记录'
verbose_name_plural = verbose_name
indexes = [
models.Index(fields=['club_id', 'guanshi_uid', '-CreateTime']),
]
# === 业务用户模型注册 ===
# 导入业务子类,使 Django app registry 注册具体 User 模型users.User
# 放在文件末尾以避免循环导入:此时本模块所有类已定义完毕。

View File

@@ -0,0 +1,276 @@
"""管事自助更换组长:配额、校验、换绑。"""
import logging
from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
from django.db.models import F
from jituan.services.club_context import resolve_effective_club_id
from jituan.services.invite_guard import assert_invite_same_club
from users.models import GuanshiChangeLeaderLog, GuanshiChangeLeaderQuota, UserGuanshi, UserZuzhang
from users.business_models import User
logger = logging.getLogger(__name__)
DEFAULT_QUOTA = 1
def _guanshi_display_name(user):
try:
return (user.BossProfile.nickname or '').strip() or user.UserUID
except ObjectDoesNotExist:
return user.UserUID
def _zuzhang_brief(uid):
if not uid:
return None
try:
u = User.query.get(UserUID=uid)
except User.DoesNotExist:
return {'uid': uid, 'nicheng': '未知', 'touxiang': ''}
try:
nicheng = u.BossProfile.nickname or '组长'
except ObjectDoesNotExist:
nicheng = '组长'
return {
'uid': u.UserUID,
'nicheng': nicheng,
'touxiang': u.Avatar or '',
}
def get_or_create_quota(club_id, guanshi_uid):
club_id = (club_id or '').strip()
guanshi_uid = (guanshi_uid or '').strip()
obj, _ = GuanshiChangeLeaderQuota.objects.get_or_create(
club_id=club_id,
guanshi_uid=guanshi_uid,
defaults={'total_quota': DEFAULT_QUOTA, 'used_count': 0},
)
return obj
def quota_payload(quota):
return {
'total_quota': int(quota.total_quota or 0),
'used_count': int(quota.used_count or 0),
'remain_quota': quota.remain_quota,
}
def build_change_leader_info(request, user):
"""小程序 info 接口数据。"""
try:
guanshi = user.GuanshiProfile
except ObjectDoesNotExist:
return {'ok': False, 'code': 403, 'msg': '您还不是管事'}
if guanshi.zhuangtai != 1:
return {'ok': False, 'code': 403, 'msg': '管事账号已禁用,无法更换组长'}
club_id = resolve_effective_club_id(request, user)
quota = get_or_create_quota(club_id, user.UserUID)
return {
'ok': True,
'code': 200,
'msg': 'ok',
'data': {
'club_id': club_id,
'current_zuzhang': _zuzhang_brief(guanshi.yaoqingren),
'quota': quota_payload(quota),
},
}
def change_leader_by_invite(request, user, invite_code, source='miniapp', operator=None):
"""
用组长邀请码换绑。成功返回 data失败返回 ok=False。
仅更新管事 yaoqingren不改名下打手。
"""
invite_code = (invite_code or '').strip()
if not invite_code:
return {'ok': False, 'code': 400, 'msg': '请输入组长邀请码'}
if len(invite_code) > 100:
return {'ok': False, 'code': 400, 'msg': '邀请码长度超过限制'}
try:
guanshi = user.GuanshiProfile
except ObjectDoesNotExist:
return {'ok': False, 'code': 403, 'msg': '您还不是管事'}
if guanshi.zhuangtai != 1:
return {'ok': False, 'code': 403, 'msg': '管事账号已禁用,无法更换组长'}
try:
zuzhang = UserZuzhang.query.select_related('user').get(yaoqingma=invite_code)
except UserZuzhang.DoesNotExist:
return {'ok': False, 'code': 404, 'msg': '邀请码无效或不存在'}
if zuzhang.zhuangtai != 1:
return {'ok': False, 'code': 403, 'msg': '该邀请码对应的组长账号已被禁用'}
new_uid = zuzhang.user.UserUID
if new_uid == user.UserUID:
return {'ok': False, 'code': 400, 'msg': '不能将自己设为组长'}
old_uid = (guanshi.yaoqingren or '').strip()
if old_uid and old_uid == new_uid:
return {'ok': False, 'code': 400, 'msg': '已是该组长,无需更换'}
ok, invite_msg = assert_invite_same_club(request, zuzhang.user, user)
if not ok:
return {'ok': False, 'code': 403, 'msg': invite_msg}
club_id = resolve_effective_club_id(request, user)
op = (operator or user.UserUID or '').strip()
with transaction.atomic():
quota = (
GuanshiChangeLeaderQuota.objects
.select_for_update()
.filter(club_id=club_id, guanshi_uid=user.UserUID)
.first()
)
if not quota:
quota = GuanshiChangeLeaderQuota.objects.create(
club_id=club_id,
guanshi_uid=user.UserUID,
total_quota=DEFAULT_QUOTA,
used_count=0,
)
quota = (
GuanshiChangeLeaderQuota.objects
.select_for_update()
.get(pk=quota.pk)
)
if quota.remain_quota <= 0:
return {'ok': False, 'code': 403, 'msg': '更换次数已用完,请联系客服增加次数'}
# 再读一次管事行,防并发
guanshi = (
UserGuanshi.query
.select_for_update()
.select_related('user')
.get(pk=guanshi.pk)
)
old_uid = (guanshi.yaoqingren or '').strip()
if old_uid == new_uid:
return {'ok': False, 'code': 400, 'msg': '已是该组长,无需更换'}
guanshi.yaoqingren = new_uid
guanshi.save(update_fields=['yaoqingren'])
if old_uid:
try:
old_zz = UserZuzhang.query.select_related('user').get(user__UserUID=old_uid)
if (old_zz.yaoqing_zongshu or 0) > 0:
UserZuzhang.query.filter(pk=old_zz.pk).update(
yaoqing_zongshu=F('yaoqing_zongshu') - 1
)
except UserZuzhang.DoesNotExist:
pass
UserZuzhang.query.filter(pk=zuzhang.pk).update(
yaoqing_zongshu=F('yaoqing_zongshu') + 1
)
quota.used_count = int(quota.used_count or 0) + 1
quota.save(update_fields=['used_count', 'UpdateTime'])
GuanshiChangeLeaderLog.objects.create(
club_id=club_id,
guanshi_uid=user.UserUID,
guanshi_name=_guanshi_display_name(user)[:50],
old_zuzhang_uid=old_uid or '',
new_zuzhang_uid=new_uid,
new_invite_code=invite_code[:40],
source=source or 'miniapp',
operator=op[:64],
)
logger.info(
'guanshi_change_leader ok club=%s gs=%s %s -> %s source=%s',
club_id, user.UserUID, old_uid, new_uid, source,
)
return {
'ok': True,
'code': 200,
'msg': '更换组长成功',
'data': {
'current_zuzhang': _zuzhang_brief(new_uid),
'quota': quota_payload(quota),
'old_zuzhang_uid': old_uid or '',
'new_zuzhang_uid': new_uid,
},
}
def set_total_quota(club_id, guanshi_uid, total_quota):
"""后台设置总次数(不得小于已用次数)。"""
try:
total = int(total_quota)
except (TypeError, ValueError):
return {'ok': False, 'code': 400, 'msg': '总次数须为整数'}
if total < 0:
return {'ok': False, 'code': 400, 'msg': '总次数不能为负数'}
quota = get_or_create_quota(club_id, guanshi_uid)
if total < int(quota.used_count or 0):
return {
'ok': False,
'code': 400,
'msg': f'总次数不能小于已用次数(已用 {quota.used_count}',
}
quota.total_quota = total
quota.save(update_fields=['total_quota', 'UpdateTime'])
return {'ok': True, 'code': 0, 'msg': '已更新', 'data': quota_payload(quota)}
def add_quota(club_id, guanshi_uid, add_n):
"""后台追加次数(增加 total_quota"""
try:
n = int(add_n)
except (TypeError, ValueError):
return {'ok': False, 'code': 400, 'msg': '追加次数须为整数'}
if n <= 0:
return {'ok': False, 'code': 400, 'msg': '追加次数须大于 0'}
quota = get_or_create_quota(club_id, guanshi_uid)
quota.total_quota = int(quota.total_quota or 0) + n
quota.save(update_fields=['total_quota', 'UpdateTime'])
return {'ok': True, 'code': 0, 'msg': '已追加', 'data': quota_payload(quota)}
def list_change_logs(club_id, guanshi_uid, page=1, page_size=20):
qs = (
GuanshiChangeLeaderLog.objects
.filter(club_id=club_id, guanshi_uid=guanshi_uid)
.order_by('-CreateTime', '-id')
)
total = qs.count()
try:
page = max(1, int(page))
except (TypeError, ValueError):
page = 1
try:
page_size = min(100, max(1, int(page_size)))
except (TypeError, ValueError):
page_size = 20
start = (page - 1) * page_size
rows = []
for row in qs[start:start + page_size]:
rows.append({
'id': row.id,
'old_zuzhang_uid': row.old_zuzhang_uid,
'new_zuzhang_uid': row.new_zuzhang_uid,
'new_invite_code': row.new_invite_code,
'source': row.source,
'operator': row.operator,
'created_at': row.CreateTime.isoformat() if row.CreateTime else None,
})
return {
'list': rows,
'total': total,
'page': page,
'page_size': page_size,
}

View File

@@ -20,7 +20,8 @@ from .views import WechatMiniProgramLoginView, UserInfoUpdateView, DashouXinxiAP
FaKuanShenSuView, FaKuanPayView,FaKuanHuitiaoView, FaKuanPayPollView, FaKuanPayFailView,KaohePayView,KaohePayCallbackView, KaohePayPollView,KaohePayFailView, TixianAssetView, GuanshiContactView,TixianQueRenAutoView, TixianShenqingV3View, TixianCallbackV3View, \
GetUserPhoneView, BindUserPhoneView, BossSearchDashouView, \
FundFreezeMineView, FundFreezeMyLedgerView, FundFreezeMyLedgerDetailView, \
RoleAgreementCurrentView, RoleAgreementMineView, RoleAgreementSignView
RoleAgreementCurrentView, RoleAgreementMineView, RoleAgreementSignView, \
GuanshiChangeZuzhangInfoView, GuanshiChangeZuzhangView
from .tixian_shenhe_views import TixianZddkshApplyView
from .paihang_views import PhbHqsjView
from .xzj_paihang_views import XzjPhbHqsjView
@@ -135,6 +136,10 @@ urlpatterns = [
# 未登录用户微信登录+管事注册
path('zuzhangyqmzc', WechatLoginAndGuanshiRegisterView.as_view(), name='管事注册,没有登录'),
# 管事自助更换组长
path('gs_huan_zuzhang_info', GuanshiChangeZuzhangInfoView.as_view(), name='管事换组长信息'),
path('gs_huan_zuzhang', GuanshiChangeZuzhangView.as_view(), name='管事换组长提交'),
path('zuzhangzhuce', ZuzhangZhuceView.as_view(), name='组长注册'),
path('zuzhangxinxi', ZuzhangXinxiView.as_view(), name='组长刷新获取信息'),

View File

@@ -74,6 +74,11 @@ from .role_agreement_mp import (
RoleAgreementSignView,
)
from .change_leader_mp import (
GuanshiChangeZuzhangInfoView,
GuanshiChangeZuzhangView,
)
from .admin import (
AdGetOrderList,
AdGetOrderTypes,

View File

@@ -0,0 +1,61 @@
"""小程序:管事更换组长。"""
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from users.services.change_leader import build_change_leader_info, change_leader_by_invite
class GuanshiChangeZuzhangInfoView(APIView):
"""
POST /yonghu/gs_huan_zuzhang_info
当前组长 + 剩余更换次数
"""
permission_classes = [IsAuthenticated]
def post(self, request):
result = build_change_leader_info(request, request.user)
if not result.get('ok'):
return Response({
'code': result.get('code', 403),
'msg': result.get('msg', '失败'),
'data': None,
})
return Response({
'code': 200,
'msg': result.get('msg', 'ok'),
'data': result.get('data'),
})
class GuanshiChangeZuzhangView(APIView):
"""
POST /yonghu/gs_huan_zuzhang
body: { inviteCode: 组长邀请码 }
"""
permission_classes = [IsAuthenticated]
def post(self, request):
invite = (
request.data.get('inviteCode')
or request.data.get('yaoqingma')
or ''
)
result = change_leader_by_invite(
request,
request.user,
invite,
source='miniapp',
operator=getattr(request.user, 'UserUID', '') or '',
)
if not result.get('ok'):
return Response({
'code': result.get('code', 400),
'msg': result.get('msg', '更换失败'),
'data': None,
})
return Response({
'code': 200,
'msg': result.get('msg', '更换组长成功'),
'data': result.get('data'),
})