修复了管理员无法进后台的问题
This commit is contained in:
957
backend/utils.py
957
backend/utils.py
@@ -1,478 +1,481 @@
|
||||
# houtai/utils.py
|
||||
import logging
|
||||
import json
|
||||
from functools import lru_cache
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db.models import Q
|
||||
from rest_framework.response import Response
|
||||
from .models import AbnormalUserLog, PlayerDailyStats, MerchantDailyStats, \
|
||||
ManagerRenewalDailyStats, ManagerDailyStats, LeaderDailyStats, WithdrawalDailyStats
|
||||
from gvsdsdk.models import UserRole as SdkUserRole, RolePermission as SdkRolePermission, Permission as SdkPermission
|
||||
|
||||
from django.db import transaction
|
||||
from django.db.models import F
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
|
||||
from gvsdsdk.fluent import db, func, FQ
|
||||
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _get_real_ip(request):
|
||||
"""获取真实IP(考虑代理)"""
|
||||
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||
if x_forwarded_for:
|
||||
ip = x_forwarded_for.split(',')[0].strip()
|
||||
return ip, x_forwarded_for
|
||||
else:
|
||||
ip = request.META.get('REMOTE_ADDR')
|
||||
return ip, ''
|
||||
|
||||
|
||||
def _record_abnormal(account_id, request, attempt_type, detail=''):
|
||||
"""记录异常操作(仅用于越权等攻击行为)"""
|
||||
try:
|
||||
real_ip, xff = _get_real_ip(request)
|
||||
headers = {k: v for k, v in request.META.items() if k.startswith('HTTP_')}
|
||||
headers_json = json.dumps(headers, ensure_ascii=False)[:2000]
|
||||
|
||||
request_params = json.dumps(request.query_params.dict(), ensure_ascii=False) if request.query_params else ''
|
||||
request_body = request.body.decode('utf-8', errors='ignore')[:5000]
|
||||
|
||||
AbnormalUserLog.query.create(
|
||||
account_id=account_id,
|
||||
ip_address=real_ip,
|
||||
real_ip=real_ip,
|
||||
x_forwarded_for=xff,
|
||||
user_agent=request.META.get('HTTP_USER_AGENT', ''),
|
||||
request_method=request.method,
|
||||
request_path=request.path,
|
||||
request_params=request_params,
|
||||
request_body=request_body,
|
||||
request_headers=headers_json,
|
||||
attempt_type=attempt_type,
|
||||
detail=detail,
|
||||
)
|
||||
logger.warning(f"记录异常用户: {account_id} IP:{real_ip} 类型:{attempt_type}")
|
||||
except Exception as e:
|
||||
logger.error(f"记录异常日志失败: {e}")
|
||||
|
||||
|
||||
def verify_kefu_permission(request, username_from_frontend=None):
|
||||
"""
|
||||
验证客服身份,并返回该用户的所有权限列表(基于新RBAC表)
|
||||
只有前端传递的username与当前登录用户不匹配时,才记录异常并警告前端。
|
||||
|
||||
参数:
|
||||
request: DRF request 对象
|
||||
username_from_frontend: 前端传递的账号(用于防越权)
|
||||
|
||||
返回:
|
||||
(kefu_obj, permissions_list) # 验证通过
|
||||
(None, Response) # 验证失败,直接返回Response
|
||||
"""
|
||||
current_user = request.user
|
||||
|
||||
# ---------- 1. 必须是客服 ----------
|
||||
if current_user.user_type != 'kefu':
|
||||
return None, Response({'code': 403, 'msg': '身份错误,非客服账号'}, status=403)
|
||||
|
||||
# ---------- 2. 客服扩展表存在且状态正常 ----------
|
||||
try:
|
||||
kefu = current_user.kefu_profile
|
||||
if kefu.zhuangtai != 1:
|
||||
return None, Response({'code': 403, 'msg': '客服账号已被禁用'}, status=403)
|
||||
except ObjectDoesNotExist:
|
||||
return None, Response({'code': 403, 'msg': '客服账号不存在'}, status=403)
|
||||
|
||||
# ---------- 3. 越权检测(只记录前端篡改username的情况) ----------
|
||||
if username_from_frontend and current_user.phone != username_from_frontend:
|
||||
detail = f'前端username: {username_from_frontend},实际登录账号: {current_user.phone}'
|
||||
_record_abnormal(current_user.phone, request, '越权尝试篡改username', detail=detail)
|
||||
return None, Response({
|
||||
'code': 403,
|
||||
'msg': '身份错误,无权操作其他账号,相关操作已记录'
|
||||
}, status=403)
|
||||
|
||||
# ---------- 4. 获取用户的所有权限 ----------
|
||||
# 使用 gvsdsdk RBAC 表(UserRole → RolePermission → Permission)
|
||||
try:
|
||||
user_uuid = current_user.UserUUID
|
||||
role_uuids = list(SdkUserRole.objects.filter(
|
||||
UserUUID=user_uuid
|
||||
).values_list('RoleUUID', flat=True))
|
||||
|
||||
if role_uuids:
|
||||
perm_uuids = list(SdkRolePermission.objects.filter(
|
||||
RoleUUID__in=role_uuids
|
||||
).values_list('PermUUID', flat=True))
|
||||
|
||||
permissions = list(SdkPermission.objects.filter(
|
||||
PermUUID__in=perm_uuids,
|
||||
PermStatus=1
|
||||
).values_list('PermCode', flat=True).distinct())
|
||||
else:
|
||||
permissions = []
|
||||
except Exception:
|
||||
permissions = []
|
||||
|
||||
# 超级用户自动拥有所有权限
|
||||
if current_user.IsSuperuser and '000001' not in permissions:
|
||||
permissions.insert(0, '000001')
|
||||
|
||||
if not permissions:
|
||||
logger.warning(f"用户 {current_user.phone} 没有任何权限,请检查角色分配")
|
||||
|
||||
return kefu, permissions
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def update_dashou_daily_by_action(yonghuid, amount, action):
|
||||
"""
|
||||
根据行为类型更新打手每日统计(接单、成交、退款)
|
||||
|
||||
参数:
|
||||
yonghuid: 打手用户ID
|
||||
amount: 本单涉及的金额(Decimal)
|
||||
action: 1 = 接单, 2 = 成交(结算), 3 = 退款
|
||||
"""
|
||||
amount = Decimal(str(amount)) if amount else Decimal('0.00')
|
||||
if amount <= 0:
|
||||
return # 金额非正不统计
|
||||
|
||||
today = date.today()
|
||||
|
||||
with transaction.atomic():
|
||||
stat, created = PlayerDailyStats.objects.select_for_update().get_or_create(
|
||||
PlayerID=yonghuid,
|
||||
Date=today,
|
||||
defaults={
|
||||
'PlayerID': yonghuid,
|
||||
'Date': today,
|
||||
'AcceptedOrderTotal': 0,
|
||||
'AcceptedAmount': Decimal('0.00'),
|
||||
'CompletedOrderTotal': 0,
|
||||
'CompletedAmount': Decimal('0.00'),
|
||||
'RefundCount': 0,
|
||||
'RefundAmount': Decimal('0.00'),
|
||||
}
|
||||
)
|
||||
|
||||
update_fields = {}
|
||||
if action == 1: # 接单
|
||||
update_fields['AcceptedOrderTotal'] = F('AcceptedOrderTotal') + 1
|
||||
update_fields['AcceptedAmount'] = F('AcceptedAmount') + amount
|
||||
elif action == 2: # 成交
|
||||
update_fields['CompletedOrderTotal'] = F('CompletedOrderTotal') + 1
|
||||
update_fields['CompletedAmount'] = F('CompletedAmount') + amount
|
||||
elif action == 3: # 退款
|
||||
update_fields['RefundCount'] = F('RefundCount') + 1
|
||||
update_fields['RefundAmount'] = F('RefundAmount') + amount
|
||||
else:
|
||||
return # 无效行为
|
||||
|
||||
if update_fields:
|
||||
PlayerDailyStats.query.filter(id=stat.id).update(**update_fields)
|
||||
|
||||
|
||||
def update_shangjia_daily(yonghuid, amount, action):
|
||||
"""
|
||||
根据操作行为更新商家每日统计(派发、结算、退款)
|
||||
|
||||
参数:
|
||||
yonghuid: 商家用户ID
|
||||
amount: 当前订单涉及的金额(Decimal)
|
||||
action: 操作类型,1 = 派发,2 = 结算(成交),3 = 退款
|
||||
|
||||
说明:
|
||||
- 金额必须大于0,否则不执行任何操作
|
||||
- 使用 select_for_update + F() 表达式保证原子性和并发安全
|
||||
- 每天每个商家只会有一条统计记录,不存在则自动创建
|
||||
"""
|
||||
amount = Decimal(str(amount)) if amount else Decimal('0.00')
|
||||
if amount <= 0:
|
||||
return # 金额非正,不统计
|
||||
|
||||
today = date.today()
|
||||
|
||||
with transaction.atomic():
|
||||
# 获取或创建当天统计记录,同时加锁防止并发
|
||||
stat, created = MerchantDailyStats.objects.select_for_update().get_or_create(
|
||||
MerchantID=yonghuid,
|
||||
Date=today,
|
||||
defaults={
|
||||
'MerchantID': yonghuid,
|
||||
'Date': today,
|
||||
'AssignedOrderCount': 0,
|
||||
'AssignedAmount': Decimal('0.00'),
|
||||
'SettledOrderCount': 0,
|
||||
'SettledAmount': Decimal('0.00'),
|
||||
'RefundOrderCount': 0,
|
||||
'RefundAmount': Decimal('0.00'),
|
||||
}
|
||||
)
|
||||
|
||||
# 构建本次更新的字段,使用 F 表达式进行原子累加
|
||||
update_fields = {}
|
||||
if action == 1: # 派发
|
||||
update_fields['AssignedOrderCount'] = F('AssignedOrderCount') + 1
|
||||
update_fields['AssignedAmount'] = F('AssignedAmount') + amount
|
||||
elif action == 2: # 结算(成交)
|
||||
update_fields['SettledOrderCount'] = F('SettledOrderCount') + 1
|
||||
update_fields['SettledAmount'] = F('SettledAmount') + amount
|
||||
elif action == 3: # 退款
|
||||
update_fields['RefundOrderCount'] = F('RefundOrderCount') + 1
|
||||
update_fields['RefundAmount'] = F('RefundAmount') + amount
|
||||
else:
|
||||
# 无效的行为类型,直接返回
|
||||
return
|
||||
|
||||
# 执行原子更新
|
||||
MerchantDailyStats.query.filter(id=stat.id).update(**update_fields)
|
||||
|
||||
|
||||
|
||||
def update_guanshi_daily_by_action(yonghuid, action, amount=Decimal('0.00')):
|
||||
"""
|
||||
根据操作行为更新管事每日统计(邀请打手、充值会员、订单/押金分红)
|
||||
action: 1 = 邀请打手, 2 = 充值会员, 3 = 商家订单分红, 4 = 押金分红
|
||||
"""
|
||||
today = date.today()
|
||||
|
||||
with transaction.atomic():
|
||||
stat, created = ManagerDailyStats.objects.select_for_update().get_or_create(
|
||||
ManagerID=yonghuid,
|
||||
Date=today,
|
||||
defaults={
|
||||
'ManagerID': yonghuid,
|
||||
'Date': today,
|
||||
'InvitedPlayerCount': 0,
|
||||
'RechargedPlayerCount': 0,
|
||||
'TotalIncome': Decimal('0.00'),
|
||||
}
|
||||
)
|
||||
|
||||
if action == 1:
|
||||
# 邀请打手:无论新创建还是已存在,直接 +1
|
||||
if created:
|
||||
stat.InvitedPlayerCount = 1
|
||||
stat.save()
|
||||
else:
|
||||
ManagerDailyStats.query.filter(id=stat.id).update(
|
||||
InvitedPlayerCount=F('InvitedPlayerCount') + 1
|
||||
)
|
||||
|
||||
elif action == 2:
|
||||
amount = Decimal(str(amount)) if amount else Decimal('0.00')
|
||||
if amount <= 0:
|
||||
return
|
||||
if created:
|
||||
stat.RechargedPlayerCount = 1
|
||||
stat.TotalIncome = amount
|
||||
stat.save()
|
||||
else:
|
||||
ManagerDailyStats.query.filter(id=stat.id).update(
|
||||
RechargedPlayerCount=F('RechargedPlayerCount') + 1,
|
||||
TotalIncome=F('TotalIncome') + amount
|
||||
)
|
||||
|
||||
elif action in (3, 4):
|
||||
amount = Decimal(str(amount)) if amount else Decimal('0.00')
|
||||
if amount <= 0:
|
||||
return
|
||||
if created:
|
||||
stat.TotalIncome = amount
|
||||
stat.save()
|
||||
else:
|
||||
ManagerDailyStats.query.filter(id=stat.id).update(
|
||||
TotalIncome=F('TotalIncome') + amount
|
||||
)
|
||||
|
||||
|
||||
def update_guanshi_xufei_daily(yonghuid, xufei_jine=Decimal('0.00')):
|
||||
"""
|
||||
管事续费统计(单独表)
|
||||
用法: update_guanshi_xufei_daily('300001', Decimal('30'))
|
||||
"""
|
||||
today = date.today()
|
||||
with transaction.atomic():
|
||||
stat, created = ManagerRenewalDailyStats.objects.select_for_update().get_or_create(
|
||||
ManagerID=yonghuid,
|
||||
Date=today,
|
||||
defaults={
|
||||
'ManagerID': yonghuid,
|
||||
'Date': today,
|
||||
'RenewalTotal': 1,
|
||||
'RenewalRevenue': xufei_jine,
|
||||
}
|
||||
)
|
||||
if not created:
|
||||
ManagerRenewalDailyStats.query.filter(id=stat.id).update(
|
||||
RenewalTotal=F('RenewalTotal') + 1,
|
||||
RenewalRevenue=F('RenewalRevenue') + xufei_jine
|
||||
)
|
||||
|
||||
|
||||
def update_zuzhang_daily_by_action(yonghuid, action, amount=Decimal('0.00')):
|
||||
"""
|
||||
根据操作行为更新组长每日统计(邀请管事、分佣收入)
|
||||
|
||||
参数:
|
||||
yonghuid: 组长用户ID
|
||||
action: 操作类型
|
||||
1 = 邀请管事(次数+1,无金额)
|
||||
2 = 分佣收入(累加金额)
|
||||
amount: 分佣金额(Decimal),仅在 action=2 时有效
|
||||
"""
|
||||
today = date.today()
|
||||
|
||||
with transaction.atomic():
|
||||
stat, created = LeaderDailyStats.objects.select_for_update().get_or_create(
|
||||
LeaderID=yonghuid,
|
||||
Date=today,
|
||||
defaults={
|
||||
'LeaderID': yonghuid,
|
||||
'Date': today,
|
||||
'InvitedManagerCount': 0,
|
||||
'TotalIncome': Decimal('0.00'),
|
||||
'CommissionAmount': Decimal('0.00'),
|
||||
}
|
||||
)
|
||||
|
||||
if created:
|
||||
# 新记录直接设置初始值
|
||||
if action == 1:
|
||||
stat.InvitedManagerCount = 1
|
||||
elif action == 2:
|
||||
amount = Decimal(str(amount)) if amount else Decimal('0.00')
|
||||
stat.TotalIncome = amount
|
||||
stat.CommissionAmount = amount
|
||||
stat.save()
|
||||
else:
|
||||
# 已存在记录,使用 F 表达式原子累加
|
||||
if action == 1:
|
||||
LeaderDailyStats.query.filter(id=stat.id).update(
|
||||
InvitedManagerCount=F('InvitedManagerCount') + 1
|
||||
)
|
||||
elif action == 2:
|
||||
amount = Decimal(str(amount)) if amount else Decimal('0.00')
|
||||
if amount > 0:
|
||||
LeaderDailyStats.query.filter(id=stat.id).update(
|
||||
TotalIncome=F('TotalIncome') + amount,
|
||||
CommissionAmount=F('CommissionAmount') + amount
|
||||
)
|
||||
|
||||
|
||||
|
||||
def update_tixian_daily_stat(leixing, amount):
|
||||
"""
|
||||
更新每日提现统计(平台维度)
|
||||
leixing: 1=打手, 2=管事, 3=组长
|
||||
amount: 本次提现金额(申请金额,含手续费)
|
||||
"""
|
||||
today = date.today()
|
||||
with transaction.atomic():
|
||||
stat, created = WithdrawalDailyStats.objects.select_for_update().get_or_create(
|
||||
Date=today,
|
||||
WithdrawalType=leixing,
|
||||
defaults={'total_amount': amount}
|
||||
)
|
||||
if not created:
|
||||
WithdrawalDailyStats.query.filter(id=stat.id).update(
|
||||
total_amount=F('total_amount') + amount
|
||||
)
|
||||
|
||||
|
||||
# 罚款权限(与 permission 表一致)
|
||||
# 66693a/b/c + 66694c:按身份管理罚款;99933abs:罚款申请(通用,可查看列表并操作各身份)
|
||||
_DEFAULT_FADAN_PERM_TO_SHENFEN = {
|
||||
'66693a': 1, # 罚款管理-打手
|
||||
'66693c': 2, # 罚款管理-管事
|
||||
'66693b': 3, # 罚款管理-商家
|
||||
'66694c': 4, # 罚款管理-组长
|
||||
}
|
||||
|
||||
_FADAN_GENERIC_PERMS = (
|
||||
'99933abs', # 罚款申请权限
|
||||
)
|
||||
|
||||
_SHENFEN_KEYWORDS = {
|
||||
'打手': 1,
|
||||
'管事': 2,
|
||||
'商家': 3,
|
||||
'组长': 4,
|
||||
}
|
||||
|
||||
SHENFEN_PROFILE_MAP = {
|
||||
1: 'dashou_profile',
|
||||
2: 'guanshi_profile',
|
||||
3: 'shop_profile',
|
||||
4: 'zuzhang_profile',
|
||||
}
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def _get_fadan_permission_config():
|
||||
"""
|
||||
加载罚款相关权限码(硬编码 + permission 表按 perm_name 补充)。
|
||||
仅匹配 perm_name 含「罚款/罚单」,避免 qtczcaiwu 等描述里带「罚款」的财务权限误入。
|
||||
"""
|
||||
perm_map = dict(_DEFAULT_FADAN_PERM_TO_SHENFEN)
|
||||
generic_codes = list(_FADAN_GENERIC_PERMS)
|
||||
try:
|
||||
rows = Permission.query.filter(
|
||||
Q(perm_name__icontains='罚款') | Q(perm_name__icontains='罚单')
|
||||
).values('perm_code', 'perm_name')
|
||||
for row in rows:
|
||||
code = row['perm_code']
|
||||
name = row['perm_name'] or ''
|
||||
matched_sf = None
|
||||
for kw, sf in _SHENFEN_KEYWORDS.items():
|
||||
if kw in name:
|
||||
matched_sf = sf
|
||||
break
|
||||
if matched_sf is not None:
|
||||
perm_map[code] = matched_sf
|
||||
elif code not in generic_codes:
|
||||
generic_codes.append(code)
|
||||
except Exception as e:
|
||||
logger.warning(f"从 permission 表加载罚款权限失败,使用硬编码映射: {e}")
|
||||
return perm_map, tuple(generic_codes)
|
||||
|
||||
|
||||
# 兼容旧引用
|
||||
PERMISSION_TO_SHENFEN = _DEFAULT_FADAN_PERM_TO_SHENFEN
|
||||
|
||||
|
||||
def has_fadan_view_permission(permissions, account_id=''):
|
||||
"""列表/统计:拥有任一罚款权限或超级管理员权限即可查看。"""
|
||||
if '000001' in permissions:
|
||||
return True
|
||||
perm_map, generic_codes = _get_fadan_permission_config()
|
||||
all_codes = set(perm_map.keys()) | set(generic_codes)
|
||||
if any(p in permissions for p in all_codes):
|
||||
return True
|
||||
logger.warning(
|
||||
f"罚款查看权限不足 account={account_id} "
|
||||
f"user_perms={permissions} need_any={sorted(all_codes)}"
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
def check_fadan_permission(permissions, shenfen):
|
||||
"""创建/处理:需拥有对应身份的罚款权限,或通用罚款权限,或超级管理员权限。"""
|
||||
if '000001' in permissions:
|
||||
return True
|
||||
if any(p in permissions for p in _get_fadan_permission_config()[1]):
|
||||
return True
|
||||
shenfen = int(shenfen)
|
||||
perm_map, _ = _get_fadan_permission_config()
|
||||
for perm, sf in perm_map.items():
|
||||
if sf == shenfen and perm in permissions:
|
||||
return True
|
||||
# houtai/utils.py
|
||||
import logging
|
||||
import json
|
||||
from functools import lru_cache
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db.models import Q
|
||||
from rest_framework.response import Response
|
||||
from .models import AbnormalUserLog, PlayerDailyStats, MerchantDailyStats, \
|
||||
ManagerRenewalDailyStats, ManagerDailyStats, LeaderDailyStats, WithdrawalDailyStats
|
||||
from gvsdsdk.models import UserRole as SdkUserRole, RolePermission as SdkRolePermission, Permission as SdkPermission
|
||||
|
||||
from django.db import transaction
|
||||
from django.db.models import F
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
|
||||
from gvsdsdk.fluent import db, func, FQ
|
||||
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _get_real_ip(request):
|
||||
"""获取真实IP(考虑代理)"""
|
||||
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||
if x_forwarded_for:
|
||||
ip = x_forwarded_for.split(',')[0].strip()
|
||||
return ip, x_forwarded_for
|
||||
else:
|
||||
ip = request.META.get('REMOTE_ADDR')
|
||||
return ip, ''
|
||||
|
||||
|
||||
def _record_abnormal(account_id, request, attempt_type, detail=''):
|
||||
"""记录异常操作(仅用于越权等攻击行为)"""
|
||||
try:
|
||||
real_ip, xff = _get_real_ip(request)
|
||||
headers = {k: v for k, v in request.META.items() if k.startswith('HTTP_')}
|
||||
headers_json = json.dumps(headers, ensure_ascii=False)[:2000]
|
||||
|
||||
request_params = json.dumps(request.query_params.dict(), ensure_ascii=False) if request.query_params else ''
|
||||
request_body = request.body.decode('utf-8', errors='ignore')[:5000]
|
||||
|
||||
AbnormalUserLog.query.create(
|
||||
account_id=account_id,
|
||||
ip_address=real_ip,
|
||||
real_ip=real_ip,
|
||||
x_forwarded_for=xff,
|
||||
user_agent=request.META.get('HTTP_USER_AGENT', ''),
|
||||
request_method=request.method,
|
||||
request_path=request.path,
|
||||
request_params=request_params,
|
||||
request_body=request_body,
|
||||
request_headers=headers_json,
|
||||
attempt_type=attempt_type,
|
||||
detail=detail,
|
||||
)
|
||||
logger.warning(f"记录异常用户: {account_id} IP:{real_ip} 类型:{attempt_type}")
|
||||
except Exception as e:
|
||||
logger.error(f"记录异常日志失败: {e}")
|
||||
|
||||
|
||||
def verify_kefu_permission(request, username_from_frontend=None):
|
||||
"""
|
||||
验证客服/管理员身份,并返回该用户的所有权限列表(基于新RBAC表)
|
||||
只有前端传递的username与当前登录用户不匹配时,才记录异常并警告前端。
|
||||
|
||||
参数:
|
||||
request: DRF request 对象
|
||||
username_from_frontend: 前端传递的账号(用于防越权)
|
||||
|
||||
返回:
|
||||
(kefu_obj, permissions_list) # 验证通过
|
||||
(None, Response) # 验证失败,直接返回Response
|
||||
"""
|
||||
current_user = request.user
|
||||
|
||||
# ---------- 1. 必须是客服或管理员 ----------
|
||||
is_admin = current_user.UserType == 'admin' or current_user.IsSuperuser
|
||||
if current_user.UserType != 'kefu' and not is_admin:
|
||||
return None, Response({'code': 403, 'msg': '身份错误,非客服账号'}, status=403)
|
||||
|
||||
# ---------- 2. 客服扩展表存在且状态正常(管理员跳过) ----------
|
||||
kefu = None
|
||||
if not is_admin:
|
||||
try:
|
||||
kefu = current_user.KefuProfile
|
||||
if kefu.zhuangtai != 1:
|
||||
return None, Response({'code': 403, 'msg': '客服账号已被禁用'}, status=403)
|
||||
except ObjectDoesNotExist:
|
||||
return None, Response({'code': 403, 'msg': '客服账号不存在'}, status=403)
|
||||
|
||||
# ---------- 3. 越权检测(只记录前端篡改username的情况) ----------
|
||||
if username_from_frontend and current_user.Phone != username_from_frontend:
|
||||
detail = f'前端username: {username_from_frontend},实际登录账号: {current_user.Phone}'
|
||||
_record_abnormal(current_user.Phone, request, '越权尝试篡改username', detail=detail)
|
||||
return None, Response({
|
||||
'code': 403,
|
||||
'msg': '身份错误,无权操作其他账号,相关操作已记录'
|
||||
}, status=403)
|
||||
|
||||
# ---------- 4. 获取用户的所有权限 ----------
|
||||
# 使用 gvsdsdk RBAC 表(UserRole → RolePermission → Permission)
|
||||
try:
|
||||
user_uuid = current_user.UserUUID
|
||||
role_uuids = list(SdkUserRole.objects.filter(
|
||||
UserUUID=user_uuid
|
||||
).values_list('RoleUUID', flat=True))
|
||||
|
||||
if role_uuids:
|
||||
perm_uuids = list(SdkRolePermission.objects.filter(
|
||||
RoleUUID__in=role_uuids
|
||||
).values_list('PermUUID', flat=True))
|
||||
|
||||
permissions = list(SdkPermission.objects.filter(
|
||||
PermUUID__in=perm_uuids,
|
||||
PermStatus=1
|
||||
).values_list('PermCode', flat=True).distinct())
|
||||
else:
|
||||
permissions = []
|
||||
except Exception:
|
||||
permissions = []
|
||||
|
||||
# 超级用户自动拥有所有权限
|
||||
if current_user.IsSuperuser and '000001' not in permissions:
|
||||
permissions.insert(0, '000001')
|
||||
|
||||
if not permissions:
|
||||
logger.warning(f"用户 {current_user.Phone} 没有任何权限,请检查角色分配")
|
||||
|
||||
return kefu, permissions
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def update_dashou_daily_by_action(yonghuid, amount, action):
|
||||
"""
|
||||
根据行为类型更新打手每日统计(接单、成交、退款)
|
||||
|
||||
参数:
|
||||
yonghuid: 打手用户ID
|
||||
amount: 本单涉及的金额(Decimal)
|
||||
action: 1 = 接单, 2 = 成交(结算), 3 = 退款
|
||||
"""
|
||||
amount = Decimal(str(amount)) if amount else Decimal('0.00')
|
||||
if amount <= 0:
|
||||
return # 金额非正不统计
|
||||
|
||||
today = date.today()
|
||||
|
||||
with transaction.atomic():
|
||||
stat, created = PlayerDailyStats.objects.select_for_update().get_or_create(
|
||||
PlayerID=yonghuid,
|
||||
Date=today,
|
||||
defaults={
|
||||
'PlayerID': yonghuid,
|
||||
'Date': today,
|
||||
'AcceptedOrderTotal': 0,
|
||||
'AcceptedAmount': Decimal('0.00'),
|
||||
'CompletedOrderTotal': 0,
|
||||
'CompletedAmount': Decimal('0.00'),
|
||||
'RefundCount': 0,
|
||||
'RefundAmount': Decimal('0.00'),
|
||||
}
|
||||
)
|
||||
|
||||
update_fields = {}
|
||||
if action == 1: # 接单
|
||||
update_fields['AcceptedOrderTotal'] = F('AcceptedOrderTotal') + 1
|
||||
update_fields['AcceptedAmount'] = F('AcceptedAmount') + amount
|
||||
elif action == 2: # 成交
|
||||
update_fields['CompletedOrderTotal'] = F('CompletedOrderTotal') + 1
|
||||
update_fields['CompletedAmount'] = F('CompletedAmount') + amount
|
||||
elif action == 3: # 退款
|
||||
update_fields['RefundCount'] = F('RefundCount') + 1
|
||||
update_fields['RefundAmount'] = F('RefundAmount') + amount
|
||||
else:
|
||||
return # 无效行为
|
||||
|
||||
if update_fields:
|
||||
PlayerDailyStats.query.filter(id=stat.id).update(**update_fields)
|
||||
|
||||
|
||||
def update_shangjia_daily(yonghuid, amount, action):
|
||||
"""
|
||||
根据操作行为更新商家每日统计(派发、结算、退款)
|
||||
|
||||
参数:
|
||||
yonghuid: 商家用户ID
|
||||
amount: 当前订单涉及的金额(Decimal)
|
||||
action: 操作类型,1 = 派发,2 = 结算(成交),3 = 退款
|
||||
|
||||
说明:
|
||||
- 金额必须大于0,否则不执行任何操作
|
||||
- 使用 select_for_update + F() 表达式保证原子性和并发安全
|
||||
- 每天每个商家只会有一条统计记录,不存在则自动创建
|
||||
"""
|
||||
amount = Decimal(str(amount)) if amount else Decimal('0.00')
|
||||
if amount <= 0:
|
||||
return # 金额非正,不统计
|
||||
|
||||
today = date.today()
|
||||
|
||||
with transaction.atomic():
|
||||
# 获取或创建当天统计记录,同时加锁防止并发
|
||||
stat, created = MerchantDailyStats.objects.select_for_update().get_or_create(
|
||||
MerchantID=yonghuid,
|
||||
Date=today,
|
||||
defaults={
|
||||
'MerchantID': yonghuid,
|
||||
'Date': today,
|
||||
'AssignedOrderCount': 0,
|
||||
'AssignedAmount': Decimal('0.00'),
|
||||
'SettledOrderCount': 0,
|
||||
'SettledAmount': Decimal('0.00'),
|
||||
'RefundOrderCount': 0,
|
||||
'RefundAmount': Decimal('0.00'),
|
||||
}
|
||||
)
|
||||
|
||||
# 构建本次更新的字段,使用 F 表达式进行原子累加
|
||||
update_fields = {}
|
||||
if action == 1: # 派发
|
||||
update_fields['AssignedOrderCount'] = F('AssignedOrderCount') + 1
|
||||
update_fields['AssignedAmount'] = F('AssignedAmount') + amount
|
||||
elif action == 2: # 结算(成交)
|
||||
update_fields['SettledOrderCount'] = F('SettledOrderCount') + 1
|
||||
update_fields['SettledAmount'] = F('SettledAmount') + amount
|
||||
elif action == 3: # 退款
|
||||
update_fields['RefundOrderCount'] = F('RefundOrderCount') + 1
|
||||
update_fields['RefundAmount'] = F('RefundAmount') + amount
|
||||
else:
|
||||
# 无效的行为类型,直接返回
|
||||
return
|
||||
|
||||
# 执行原子更新
|
||||
MerchantDailyStats.query.filter(id=stat.id).update(**update_fields)
|
||||
|
||||
|
||||
|
||||
def update_guanshi_daily_by_action(yonghuid, action, amount=Decimal('0.00')):
|
||||
"""
|
||||
根据操作行为更新管事每日统计(邀请打手、充值会员、订单/押金分红)
|
||||
action: 1 = 邀请打手, 2 = 充值会员, 3 = 商家订单分红, 4 = 押金分红
|
||||
"""
|
||||
today = date.today()
|
||||
|
||||
with transaction.atomic():
|
||||
stat, created = ManagerDailyStats.objects.select_for_update().get_or_create(
|
||||
ManagerID=yonghuid,
|
||||
Date=today,
|
||||
defaults={
|
||||
'ManagerID': yonghuid,
|
||||
'Date': today,
|
||||
'InvitedPlayerCount': 0,
|
||||
'RechargedPlayerCount': 0,
|
||||
'TotalIncome': Decimal('0.00'),
|
||||
}
|
||||
)
|
||||
|
||||
if action == 1:
|
||||
# 邀请打手:无论新创建还是已存在,直接 +1
|
||||
if created:
|
||||
stat.InvitedPlayerCount = 1
|
||||
stat.save()
|
||||
else:
|
||||
ManagerDailyStats.query.filter(id=stat.id).update(
|
||||
InvitedPlayerCount=F('InvitedPlayerCount') + 1
|
||||
)
|
||||
|
||||
elif action == 2:
|
||||
amount = Decimal(str(amount)) if amount else Decimal('0.00')
|
||||
if amount <= 0:
|
||||
return
|
||||
if created:
|
||||
stat.RechargedPlayerCount = 1
|
||||
stat.TotalIncome = amount
|
||||
stat.save()
|
||||
else:
|
||||
ManagerDailyStats.query.filter(id=stat.id).update(
|
||||
RechargedPlayerCount=F('RechargedPlayerCount') + 1,
|
||||
TotalIncome=F('TotalIncome') + amount
|
||||
)
|
||||
|
||||
elif action in (3, 4):
|
||||
amount = Decimal(str(amount)) if amount else Decimal('0.00')
|
||||
if amount <= 0:
|
||||
return
|
||||
if created:
|
||||
stat.TotalIncome = amount
|
||||
stat.save()
|
||||
else:
|
||||
ManagerDailyStats.query.filter(id=stat.id).update(
|
||||
TotalIncome=F('TotalIncome') + amount
|
||||
)
|
||||
|
||||
|
||||
def update_guanshi_xufei_daily(yonghuid, xufei_jine=Decimal('0.00')):
|
||||
"""
|
||||
管事续费统计(单独表)
|
||||
用法: update_guanshi_xufei_daily('300001', Decimal('30'))
|
||||
"""
|
||||
today = date.today()
|
||||
with transaction.atomic():
|
||||
stat, created = ManagerRenewalDailyStats.objects.select_for_update().get_or_create(
|
||||
ManagerID=yonghuid,
|
||||
Date=today,
|
||||
defaults={
|
||||
'ManagerID': yonghuid,
|
||||
'Date': today,
|
||||
'RenewalTotal': 1,
|
||||
'RenewalRevenue': xufei_jine,
|
||||
}
|
||||
)
|
||||
if not created:
|
||||
ManagerRenewalDailyStats.query.filter(id=stat.id).update(
|
||||
RenewalTotal=F('RenewalTotal') + 1,
|
||||
RenewalRevenue=F('RenewalRevenue') + xufei_jine
|
||||
)
|
||||
|
||||
|
||||
def update_zuzhang_daily_by_action(yonghuid, action, amount=Decimal('0.00')):
|
||||
"""
|
||||
根据操作行为更新组长每日统计(邀请管事、分佣收入)
|
||||
|
||||
参数:
|
||||
yonghuid: 组长用户ID
|
||||
action: 操作类型
|
||||
1 = 邀请管事(次数+1,无金额)
|
||||
2 = 分佣收入(累加金额)
|
||||
amount: 分佣金额(Decimal),仅在 action=2 时有效
|
||||
"""
|
||||
today = date.today()
|
||||
|
||||
with transaction.atomic():
|
||||
stat, created = LeaderDailyStats.objects.select_for_update().get_or_create(
|
||||
LeaderID=yonghuid,
|
||||
Date=today,
|
||||
defaults={
|
||||
'LeaderID': yonghuid,
|
||||
'Date': today,
|
||||
'InvitedManagerCount': 0,
|
||||
'TotalIncome': Decimal('0.00'),
|
||||
'CommissionAmount': Decimal('0.00'),
|
||||
}
|
||||
)
|
||||
|
||||
if created:
|
||||
# 新记录直接设置初始值
|
||||
if action == 1:
|
||||
stat.InvitedManagerCount = 1
|
||||
elif action == 2:
|
||||
amount = Decimal(str(amount)) if amount else Decimal('0.00')
|
||||
stat.TotalIncome = amount
|
||||
stat.CommissionAmount = amount
|
||||
stat.save()
|
||||
else:
|
||||
# 已存在记录,使用 F 表达式原子累加
|
||||
if action == 1:
|
||||
LeaderDailyStats.query.filter(id=stat.id).update(
|
||||
InvitedManagerCount=F('InvitedManagerCount') + 1
|
||||
)
|
||||
elif action == 2:
|
||||
amount = Decimal(str(amount)) if amount else Decimal('0.00')
|
||||
if amount > 0:
|
||||
LeaderDailyStats.query.filter(id=stat.id).update(
|
||||
TotalIncome=F('TotalIncome') + amount,
|
||||
CommissionAmount=F('CommissionAmount') + amount
|
||||
)
|
||||
|
||||
|
||||
|
||||
def update_tixian_daily_stat(leixing, amount):
|
||||
"""
|
||||
更新每日提现统计(平台维度)
|
||||
leixing: 1=打手, 2=管事, 3=组长
|
||||
amount: 本次提现金额(申请金额,含手续费)
|
||||
"""
|
||||
today = date.today()
|
||||
with transaction.atomic():
|
||||
stat, created = WithdrawalDailyStats.objects.select_for_update().get_or_create(
|
||||
Date=today,
|
||||
WithdrawalType=leixing,
|
||||
defaults={'total_amount': amount}
|
||||
)
|
||||
if not created:
|
||||
WithdrawalDailyStats.query.filter(id=stat.id).update(
|
||||
total_amount=F('total_amount') + amount
|
||||
)
|
||||
|
||||
|
||||
# 罚款权限(与 permission 表一致)
|
||||
# 66693a/b/c + 66694c:按身份管理罚款;99933abs:罚款申请(通用,可查看列表并操作各身份)
|
||||
_DEFAULT_FADAN_PERM_TO_SHENFEN = {
|
||||
'66693a': 1, # 罚款管理-打手
|
||||
'66693c': 2, # 罚款管理-管事
|
||||
'66693b': 3, # 罚款管理-商家
|
||||
'66694c': 4, # 罚款管理-组长
|
||||
}
|
||||
|
||||
_FADAN_GENERIC_PERMS = (
|
||||
'99933abs', # 罚款申请权限
|
||||
)
|
||||
|
||||
_SHENFEN_KEYWORDS = {
|
||||
'打手': 1,
|
||||
'管事': 2,
|
||||
'商家': 3,
|
||||
'组长': 4,
|
||||
}
|
||||
|
||||
SHENFEN_PROFILE_MAP = {
|
||||
1: 'DashouProfile',
|
||||
2: 'GuanshiProfile',
|
||||
3: 'ShopProfile',
|
||||
4: 'ZuzhangProfile',
|
||||
}
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def _get_fadan_permission_config():
|
||||
"""
|
||||
加载罚款相关权限码(硬编码 + permission 表按 perm_name 补充)。
|
||||
仅匹配 perm_name 含「罚款/罚单」,避免 qtczcaiwu 等描述里带「罚款」的财务权限误入。
|
||||
"""
|
||||
perm_map = dict(_DEFAULT_FADAN_PERM_TO_SHENFEN)
|
||||
generic_codes = list(_FADAN_GENERIC_PERMS)
|
||||
try:
|
||||
rows = Permission.query.filter(
|
||||
Q(perm_name__icontains='罚款') | Q(perm_name__icontains='罚单')
|
||||
).values('perm_code', 'perm_name')
|
||||
for row in rows:
|
||||
code = row['perm_code']
|
||||
name = row['perm_name'] or ''
|
||||
matched_sf = None
|
||||
for kw, sf in _SHENFEN_KEYWORDS.items():
|
||||
if kw in name:
|
||||
matched_sf = sf
|
||||
break
|
||||
if matched_sf is not None:
|
||||
perm_map[code] = matched_sf
|
||||
elif code not in generic_codes:
|
||||
generic_codes.append(code)
|
||||
except Exception as e:
|
||||
logger.warning(f"从 permission 表加载罚款权限失败,使用硬编码映射: {e}")
|
||||
return perm_map, tuple(generic_codes)
|
||||
|
||||
|
||||
# 兼容旧引用
|
||||
PERMISSION_TO_SHENFEN = _DEFAULT_FADAN_PERM_TO_SHENFEN
|
||||
|
||||
|
||||
def has_fadan_view_permission(permissions, account_id=''):
|
||||
"""列表/统计:拥有任一罚款权限或超级管理员权限即可查看。"""
|
||||
if '000001' in permissions:
|
||||
return True
|
||||
perm_map, generic_codes = _get_fadan_permission_config()
|
||||
all_codes = set(perm_map.keys()) | set(generic_codes)
|
||||
if any(p in permissions for p in all_codes):
|
||||
return True
|
||||
logger.warning(
|
||||
f"罚款查看权限不足 account={account_id} "
|
||||
f"user_perms={permissions} need_any={sorted(all_codes)}"
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
def check_fadan_permission(permissions, shenfen):
|
||||
"""创建/处理:需拥有对应身份的罚款权限,或通用罚款权限,或超级管理员权限。"""
|
||||
if '000001' in permissions:
|
||||
return True
|
||||
if any(p in permissions for p in _get_fadan_permission_config()[1]):
|
||||
return True
|
||||
shenfen = int(shenfen)
|
||||
perm_map, _ = _get_fadan_permission_config()
|
||||
for perm, sf in perm_map.items():
|
||||
if sf == shenfen and perm in permissions:
|
||||
return True
|
||||
return False
|
||||
224
backend/view.py
224
backend/view.py
@@ -322,13 +322,13 @@ class GetAdminUserListView(APIView):
|
||||
|
||||
users = User.query.filter(
|
||||
user_type='kefu',
|
||||
kefu_profile__isnull=False
|
||||
).select_related('kefu_profile')
|
||||
KefuProfile__isnull=False
|
||||
).select_related('KefuProfile')
|
||||
|
||||
if phone:
|
||||
users = users.filter(phone__icontains=phone)
|
||||
if nicheng:
|
||||
users = users.filter(kefu_profile__nicheng__icontains=nicheng)
|
||||
users = users.filter(KefuProfile__nicheng__icontains=nicheng)
|
||||
|
||||
# 关键修正:先求值为列表,再传入 phone__in
|
||||
if role_code:
|
||||
@@ -365,11 +365,11 @@ class GetAdminUserListView(APIView):
|
||||
for r in user_roles
|
||||
]
|
||||
data_list.append({
|
||||
'phone': user.phone,
|
||||
'nicheng': user.kefu_profile.nicheng,
|
||||
'phone': user.Phone,
|
||||
'nicheng': user.KefuProfile.nicheng,
|
||||
'roles': roles_data,
|
||||
'status': user.kefu_profile.zhuangtai,
|
||||
'create_time': user.create_time.strftime('%Y-%m-%d %H:%M:%S') if hasattr(user, 'create_time') else '',
|
||||
'status': user.KefuProfile.zhuangtai,
|
||||
'create_time': user.UserCreateTime.strftime('%Y-%m-%d %H:%M:%S') if hasattr(user, 'UserCreateTime') else '',
|
||||
'update_time': user.update_time.strftime('%Y-%m-%d %H:%M:%S') if hasattr(user, 'update_time') else '',
|
||||
})
|
||||
|
||||
@@ -440,11 +440,11 @@ class GetAdminRolesView(APIView):
|
||||
page_size = int(request.data.get('pageSize', 20))
|
||||
|
||||
# 基础查询:存在客服扩展表
|
||||
users = User.query.filter(kefu_profile__isnull=False).select_related('kefu_profile')
|
||||
users = User.query.filter(KefuProfile__isnull=False).select_related('KefuProfile')
|
||||
if phone:
|
||||
users = users.filter(Phone__icontains=phone)
|
||||
if nicheng:
|
||||
users = users.filter(kefu_profile__nicheng__icontains=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)
|
||||
@@ -461,14 +461,14 @@ class GetAdminRolesView(APIView):
|
||||
data_list = []
|
||||
for user in page_obj:
|
||||
# 获取用户的所有角色
|
||||
user_roles = UserRole.query.filter(account_id=user.phone).select_related('role')
|
||||
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.kefu_profile.nicheng,
|
||||
'phone': user.Phone,
|
||||
'nicheng': user.KefuProfile.nicheng,
|
||||
'roles': roles_data,
|
||||
'status': user.kefu_profile.zhuangtai,
|
||||
'create_time': user.create_time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'status': user.KefuProfile.zhuangtai,
|
||||
'create_time': user.UserCreateTime.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'update_time': user.update_time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
})
|
||||
|
||||
@@ -508,7 +508,7 @@ class ModifyAdminUserView(APIView):
|
||||
|
||||
try:
|
||||
target_user = User.query.get(Phone=target_phone)
|
||||
target_kefu = target_user.kefu_profile
|
||||
target_kefu = target_user.KefuProfile
|
||||
except User.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '用户不存在'})
|
||||
except UserKefu.DoesNotExist:
|
||||
@@ -600,7 +600,7 @@ class AddAdminUserView(APIView):
|
||||
return Response({'code': 400, 'msg': '密码和二级密码至少6位'})
|
||||
|
||||
# 校验手机号是否已被客服占用
|
||||
if User.query.filter(Phone=phone, kefu_profile__isnull=False).exists():
|
||||
if User.query.filter(Phone=phone, KefuProfile__isnull=False).exists():
|
||||
return Response({'code': 400, 'msg': '该账号已存在'})
|
||||
|
||||
# 生成唯一的 yonghuid(7位数字)
|
||||
@@ -743,8 +743,8 @@ class KefuGetDashouListView(APIView):
|
||||
for dashou in dashou_list:
|
||||
user = dashou.user
|
||||
result.append({
|
||||
'yonghuid': user.yonghuid,
|
||||
'avatar': user.avatar or '',
|
||||
'yonghuid': user.UserUID,
|
||||
'avatar': user.Avatar or '',
|
||||
'zaixianzhuangtai': dashou.zaixianzhuangtai,
|
||||
'zhanghaozhuangtai': dashou.zhanghaozhuangtai,
|
||||
'nicheng': dashou.nicheng or '',
|
||||
@@ -799,19 +799,19 @@ class KefuGetDashouDetailView(APIView):
|
||||
|
||||
# 4. 查询打手主表和扩展表
|
||||
try:
|
||||
user_main = User.query.select_related('dashou_profile').get(
|
||||
user_main = User.query.select_related('DashouProfile').get(
|
||||
UserUID=uid
|
||||
)
|
||||
except User.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '打手不存在'})
|
||||
|
||||
try:
|
||||
dashou = user_main.dashou_profile
|
||||
dashou = user_main.DashouProfile
|
||||
except ObjectDoesNotExist:
|
||||
# 用户存在但未注册打手身份,返回基本信息
|
||||
user_info = {
|
||||
'yonghuid': user_main.yonghuid,
|
||||
'avatar': user_main.avatar or '',
|
||||
'yonghuid': user_main.UserUID,
|
||||
'avatar': user_main.Avatar or '',
|
||||
'zaixianzhuangtai': 0,
|
||||
'zhanghaozhuangtai': 0,
|
||||
'zhuangtai': 0,
|
||||
@@ -819,9 +819,9 @@ class KefuGetDashouDetailView(APIView):
|
||||
'chenghao': '',
|
||||
'dianhua': '',
|
||||
'wechat': '',
|
||||
'phone': user_main.phone or '',
|
||||
'create_time': user_main.create_time,
|
||||
'ip': user_main.ip or '',
|
||||
'phone': user_main.Phone or '',
|
||||
'create_time': user_main.UserCreateTime,
|
||||
'ip': user_main.IP or '',
|
||||
'jiedanzongliang': 0,
|
||||
'chengjiaozongliang': 0,
|
||||
'tuikuanliang': 0,
|
||||
@@ -850,8 +850,8 @@ class KefuGetDashouDetailView(APIView):
|
||||
|
||||
# 5. 构建打手信息
|
||||
user_info = {
|
||||
'yonghuid': user_main.yonghuid,
|
||||
'avatar': user_main.avatar or '',
|
||||
'yonghuid': user_main.UserUID,
|
||||
'avatar': user_main.Avatar or '',
|
||||
'zaixianzhuangtai': dashou.zaixianzhuangtai,
|
||||
'zhanghaozhuangtai': dashou.zhanghaozhuangtai,
|
||||
'zhuangtai': dashou.zhuangtai,
|
||||
@@ -859,9 +859,9 @@ class KefuGetDashouDetailView(APIView):
|
||||
'chenghao': dashou.chenghao or '',
|
||||
'dianhua': dashou.dianhua or '',
|
||||
'wechat': dashou.wechat or '',
|
||||
'phone': user_main.phone or '',
|
||||
'create_time': user_main.create_time,
|
||||
'ip': user_main.ip or '',
|
||||
'phone': user_main.Phone or '',
|
||||
'create_time': user_main.UserCreateTime,
|
||||
'ip': user_main.IP or '',
|
||||
'jiedanzongliang': dashou.jiedanzongliang,
|
||||
'chengjiaozongliang': dashou.chengjiaozongliang,
|
||||
'tuikuanliang': dashou.tuikuanliang,
|
||||
@@ -956,7 +956,7 @@ class KefuGetDashouDetailView(APIView):
|
||||
# 3. 查询打手主表和扩展表
|
||||
try:
|
||||
# 使用 select_related 预加载 dashou_profile,减少数据库查询
|
||||
user_main = User.query.select_related('dashou_profile').get(
|
||||
user_main = User.query.select_related('DashouProfile').get(
|
||||
UserUID=uid
|
||||
)
|
||||
except User.DoesNotExist:
|
||||
@@ -965,12 +965,12 @@ class KefuGetDashouDetailView(APIView):
|
||||
# 验证用户类型是否为打手(可选,但建议验证)
|
||||
# 如果该用户没有打手扩展表,则返回空信息(但前端会显示未注册)
|
||||
try:
|
||||
dashou = user_main.dashou_profile
|
||||
dashou = user_main.DashouProfile
|
||||
except ObjectDoesNotExist:
|
||||
# 用户存在但未注册打手身份,返回基本信息
|
||||
user_info = {
|
||||
'yonghuid': user_main.yonghuid,
|
||||
'avatar': user_main.avatar or '',
|
||||
'yonghuid': user_main.UserUID,
|
||||
'avatar': user_main.Avatar or '',
|
||||
'zaixianzhuangtai': 0,
|
||||
'zhanghaozhuangtai': 0,
|
||||
'zhuangtai': 0,
|
||||
@@ -978,9 +978,9 @@ class KefuGetDashouDetailView(APIView):
|
||||
'chenghao': '',
|
||||
'dianhua': '',
|
||||
'wechat': '',
|
||||
'phone': user_main.phone or '',
|
||||
'create_time': user_main.create_time,
|
||||
'ip': user_main.ip or '',
|
||||
'phone': user_main.Phone or '',
|
||||
'create_time': user_main.UserCreateTime,
|
||||
'ip': user_main.IP or '',
|
||||
'jiedanzongliang': 0,
|
||||
'chengjiaozongliang': 0,
|
||||
'tuikuanliang': 0,
|
||||
@@ -1005,8 +1005,8 @@ class KefuGetDashouDetailView(APIView):
|
||||
|
||||
# 4. 构建打手信息
|
||||
user_info = {
|
||||
'yonghuid': user_main.yonghuid,
|
||||
'avatar': user_main.avatar or '',
|
||||
'yonghuid': user_main.UserUID,
|
||||
'avatar': user_main.Avatar or '',
|
||||
'zaixianzhuangtai': dashou.zaixianzhuangtai,
|
||||
'zhanghaozhuangtai': dashou.zhanghaozhuangtai,
|
||||
'zhuangtai': dashou.zhuangtai,
|
||||
@@ -1014,9 +1014,9 @@ class KefuGetDashouDetailView(APIView):
|
||||
'chenghao': dashou.chenghao or '',
|
||||
'dianhua': dashou.dianhua or '',
|
||||
'wechat': dashou.wechat or '',
|
||||
'phone': user_main.phone or '',
|
||||
'create_time': user_main.create_time,
|
||||
'ip': user_main.ip or '',
|
||||
'phone': user_main.Phone or '',
|
||||
'create_time': user_main.UserCreateTime,
|
||||
'ip': user_main.IP or '',
|
||||
'jiedanzongliang': dashou.jiedanzongliang,
|
||||
'chengjiaozongliang': dashou.chengjiaozongliang,
|
||||
'tuikuanliang': dashou.tuikuanliang,
|
||||
@@ -1107,7 +1107,7 @@ class KefuUpdateDashouView(APIView):
|
||||
# 3. 查询打手
|
||||
try:
|
||||
dashou_user = User.query.get(UserUID=dashou_id)
|
||||
dashou_profile = dashou_user.dashou_profile
|
||||
dashou_profile = dashou_user.DashouProfile
|
||||
except User.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '打手不存在'})
|
||||
except UserDashou.DoesNotExist:
|
||||
@@ -1137,7 +1137,7 @@ class KefuUpdateDashouView(APIView):
|
||||
after = dashou_profile.yue
|
||||
Xiugaijilu.query.create(
|
||||
yonghuid=dashou_id,
|
||||
xiugaiid=kefu.user.phone,
|
||||
xiugaiid=kefu.user.Phone,
|
||||
leixing=2,
|
||||
xiugaitijiao=after,
|
||||
xiugaitijiaoq=before['yue'],
|
||||
@@ -1153,7 +1153,7 @@ class KefuUpdateDashouView(APIView):
|
||||
after = dashou_profile.yue
|
||||
Xiugaijilu.query.create(
|
||||
yonghuid=dashou_id,
|
||||
xiugaiid=kefu.user.phone,
|
||||
xiugaiid=kefu.user.Phone,
|
||||
leixing=2,
|
||||
xiugaitijiao=after,
|
||||
xiugaitijiaoq=before['yue'],
|
||||
@@ -1172,7 +1172,7 @@ class KefuUpdateDashouView(APIView):
|
||||
after = dashou_profile.yajin
|
||||
Xiugaijilu.query.create(
|
||||
yonghuid=dashou_id,
|
||||
xiugaiid=kefu.user.phone,
|
||||
xiugaiid=kefu.user.Phone,
|
||||
leixing=2,
|
||||
yajin=after,
|
||||
yyajin=before['yajin'],
|
||||
@@ -1188,7 +1188,7 @@ class KefuUpdateDashouView(APIView):
|
||||
after = dashou_profile.yajin
|
||||
Xiugaijilu.query.create(
|
||||
yonghuid=dashou_id,
|
||||
xiugaiid=kefu.user.phone,
|
||||
xiugaiid=kefu.user.Phone,
|
||||
leixing=2,
|
||||
yajin=after,
|
||||
yyajin=before['yajin'],
|
||||
@@ -1207,7 +1207,7 @@ class KefuUpdateDashouView(APIView):
|
||||
after = dashou_profile.jifen
|
||||
Xiugaijilu.query.create(
|
||||
yonghuid=dashou_id,
|
||||
xiugaiid=kefu.user.phone,
|
||||
xiugaiid=kefu.user.Phone,
|
||||
leixing=2,
|
||||
jifen=after,
|
||||
yjifen=before['jifen'],
|
||||
@@ -1223,7 +1223,7 @@ class KefuUpdateDashouView(APIView):
|
||||
after = dashou_profile.jifen
|
||||
Xiugaijilu.query.create(
|
||||
yonghuid=dashou_id,
|
||||
xiugaiid=kefu.user.phone,
|
||||
xiugaiid=kefu.user.Phone,
|
||||
leixing=2,
|
||||
jifen=after,
|
||||
yjifen=before['jifen'],
|
||||
@@ -1241,7 +1241,7 @@ class KefuUpdateDashouView(APIView):
|
||||
dashou_profile.save()
|
||||
Xiugaijilu.query.create(
|
||||
yonghuid=dashou_id,
|
||||
xiugaiid=kefu.user.phone,
|
||||
xiugaiid=kefu.user.Phone,
|
||||
leixing=2,
|
||||
qitashuoming=f'修改账号状态为{new_status}',
|
||||
)
|
||||
@@ -1257,7 +1257,7 @@ class KefuUpdateDashouView(APIView):
|
||||
dashou_profile.save()
|
||||
Xiugaijilu.query.create(
|
||||
yonghuid=dashou_id,
|
||||
xiugaiid=kefu.user.phone,
|
||||
xiugaiid=kefu.user.Phone,
|
||||
leixing=2,
|
||||
qitashuoming=f'修改在线状态为{new_status}',
|
||||
)
|
||||
@@ -1273,7 +1273,7 @@ class KefuUpdateDashouView(APIView):
|
||||
dashou_profile.save()
|
||||
Xiugaijilu.query.create(
|
||||
yonghuid=dashou_id,
|
||||
xiugaiid=kefu.user.phone,
|
||||
xiugaiid=kefu.user.Phone,
|
||||
leixing=2,
|
||||
qitashuoming=f'修改接单状态为{new_status}',
|
||||
)
|
||||
@@ -1306,7 +1306,7 @@ class KefuUpdateDashouView(APIView):
|
||||
record.save()
|
||||
Xiugaijilu.query.create(
|
||||
yonghuid=dashou_id,
|
||||
xiugaiid=kefu.user.phone,
|
||||
xiugaiid=kefu.user.Phone,
|
||||
leixing=2,
|
||||
huiyuants=days,
|
||||
huiyuan_id=huiyuan_id,
|
||||
@@ -1326,7 +1326,7 @@ class KefuUpdateDashouView(APIView):
|
||||
record.delete()
|
||||
Xiugaijilu.query.create(
|
||||
yonghuid=dashou_id,
|
||||
xiugaiid=kefu.user.phone,
|
||||
xiugaiid=kefu.user.Phone,
|
||||
leixing=2,
|
||||
huiyuan_id=huiyuan_id,
|
||||
qitashuoming=f'移除会员 {huiyuan_id}',
|
||||
@@ -1345,7 +1345,7 @@ class KefuUpdateDashouView(APIView):
|
||||
dashou_profile.save()
|
||||
Xiugaijilu.query.create(
|
||||
yonghuid=dashou_id,
|
||||
xiugaiid=kefu.user.phone,
|
||||
xiugaiid=kefu.user.Phone,
|
||||
leixing=2,
|
||||
qitashuoming=f'修改称号:{before["chenghao"] or "无"} → {new_chenghao}',
|
||||
)
|
||||
@@ -1479,8 +1479,8 @@ class KefuGetShangjiaListView(APIView):
|
||||
for shangjia in shangjia_list:
|
||||
user = shangjia.user
|
||||
result.append({
|
||||
'yonghuid': user.yonghuid,
|
||||
'avatar': user.avatar or '',
|
||||
'yonghuid': user.UserUID,
|
||||
'avatar': user.Avatar or '',
|
||||
'nicheng': shangjia.nicheng or '',
|
||||
'yue': str(shangjia.yue), # 转换为字符串,避免前端精度问题
|
||||
'fabu': shangjia.fabu,
|
||||
@@ -1545,8 +1545,8 @@ class KefuGetShangjiaDetailView(APIView):
|
||||
user = shangjia.user
|
||||
|
||||
data = {
|
||||
'yonghuid': user.yonghuid,
|
||||
'avatar': user.avatar or '',
|
||||
'yonghuid': user.UserUID,
|
||||
'avatar': user.Avatar or '',
|
||||
'nicheng': shangjia.nicheng,
|
||||
'zhuangtai': shangjia.zhuangtai, # 1正常,2禁用
|
||||
'dianhua': shangjia.dianhua,
|
||||
@@ -2882,14 +2882,14 @@ class GetGuanliListView(APIView):
|
||||
|
||||
# 构建查询:从 User 开始,关联 UserGuanshi 和 UserBoss(左连接获取昵称)
|
||||
qs = User.query.filter(
|
||||
guanshi_profile__isnull=False # 确保是管事
|
||||
).select_related('guanshi_profile').select_related('boss_profile')
|
||||
GuanshiProfile__isnull=False # 确保是管事
|
||||
).select_related('GuanshiProfile').select_related('BossProfile')
|
||||
|
||||
# 关键词搜索(用户ID 或 昵称来自 boss_profile.nickname)
|
||||
if keyword:
|
||||
qs = qs.filter(
|
||||
Q(UserUID__icontains=keyword) |
|
||||
Q(boss_profile__nickname__icontains=keyword)
|
||||
Q(BossProfile__nickname__icontains=keyword)
|
||||
)
|
||||
|
||||
# 余额筛选(使用 guanshi_profile.yue)
|
||||
@@ -2897,9 +2897,9 @@ class GetGuanliListView(APIView):
|
||||
try:
|
||||
balance_val = Decimal(str(balance_value))
|
||||
if balance_op == 'gte':
|
||||
qs = qs.filter(guanshi_profile__yue__gte=balance_val)
|
||||
qs = qs.filter(GuanshiProfile__yue__gte=balance_val)
|
||||
elif balance_op == 'lte':
|
||||
qs = qs.filter(guanshi_profile__yue__lte=balance_val)
|
||||
qs = qs.filter(GuanshiProfile__yue__lte=balance_val)
|
||||
else:
|
||||
return Response({'code': 400, 'msg': '余额比较符无效'})
|
||||
except:
|
||||
@@ -2910,9 +2910,9 @@ class GetGuanliListView(APIView):
|
||||
try:
|
||||
commission_val = Decimal(str(commission_value))
|
||||
if commission_op == 'gte':
|
||||
qs = qs.filter(guanshi_profile__chongzhifenrun__gte=commission_val)
|
||||
qs = qs.filter(GuanshiProfile__chongzhifenrun__gte=commission_val)
|
||||
elif commission_op == 'lte':
|
||||
qs = qs.filter(guanshi_profile__chongzhifenrun__lte=commission_val)
|
||||
qs = qs.filter(GuanshiProfile__chongzhifenrun__lte=commission_val)
|
||||
else:
|
||||
return Response({'code': 400, 'msg': '分佣比较符无效'})
|
||||
except:
|
||||
@@ -2923,9 +2923,9 @@ class GetGuanliListView(APIView):
|
||||
try:
|
||||
invite_val = int(invite_count_value)
|
||||
if invite_count_op == 'gte':
|
||||
qs = qs.filter(guanshi_profile__yaogingshuliang__gte=invite_val)
|
||||
qs = qs.filter(GuanshiProfile__yaogingshuliang__gte=invite_val)
|
||||
elif invite_count_op == 'lte':
|
||||
qs = qs.filter(guanshi_profile__yaogingshuliang__lte=invite_val)
|
||||
qs = qs.filter(GuanshiProfile__yaogingshuliang__lte=invite_val)
|
||||
else:
|
||||
return Response({'code': 400, 'msg': '邀请数量比较符无效'})
|
||||
except:
|
||||
@@ -2937,7 +2937,7 @@ class GetGuanliListView(APIView):
|
||||
status_val = int(status)
|
||||
if status_val not in (0, 1):
|
||||
raise ValueError
|
||||
qs = qs.filter(guanshi_profile__zhuangtai=status_val)
|
||||
qs = qs.filter(GuanshiProfile__zhuangtai=status_val)
|
||||
except:
|
||||
return Response({'code': 400, 'msg': '状态值无效'})
|
||||
|
||||
@@ -2951,11 +2951,11 @@ class GetGuanliListView(APIView):
|
||||
# 构建返回数据
|
||||
result = []
|
||||
for user in users:
|
||||
guanshi = user.guanshi_profile
|
||||
boss = user.boss_profile if hasattr(user, 'boss_profile') else None
|
||||
guanshi = user.GuanshiProfile
|
||||
boss = user.BossProfile if hasattr(user, 'BossProfile') else None
|
||||
result.append({
|
||||
'yonghuid': user.yonghuid,
|
||||
'avatar': user.avatar or '',
|
||||
'yonghuid': user.UserUID,
|
||||
'avatar': user.Avatar or '',
|
||||
'nickname': boss.nickname if boss else '',
|
||||
'zhuangtai': guanshi.zhuangtai,
|
||||
'yaogingshuliang': guanshi.yaogingshuliang,
|
||||
@@ -3010,9 +3010,9 @@ class GetGuanliDetailView(APIView):
|
||||
|
||||
# 查询用户主表和管事扩展表
|
||||
try:
|
||||
user = User.query.select_related('guanshi_profile', 'boss_profile').get(UserUID=yonghuid)
|
||||
guanshi = user.guanshi_profile
|
||||
boss = user.boss_profile if hasattr(user, 'boss_profile') else None
|
||||
user = User.query.select_related('GuanshiProfile', 'BossProfile').get(UserUID=yonghuid)
|
||||
guanshi = user.GuanshiProfile
|
||||
boss = user.BossProfile if hasattr(user, 'BossProfile') else None
|
||||
except User.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '管事不存在'})
|
||||
except UserGuanshi.DoesNotExist:
|
||||
@@ -3020,9 +3020,9 @@ class GetGuanliDetailView(APIView):
|
||||
|
||||
# 基础信息
|
||||
base_data = {
|
||||
'yonghuid': user.yonghuid,
|
||||
'yonghuid': user.UserUID,
|
||||
'nickname': boss.nickname if boss else '',
|
||||
'avatar': user.avatar or '',
|
||||
'avatar': user.Avatar or '',
|
||||
'dianhua': guanshi.dianhua or '',
|
||||
'wechat': guanshi.wechat or '',
|
||||
'zhuangtai': guanshi.zhuangtai,
|
||||
@@ -3132,8 +3132,8 @@ class UpdateGuanliView(APIView):
|
||||
# 查询管事对象(不在事务外加锁,事务内加锁)
|
||||
try:
|
||||
user = User.query.get(UserUID=yonghuid)
|
||||
guanshi = user.guanshi_profile
|
||||
boss = user.boss_profile if hasattr(user, 'boss_profile') else None
|
||||
guanshi = user.GuanshiProfile
|
||||
boss = user.BossProfile if hasattr(user, 'BossProfile') else None
|
||||
except User.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '用户不存在'})
|
||||
except UserGuanshi.DoesNotExist:
|
||||
@@ -3143,8 +3143,8 @@ class UpdateGuanliView(APIView):
|
||||
with transaction.atomic():
|
||||
# 重新获取加锁对象
|
||||
user = User.objects.select_for_update().get(UserUID=yonghuid)
|
||||
guanshi = user.guanshi_profile
|
||||
boss = user.boss_profile if hasattr(user, 'boss_profile') else None
|
||||
guanshi = user.GuanshiProfile
|
||||
boss = user.BossProfile if hasattr(user, 'BossProfile') else None
|
||||
|
||||
# ---------- 1. 基础信息修改(需要4400a)----------
|
||||
nickname = request.data.get('nickname')
|
||||
@@ -3176,7 +3176,7 @@ class UpdateGuanliView(APIView):
|
||||
except:
|
||||
pass
|
||||
if avatar is not None:
|
||||
user.avatar = avatar
|
||||
user.Avatar = avatar
|
||||
user.save()
|
||||
guanshi.save()
|
||||
|
||||
@@ -3559,7 +3559,7 @@ class GetZuzhangListView(APIView):
|
||||
# 3. 检查是否拥有组长管理所需权限(6600a ~ 6600e 任一)
|
||||
required_perms = ['6600a', '6600b', '6600c', '6600d', '6600e']
|
||||
if not any(perm in permissions for perm in required_perms):
|
||||
logger.warning(f"用户 {request.user.phone} 尝试访问组长列表但缺少必要权限,已有权限: {permissions}")
|
||||
logger.warning(f"用户 {request.user.Phone} 尝试访问组长列表但缺少必要权限,已有权限: {permissions}")
|
||||
return Response({'code': 403, 'msg': '您无权访问组长管理页面'})
|
||||
|
||||
# 4. 提取请求参数(分页 + 筛选)
|
||||
@@ -3579,7 +3579,7 @@ class GetZuzhangListView(APIView):
|
||||
commission_value = request.data.get('commission_value')
|
||||
|
||||
# 5. 构建基础 QuerySet(预加载关联表)
|
||||
queryset = UserZuzhang.query.select_related('user', 'user__boss_profile').all()
|
||||
queryset = UserZuzhang.query.select_related('user', 'user__BossProfile').all()
|
||||
|
||||
# 6. 应用筛选条件(使用 ORM 安全过滤)
|
||||
if keyword:
|
||||
@@ -3633,12 +3633,12 @@ class GetZuzhangListView(APIView):
|
||||
for zu in paged_queryset:
|
||||
user = zu.user
|
||||
nickname = ''
|
||||
if hasattr(user, 'boss_profile') and user.boss_profile:
|
||||
nickname = user.boss_profile.nickname or ''
|
||||
if hasattr(user, 'BossProfile') and user.BossProfile:
|
||||
nickname = user.BossProfile.nickname or ''
|
||||
|
||||
data_list.append({
|
||||
'yonghuid': user.yonghuid,
|
||||
'avatar': user.avatar or '',
|
||||
'yonghuid': user.UserUID,
|
||||
'avatar': user.Avatar or '',
|
||||
'nickname': nickname,
|
||||
'fenyong_zonge': float(zu.fenyong_zonge),
|
||||
'ketixian_jine': float(zu.ketixian_jine),
|
||||
@@ -3702,9 +3702,9 @@ class GetZuzhangDetailView(APIView):
|
||||
|
||||
# 查询组长主表、扩展表、老板扩展表(昵称)
|
||||
try:
|
||||
user = User.query.select_related('zuzhang_profile', 'boss_profile').get(UserUID=yonghuid)
|
||||
zuzhang = user.zuzhang_profile
|
||||
boss = user.boss_profile if hasattr(user, 'boss_profile') else None
|
||||
user = User.query.select_related('ZuzhangProfile', 'BossProfile').get(UserUID=yonghuid)
|
||||
zuzhang = user.ZuzhangProfile
|
||||
boss = user.BossProfile if hasattr(user, 'BossProfile') else None
|
||||
except User.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '组长不存在'})
|
||||
except UserZuzhang.DoesNotExist:
|
||||
@@ -3712,9 +3712,9 @@ class GetZuzhangDetailView(APIView):
|
||||
|
||||
# 基础信息
|
||||
base_data = {
|
||||
'yonghuid': user.yonghuid,
|
||||
'yonghuid': user.UserUID,
|
||||
'nickname': boss.nickname if boss else '',
|
||||
'avatar': user.avatar or '',
|
||||
'avatar': user.Avatar or '',
|
||||
'dianhua': '', # 组长表无电话字段?组长扩展表没有电话/微信,但前端可能需要,可从User关联?实际上组长表无电话字段,这里留空或从其他表获取
|
||||
'wechat': '',
|
||||
'zhuangtai': zuzhang.zhuangtai,
|
||||
@@ -3826,8 +3826,8 @@ class UpdateZuzhangView(APIView):
|
||||
# 查询组长对象
|
||||
try:
|
||||
user = User.query.get(UserUID=yonghuid)
|
||||
zuzhang = user.zuzhang_profile
|
||||
boss = user.boss_profile if hasattr(user, 'boss_profile') else None
|
||||
zuzhang = user.ZuzhangProfile
|
||||
boss = user.BossProfile if hasattr(user, 'BossProfile') else None
|
||||
except User.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '用户不存在'})
|
||||
except UserZuzhang.DoesNotExist:
|
||||
@@ -3861,7 +3861,7 @@ class UpdateZuzhangView(APIView):
|
||||
boss.nickname = nickname
|
||||
boss.save()
|
||||
if avatar:
|
||||
user.avatar = avatar
|
||||
user.Avatar = avatar
|
||||
user.save()
|
||||
# 组长表没有电话/微信字段,如需存储可暂存到User或忽略
|
||||
# 这里不处理
|
||||
@@ -5944,7 +5944,7 @@ class FaKuanChuLiView(APIView):
|
||||
return Response({'code': 400, 'msg': '无效的操作类型'})
|
||||
|
||||
# 记录处理者(使用 request.user 的 phone)
|
||||
penalty.ProcessorID = request.user.phone
|
||||
penalty.ProcessorID = request.user.Phone
|
||||
penalty.ProcessorIdentity = 2 # 这里假设处理者是售后身份,可根据实际业务获取
|
||||
penalty.save()
|
||||
|
||||
@@ -6033,7 +6033,7 @@ class FaKuanChuangJianView(APIView):
|
||||
penalty = Penalty.query.create(
|
||||
PenalizedUserID=PenalizedUserID,
|
||||
Identity=shenfen,
|
||||
ApplicantID=request.user.phone, # 申请人(客服)手机号
|
||||
ApplicantID=request.user.Phone, # 申请人(客服)手机号
|
||||
ApplicantIdentity=2, # 售后身份
|
||||
Reason=Reason,
|
||||
FineAmount=FineAmount,
|
||||
@@ -6134,7 +6134,7 @@ class FineApplyView(APIView):
|
||||
with transaction.atomic():
|
||||
penalty = Penalty.query.create(
|
||||
PenalizedUserID=dashou_id,
|
||||
ApplicantID=request.user.phone,
|
||||
ApplicantID=request.user.Phone,
|
||||
Identity=1, # 被处罚人身份:1 打手
|
||||
Reason=Reason,
|
||||
FineAmount=FineAmount,
|
||||
@@ -6204,7 +6204,7 @@ class PunishDashouView(APIView):
|
||||
# 查询打手
|
||||
try:
|
||||
dashou_user = User.query.get(UserUID=dashou_id)
|
||||
dashou = dashou_user.dashou_profile
|
||||
dashou = dashou_user.DashouProfile
|
||||
except User.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '打手用户不存在'})
|
||||
except ObjectDoesNotExist:
|
||||
@@ -7984,7 +7984,7 @@ class KhgglView(APIView):
|
||||
filter_bankuai_name = request.data.get('bankuai_name', '').strip()
|
||||
|
||||
# 基础查询:所有审核官,预加载用户及打手扩展表
|
||||
queryset = UserShenheguan.query.select_related('user__dashou_profile')
|
||||
queryset = UserShenheguan.query.select_related('user__DashouProfile')
|
||||
|
||||
if filter_yonghuid:
|
||||
queryset = queryset.filter(user__UserUID=filter_yonghuid)
|
||||
@@ -8015,7 +8015,7 @@ class KhgglView(APIView):
|
||||
tag_ids = Chenghao.query.filter(bankuai=bk, leixing='dashou').values_list('id', flat=True)
|
||||
count = YonghuChenghao.query.filter(
|
||||
chenghao_id__in=tag_ids,
|
||||
yonghu__dashou_profile__isnull=False
|
||||
yonghu__DashouProfile__isnull=False
|
||||
).values('yonghu').distinct().count()
|
||||
bankuai_dashou_count_map[bk.bankuai_id] = count
|
||||
|
||||
@@ -8042,7 +8042,7 @@ class KhgglView(APIView):
|
||||
for sg in shenheguan_list:
|
||||
user = sg.user
|
||||
# 获取该审核官关联的板块
|
||||
bk_qs = KaoheguanBankuai.query.filter(kaoheguan_id=user.yonghuid).select_related('bankuai')
|
||||
bk_qs = KaoheguanBankuai.query.filter(kaoheguan_id=user.UserUID).select_related('bankuai')
|
||||
bankuai_info = []
|
||||
for bk in bk_qs:
|
||||
bid = bk.bankuai.bankuai_id
|
||||
@@ -8052,12 +8052,12 @@ class KhgglView(APIView):
|
||||
'dashou_count': bankuai_dashou_count_map.get(bid, 0)
|
||||
})
|
||||
|
||||
dashou_nick = user.dashou_profile.nicheng if hasattr(user, 'dashou_profile') and user.dashou_profile else ''
|
||||
dashou_nick = user.DashouProfile.nicheng if hasattr(user, 'DashouProfile') and user.DashouProfile else ''
|
||||
|
||||
data_list.append({
|
||||
'yonghuid': user.yonghuid,
|
||||
'avatar': user.avatar or '',
|
||||
'phone': user.phone or '',
|
||||
'yonghuid': user.UserUID,
|
||||
'avatar': user.Avatar or '',
|
||||
'phone': user.Phone or '',
|
||||
'zhuangtai': sg.zhuangtai,
|
||||
'shenhe_zhuangtai': sg.shenhe_zhuangtai,
|
||||
'shenhe_zongshu': sg.shenhe_zongshu,
|
||||
@@ -8231,7 +8231,7 @@ class ZxkfghdsView(APIView):
|
||||
shangjia_id = shangjia_ext.MerchantID
|
||||
# 获取商家昵称用于新订单扩展表
|
||||
shangjia_user = User.query.get(UserUID=shangjia_id)
|
||||
shangjia_nicheng = shangjia_user.shop_profile.nicheng or f"商家{shangjia_id}"
|
||||
shangjia_nicheng = shangjia_user.ShopProfile.nicheng or f"商家{shangjia_id}"
|
||||
except (ObjectDoesNotExist, UserShangjia.DoesNotExist):
|
||||
logger.error(f"商家信息缺失,订单: {OrderID}")
|
||||
return Response({'code': 500, 'msg': '商家数据异常'})
|
||||
@@ -8240,7 +8240,7 @@ class ZxkfghdsView(APIView):
|
||||
with transaction.atomic():
|
||||
# 5.1 订单状态改为已退款
|
||||
old_order.Status = 5
|
||||
old_order.AssignedCS = current_user.phone
|
||||
old_order.AssignedCS = current_user.Phone
|
||||
old_order.save()
|
||||
|
||||
# 5.2 处理接单打手(若有)
|
||||
@@ -8248,7 +8248,7 @@ class ZxkfghdsView(APIView):
|
||||
if dashou_id:
|
||||
try:
|
||||
dashou_user = User.query.get(UserUID=dashou_id)
|
||||
dashou_profile = dashou_user.dashou_profile
|
||||
dashou_profile = dashou_user.DashouProfile
|
||||
dashou_profile.tuikuanliang += 1 # 退款次数+1
|
||||
dashou_profile.zhuangtai = 1 # 设为空闲
|
||||
dashou_profile.save()
|
||||
@@ -8261,7 +8261,7 @@ class ZxkfghdsView(APIView):
|
||||
defaults={
|
||||
'PlayerID': dashou_id or '',
|
||||
'ApplicantID': '',
|
||||
'ProcessorID': current_user.phone,
|
||||
'ProcessorID': current_user.Phone,
|
||||
'Reason': '客服更换打手退款',
|
||||
'ApplyStatus': 1,
|
||||
'Amount': old_order.Amount or 0,
|
||||
|
||||
Reference in New Issue
Block a user