import hmac import threading import traceback import uuid import hashlib import xmltodict import time import logging import requests import os import secrets import random import string from calendar import monthrange from decimal import Decimal from datetime import date, datetime, timedelta from django.utils import timezone from django.conf import settings from django.core.exceptions import ObjectDoesNotExist from django.core.paginator import Paginator from django.db import models, transaction, IntegrityError from django.db.models import Q, Count, Sum, F, Exists, OuterRef from gvsdsdk.fluent import db, func, FQ from django.db.models.functions import TruncDate, TruncMonth, TruncYear from django.contrib.auth.hashers import make_password from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from rest_framework.permissions import IsAuthenticated, AllowAny from rest_framework.parsers import JSONParser, MultiPartParser, FormParser # 工具类导入 from utils.oss_utils import validate_image, upload_to_oss, delete_from_oss from backend.utils import ( update_dashou_daily_by_action, update_shangjia_daily ) from jituan.services.club_context import filter_club_char_field, filter_queryset_by_club, filter_user_related_by_club, filter_user_qs_by_club, orders_for_request from jituan.services.catalog_scope import block_non_group_catalog_scope from jituan.services.club_penalty import ( filter_penalty_qs, resolve_penalty_club_id, filter_gsfenhong_qs, forbid_penalty_out_of_scope, resolve_penalty_record_club_id, ) from jituan.services.club_user_access import forbid_if_user_out_of_scope, list_response_meta from shop.utils import update_dianpu_daily_stat from products.utils import update_shangpin_daily_stat from orders.notice_tasks import dingdan_guangbo from ..utils import ( verify_kefu_permission, PERMISSION_TO_SHENFEN, SHENFEN_PROFILE_MAP, has_fadan_view_permission, has_merchant_order_permission, check_fadan_permission, pick_order_id, pick_penalty_create_params, write_xiugai_log, XIUGAI_LEIXING_DASHOU, XIUGAI_LEIXING_GUANSHI, XIUGAI_LEIXING_SHANGJIA, XIUGAI_LEIXING_ZUZHANG, XIUGAI_LEIXING_LABEL, ) # models 集中导入 ## gvsdsdk RBAC 模型(使用 PascalCase 字段名,匹配实际数据库表结构) from gvsdsdk.models import Role, Permission, RolePermission, UserRole ## backend from backend.models import WithdrawalDailyStats ## users from users.models import ( UserGuanshi, UserBoss, UserZuzhang, UserKefu, UserDashou, Xiugaijilu, UserShangjia, UserShenheguan ) from users.business_models import User ## orders from orders.models import ( CommissionRate, PlayerDeliveryImage, PenaltyRecord, OrderPlayerHistory, Order, RefundRecord, MerchantOrderExt, Penalty, PenaltyAppealImage, PenaltyBonus ) ## shop from shop.models import Dianpu, DianpuMorenPeizhi, YonghuPingzheng, ShangpinLeixingDianpu, DianpuShangpinShenheShezhi ## products from products.models import ( Shangpin, ShangpinLeixing, ShangpinZhuanqu, Huiyuan, DuociFenhong, Czjilu, Huiyuangoumai, Gsfenhong ) ## config from config.models import ( WithdrawConfig, ShangjiaLianjie, AccountPermission, TixianQuotaDefault, DailyIncomeStat, DailyPayoutStat, PopupPage, PopupConfig, PopupImage ) ## rank from rank.models import ( KaoheguanBankuai, Bankuai, Chenghao, KaoheCishuFeiyong, YonghuChenghao, ShenheJilu, KaoheJiluFeiyong, KaoheJujueJilu ) # 序列化器 from ..serializers import PopupPageSerializer # 全局常量、日志对象 logger = logging.getLogger('houtai') SHOP_PRODUCT_PERMS = ['1199ab', '1199abc', '1199abd'] def _serialize_permission_row(perm_row): """gvsdsdk Permission → 后台 Vue 约定的小写字段""" if isinstance(perm_row, dict): code = perm_row.get('PermCode') or perm_row.get('perm_code') or '' name = perm_row.get('PermName') or perm_row.get('perm_name') or code desc = perm_row.get('PermDesc') or perm_row.get('perm_desc') or '' else: code = perm_row.PermCode or '' name = perm_row.PermName or code desc = perm_row.PermDesc or '' return {'perm_code': code, 'perm_name': name, 'perm_desc': desc} class GetRolePermissionView(APIView): """ 获取所有角色、权限以及角色关联的用户数 权限要求:用户必须拥有 000001 权限 """ permission_classes = [IsAuthenticated] def post(self, request): username = request.data.get('username', '').strip() if not username: return Response({'code': 400, 'msg': '缺少username'}) # 1. 权限校验(验证客服身份,并获取权限列表) kefu, permissions = verify_kefu_permission(request, username) if kefu is None: return permissions # 直接返回错误响应 # 2. 检查是否有 000001 权限 if '000001' not in permissions: return Response({'code': 403, 'msg': '您无权访问此页面'}) # 3. 获取所有权限 all_perms = Permission.objects.filter(PermStatus=1).values('PermCode', 'PermName', 'PermDesc') permissions_list = [_serialize_permission_row(p) for p in all_perms] from jituan.services.club_rbac import count_role_users_in_scope, filter_roles_for_request kefu_user_uuids = list( User.objects.filter(KefuProfile__isnull=False).values_list('UserUUID', flat=True) ) roles = filter_roles_for_request(request) roles_data = [] for role in roles: user_count = count_role_users_in_scope(role, request, kefu_user_uuids) role_perm_uuids = RolePermission.objects.filter( RoleUUID=role.RoleUUID ).values_list('PermUUID', flat=True) perms_of_role = [ _serialize_permission_row(p) for p in Permission.objects.filter( PermUUID__in=list(role_perm_uuids) ).values('PermCode', 'PermName', 'PermDesc') ] roles_data.append({ 'role_code': role.RoleName, 'role_name': role.RoleName, 'description': role.RoleDesc or '', 'club_id': getattr(role, 'ClubID', '') or '', 'user_count': user_count, 'permissions': perms_of_role }) return Response({ 'code': 0, 'data': { 'roles': roles_data, 'permissions': permissions_list } }) class ModifyRolePermissionView(APIView): """ 通用接口:支持删除角色、为角色添加权限、移除角色权限 操作类型通过 action 字段区分 """ permission_classes = [IsAuthenticated] def post(self, request): username = request.data.get('username', '').strip() action = request.data.get('action') # delete_role, add_permission, remove_permission if not username or not action: return Response({'code': 400, 'msg': '缺少必要参数'}) # 权限校验 kefu, permissions = verify_kefu_permission(request, username) if kefu is None: return permissions if '000001' not in permissions: return Response({'code': 403, 'msg': '您无权进行此操作'}) # 获取角色(需要角色名称) role_code = request.data.get('role_code') if not role_code: return Response({'code': 400, 'msg': '缺少角色编码'}) try: role = Role.objects.get(RoleName=role_code) except Role.DoesNotExist: return Response({'code': 404, 'msg': '角色不存在'}) # 超级管理员角色的特殊限制 if role.RoleName == '管理员': if action in ['delete_role']: return Response({'code': 403, 'msg': '超级管理员角色不能删除'}) # 根据 action 处理 if action == 'delete_role': # 删除角色:同时删除角色权限关联、用户角色关联 with transaction.atomic(): RolePermission.objects.filter(RoleUUID=role.RoleUUID).delete() UserRole.objects.filter(RoleUUID=role.RoleUUID).delete() role.delete() return Response({'code': 0, 'msg': '角色删除成功'}) elif action == 'add_permission': perm_code = request.data.get('perm_code') if not perm_code: return Response({'code': 400, 'msg': '缺少权限编码'}) if role.RoleName == '管理员' and perm_code == '000001': return Response({'code': 403, 'msg': '此权限已存在,不能重复添加'}) try: perm = Permission.objects.get(PermCode=perm_code) except Permission.DoesNotExist: return Response({'code': 404, 'msg': '权限不存在'}) # 检查是否已存在 if RolePermission.objects.filter(RoleUUID=role.RoleUUID, PermUUID=perm.PermUUID).exists(): return Response({'code': 400, 'msg': '该角色已拥有此权限'}) RolePermission.objects.create( RolePermUUID=uuid.uuid4().bytes, RoleUUID=role.RoleUUID, PermUUID=perm.PermUUID, CreateTime=timezone.now(), ) return Response({'code': 0, 'msg': '权限添加成功'}) elif action == 'remove_permission': perm_code = request.data.get('perm_code') if not perm_code: return Response({'code': 400, 'msg': '缺少权限编码'}) if role.RoleName == '管理员' and perm_code == '000001': return Response({'code': 403, 'msg': '不能移除超级管理员的此权限'}) try: perm = Permission.objects.get(PermCode=perm_code) except Permission.DoesNotExist: return Response({'code': 404, 'msg': '权限不存在'}) deleted, _ = RolePermission.objects.filter(RoleUUID=role.RoleUUID, PermUUID=perm.PermUUID).delete() if deleted == 0: return Response({'code': 400, 'msg': '该角色未拥有此权限'}) return Response({'code': 0, 'msg': '权限移除成功'}) elif action == 'update_role': role_name = (request.data.get('role_name') or '').strip() description = (request.data.get('description') or '').strip() perm_codes = request.data.get('perm_codes') or [] if role.RoleName == '管理员': role_name = role.RoleName elif role_name and role_name != role.RoleName: if Role.objects.filter(RoleName=role_name).exclude(RoleUUID=role.RoleUUID).exists(): return Response({'code': 400, 'msg': '角色名称已存在'}) with transaction.atomic(): if role.RoleName != '管理员': if role_name: role.RoleName = role_name role.RoleDesc = description role.save(update_fields=['RoleName', 'RoleDesc']) RolePermission.objects.filter(RoleUUID=role.RoleUUID).delete() for pc in perm_codes: if pc == '000001' and role.RoleName != '管理员': continue try: perm = Permission.objects.get(PermCode=pc, PermStatus=1) except Permission.DoesNotExist: continue RolePermission.objects.create( RolePermUUID=uuid.uuid4().bytes, RoleUUID=role.RoleUUID, PermUUID=perm.PermUUID, CreateTime=timezone.now(), ) if role.RoleName == '管理员': try: super_perm = Permission.objects.get(PermCode='000001', PermStatus=1) if not RolePermission.objects.filter( RoleUUID=role.RoleUUID, PermUUID=super_perm.PermUUID, ).exists(): RolePermission.objects.create( RolePermUUID=uuid.uuid4().bytes, RoleUUID=role.RoleUUID, PermUUID=super_perm.PermUUID, CreateTime=timezone.now(), ) except Permission.DoesNotExist: pass return Response({'code': 0, 'msg': '角色保存成功'}) else: return Response({'code': 400, 'msg': '无效的 action'}) class AddRoleView(APIView): """ 添加角色:自动生成角色编码,前端提供角色名称、描述、选择的权限列表 """ permission_classes = [IsAuthenticated] def post(self, request): username = request.data.get('username', '').strip() role_name = request.data.get('role_name', '').strip() description = request.data.get('description', '').strip() perm_codes = request.data.get('perm_codes', []) # 列表 if not username or not role_name: return Response({'code': 400, 'msg': '缺少必要参数'}) # 权限校验 kefu, permissions = verify_kefu_permission(request, username) if kefu is None: return permissions if '000001' not in permissions: return Response({'code': 403, 'msg': '您无权进行此操作'}) # 检查角色名称是否已存在(同俱乐部内唯一) from jituan.services.club_rbac import resolve_role_club_id, role_name_exists target_club_id = resolve_role_club_id( request, (request.data.get('target_club_id') or '').strip() or None, ) if role_name_exists(role_name, target_club_id): return Response({'code': 400, 'msg': '该俱乐部下角色名称已存在'}) # 生成唯一角色编码(格式:ROLE_ + 8位随机字母数字) role_code = f"ROLE_{''.join(random.choices(string.ascii_uppercase + string.digits, k=8))}" # 创建角色 with transaction.atomic(): role = Role.objects.create( RoleUUID=uuid.uuid4().bytes, TenantUUID=b'\x00' * 16, RoleName=role_name, RoleType=2, RoleStatus=1, AssignScope=0, RoleDesc=description, ClubID=target_club_id, CreateTime=timezone.now(), ) # 绑定权限(过滤掉不存在的权限编码) for pc in perm_codes: # 不允许添加 000001 权限(此权限仅供超级管理员) if pc == '000001': continue try: perm = Permission.objects.get(PermCode=pc) RolePermission.objects.create( RolePermUUID=uuid.uuid4().bytes, RoleUUID=role.RoleUUID, PermUUID=perm.PermUUID, CreateTime=timezone.now(), ) except Permission.DoesNotExist: logger.warning(f"添加角色时忽略不存在的权限编码: {pc}") return Response({'code': 0, 'msg': '角色添加成功', 'data': {'role_code': role_code}}) class GetAdminUserListView(APIView): permission_classes = [IsAuthenticated] def post(self, request): try: username = request.data.get('username', '').strip() if not username: return Response({'code': 400, 'msg': '缺少username'}) kefu, permissions = verify_kefu_permission(request, username) if kefu is None: return permissions if '000001' not in permissions: return Response({'code': 403, 'msg': '您无权访问此页面'}) phone = request.data.get('phone', '').strip() nicheng = request.data.get('nicheng', '').strip() role_code = request.data.get('roleCode', '').strip() page = int(request.data.get('page', 1)) page_size = int(request.data.get('pageSize', 20)) # UserType 是 @property 非数据库字段,不能用 filter; # KefuProfile__isnull=False 已确保只查到客服用户 users = User.query.filter( KefuProfile__isnull=False ).select_related('KefuProfile') from jituan.services.club_rbac import filter_kefu_users_qs users = filter_kefu_users_qs(users, request) if phone: users = users.filter(Phone__icontains=phone) if nicheng: users = users.filter(KefuProfile__nicheng__icontains=nicheng) # 关键修正:先求值为列表,再传入 phone__in if role_code: target_role = Role.objects.filter(RoleName=role_code).first() if target_role: user_uuids = list( UserRole.objects.filter(RoleUUID=target_role.RoleUUID) .values_list('UserUUID', flat=True) ) users = users.filter(UserUUID__in=user_uuids) else: users = users.none() users = users.order_by('-UserCreateTime') paginator = Paginator(users, page_size) page_obj = paginator.get_page(page) data_list = [] for user in page_obj: # 通过 gvsdsdk UserRole 获取用户角色 user_role_uuids = list( UserRole.objects.filter(UserUUID=user.UserUUID) .values_list('RoleUUID', flat=True) ) user_roles = Role.objects.filter(RoleUUID__in=user_role_uuids) roles_data = [ {'role_code': r.RoleName, 'role_name': r.RoleName} for r in user_roles ] data_list.append({ 'phone': user.Phone or '', 'yonghuid': user.UserUID or '', 'nicheng': user.KefuProfile.nicheng, 'club_id': getattr(user, 'ClubID', '') or '', 'roles': roles_data, 'status': user.KefuProfile.zhuangtai, 'create_time': user.UserCreateTime.strftime('%Y-%m-%d %H:%M:%S') if getattr(user, 'UserCreateTime', None) else '', 'update_time': user.KefuProfile.UpdateTime.strftime('%Y-%m-%d %H:%M:%S') if getattr(user.KefuProfile, 'UpdateTime', None) else '', 'CreateTime': user.UserCreateTime.strftime('%Y-%m-%d %H:%M:%S') if getattr(user, 'UserCreateTime', None) else '', 'UpdateTime': user.KefuProfile.UpdateTime.strftime('%Y-%m-%d %H:%M:%S') if getattr(user.KefuProfile, 'UpdateTime', None) else '', }) return Response({ 'code': 0, 'data': { 'list': data_list, 'total': paginator.count, 'page': page, 'pageSize': page_size } }) except Exception as e: logger.error(f"GetAdminUserListView 异常: {e}\n{traceback.format_exc()}") return Response({'code': 500, 'msg': f'服务器内部错误: {str(e)}'}) class GetAdminRolesView(APIView): """获取所有角色(用于筛选和分配)""" permission_classes = [IsAuthenticated] def post(self, request): username = request.data.get('username', '').strip() if not username: return Response({'code': 400, 'msg': '缺少username'}) kefu, permissions = verify_kefu_permission(request, username) if kefu is None: return permissions if '000001' not in permissions: return Response({'code': 403, 'msg': '您无权访问此页面'}) from jituan.services.club_rbac import filter_roles_for_request roles = filter_roles_for_request(request).values('RoleName', 'ClubID') return Response({ 'code': 0, 'data': { 'roles': [ { 'role_code': r['RoleName'], 'role_name': r['RoleName'], 'club_id': r.get('ClubID') or '', } for r in roles ] } }) '''class GetAdminUserListView(APIView): """获取后台用户列表(支持分页、筛选)""" permission_classes = [IsAuthenticated] def post(self, request): username = request.data.get('username', '').strip() if not username: return Response({'code': 400, 'msg': '缺少username'}) kefu, permissions = verify_kefu_permission(request, username) if kefu is None: return permissions if '000001' not in permissions: return Response({'code': 403, 'msg': '您无权访问此页面'}) # 筛选条件 phone = request.data.get('phone', '').strip() nicheng = request.data.get('nicheng', '').strip() role_code = request.data.get('roleCode', '').strip() page = int(request.data.get('page', 1)) page_size = int(request.data.get('pageSize', 20)) # 基础查询:存在客服扩展表 users = User.query.filter(KefuProfile__isnull=False).select_related('KefuProfile') if phone: users = users.filter(Phone__icontains=phone) if nicheng: users = users.filter(KefuProfile__nicheng__icontains=nicheng) if role_code: # 筛选拥有该角色的用户 user_ids_with_role = UserRole.query.filter(role__role_code=role_code).values_list('account_id', flat=True) users = users.filter(phone__in=user_ids_with_role) # 排序 users = users.order_by('-CreateTime') # 分页 paginator = Paginator(users, page_size) page_obj = paginator.get_page(page) # 构建返回数据 data_list = [] for user in page_obj: # 获取用户的所有角色 user_roles = UserRole.query.filter(account_id=user.Phone).select_related('role') roles_data = [{'role_code': ur.role.role_code, 'role_name': ur.role.role_name} for ur in user_roles] data_list.append({ 'phone': user.Phone, 'nicheng': user.KefuProfile.nicheng, 'roles': roles_data, 'status': user.KefuProfile.zhuangtai, 'CreateTime': user.UserCreateTime.strftime('%Y-%m-%d %H:%M:%S'), 'UpdateTime': user.UpdateTime.strftime('%Y-%m-%d %H:%M:%S'), }) return Response({ 'code': 0, 'data': { 'list': data_list, 'total': paginator.count, 'page': page, 'pageSize': page_size } })''' class ModifyAdminUserView(APIView): """修改后台用户信息(昵称、密码、二级密码、状态、角色)""" permission_classes = [IsAuthenticated] def post(self, request): username = request.data.get('username', '').strip() action = request.data.get('action') if not username or not action: return Response({'code': 400, 'msg': '缺少参数'}) kefu, permissions = verify_kefu_permission(request, username) if kefu is None: return permissions if '000001' not in permissions: return Response({'code': 403, 'msg': '您无权进行此操作'}) target_yonghuid = request.data.get('yonghuid', '').strip() target_phone = request.data.get('phone', '').strip() if not target_yonghuid and not target_phone: return Response({'code': 400, 'msg': '缺少目标用户(yonghuid 或 phone)'}) from jituan.services.club_rbac import resolve_kefu_admin_user target_user = resolve_kefu_admin_user(yonghuid=target_yonghuid, phone=target_phone) if not target_user: return Response({'code': 404, 'msg': '用户不存在或非后台账号'}) try: target_kefu = target_user.KefuProfile except UserKefu.DoesNotExist: return Response({'code': 404, 'msg': '用户扩展信息缺失'}) with transaction.atomic(): if action == 'update_user_info': # 修改昵称、状态、密码、二级密码 nicheng = request.data.get('nicheng') status = request.data.get('status') password = request.data.get('password') erjimima = request.data.get('erjimima') if nicheng is not None: target_kefu.nicheng = nicheng if status is not None: target_kefu.zhuangtai = int(status) if password: if len(password) < 6: return Response({'code': 400, 'msg': '密码至少6位'}) target_user.SetPassword(password) if erjimima: if len(erjimima) < 6: return Response({'code': 400, 'msg': '二级密码至少6位'}) import bcrypt as _bcrypt target_kefu.erjimima = _bcrypt.hashpw(erjimima.encode('utf-8'), _bcrypt.gensalt(rounds=12)).decode('utf-8') target_user.save() target_kefu.save() return Response({'code': 0, 'msg': '修改成功'}) elif action == 'add_user_roles': role_codes = request.data.get('role_codes', []) if not role_codes: return Response({'code': 400, 'msg': '请选择角色'}) from jituan.services.club_rbac import resolve_role_by_name club_id = getattr(target_user, 'ClubID', '') or '' added, missing = [], [] for rc in role_codes: role = resolve_role_by_name(rc, club_id) if not role: missing.append(rc) continue _, created = UserRole.objects.get_or_create( UserUUID=target_user.UserUUID, RoleUUID=role.RoleUUID, defaults={ 'UserRoleUUID': uuid.uuid4().bytes, 'CompanyUUID': uuid.UUID('b0000000-0000-0000-0000-000000000001').bytes, }, ) if created: added.append(role.RoleName) elif role.RoleName not in added: added.append(role.RoleName) if not added: return Response({ 'code': 400, 'msg': f'未找到可绑定的角色:{", ".join(missing or role_codes)}。请确认顶栏俱乐部与角色所属俱乐部一致', }) if missing: return Response({ 'code': 0, 'msg': f'已绑定:{", ".join(added)};未找到:{", ".join(missing)}', }) return Response({'code': 0, 'msg': '角色添加成功'}) elif action == 'remove_user_role': role_code = request.data.get('role_code') if not role_code: return Response({'code': 400, 'msg': '缺少角色编码'}) from jituan.services.club_rbac import resolve_role_by_name club_id = getattr(target_user, 'ClubID', '') or '' role = resolve_role_by_name(role_code, club_id) if not role: return Response({'code': 404, 'msg': '角色不存在或与用户俱乐部不匹配'}) UserRole.objects.filter(UserUUID=target_user.UserUUID, RoleUUID=role.RoleUUID).delete() return Response({'code': 0, 'msg': '角色移除成功'}) else: return Response({'code': 400, 'msg': '无效的action'}) class AddAdminUserView(APIView): """添加后台用户(客服账号)""" permission_classes = [IsAuthenticated] def post(self, request): username = request.data.get('username', '').strip() if not username: return Response({'code': 400, 'msg': '缺少username'}) kefu, permissions = verify_kefu_permission(request, username) if kefu is None: return permissions if '000001' not in permissions: return Response({'code': 403, 'msg': '您无权进行此操作'}) phone = request.data.get('phone', '').strip() password = request.data.get('password', '').strip() erjimima = request.data.get('erjimima', '').strip() nicheng = request.data.get('nicheng', '').strip() role_codes = request.data.get('role_codes', []) if not all([phone, password, erjimima, nicheng]): return Response({'code': 400, 'msg': '请填写完整信息'}) if len(password) < 6 or len(erjimima) < 6: return Response({'code': 400, 'msg': '密码和二级密码至少6位'}) from jituan.services.club_context import resolve_club_id_from_request from jituan.services.club_rbac import resolve_roles_for_binding target_club_id = resolve_club_id_from_request(request) # 校验手机号是否已被后台客服占用(同俱乐部优先) existing_kefu = User.query.filter( Phone=phone, KefuProfile__isnull=False ).order_by('-UserCreateTime').first() if existing_kefu: return Response({'code': 400, 'msg': '该账号已存在'}) if not isinstance(role_codes, list): return Response({'code': 400, 'msg': 'role_codes 格式错误'}) # 分配角色(默认客服 + 所选角色,去重;任一角色找不到则整单拒绝) role_names_to_bind = [] seen_names = set() for name in (['客服'] if '客服' not in role_codes else []) + list(role_codes): n = (name or '').strip() if n and n not in seen_names: seen_names.add(n) role_names_to_bind.append(n) roles_to_bind, missing_roles = resolve_roles_for_binding(role_names_to_bind, target_club_id) if missing_roles: return Response({ 'code': 400, 'msg': f'角色不存在或与当前俱乐部不匹配:{", ".join(missing_roles)}', }) if not roles_to_bind: return Response({'code': 400, 'msg': '请至少选择一个有效角色'}) with transaction.atomic(): # 事务内二次校验,防止并发重复创建 if User.query.filter(Phone=phone, KefuProfile__isnull=False).exists(): return Response({'code': 400, 'msg': '该账号已存在'}) # 生成唯一的 yonghuid(7位数字) while True: yonghuid = str(random.randint(1000000, 9999999)) if not User.query.filter(UserUID=yonghuid).exists(): break # 生成唯一的 openid(格式:admin_{时间戳}_{随机6位}) timestamp = str(int(time.time() * 1000)) random_suffix = ''.join(random.choices(string.ascii_lowercase + string.digits, k=6)) openid = f"admin_{timestamp}_{random_suffix}" while User.query.filter(OpenID=openid).exists(): random_suffix = ''.join(random.choices(string.ascii_lowercase + string.digits, k=6)) openid = f"admin_{timestamp}_{random_suffix}" user_main = User.query.create( UserUID=yonghuid, UserName=openid, OpenID=openid, Phone=phone, ClubID=target_club_id, ) user_main.SetPassword(password) user_main.save(update_fields=['UserPassword', 'ClubID']) # 创建客服扩展表(后台用户扩展) import bcrypt as _bcrypt erjimima_hashed = _bcrypt.hashpw(erjimima.encode('utf-8'), _bcrypt.gensalt(rounds=12)).decode('utf-8') UserKefu.query.create( user=user_main, nicheng=nicheng, erjimima=erjimima_hashed, zhuangtai=1 ) for role in roles_to_bind: UserRole.objects.get_or_create( UserUUID=user_main.UserUUID, RoleUUID=role.RoleUUID, defaults={ 'UserRoleUUID': uuid.uuid4().bytes, 'CompanyUUID': uuid.UUID('b0000000-0000-0000-0000-000000000001').bytes, }, ) return Response({'code': 0, 'msg': '添加成功'})