# yonghu/views.py
import time
import random
import hashlib
import requests
from django.db import transaction
from django.conf import settings
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework_simplejwt.tokens import RefreshToken

from .models import UserMain, UserBoss, UserDashou, UserShangjia, UserGuanshi, UserShenheguan
from dingdan.models import Dingdan, DingdanPingtai, Lilubiao
from peizhi.models import Qunpeizhi  # 假设群配置表在这个模块
from rest_framework.throttling import AnonRateThrottle
from rest_framework.permissions import AllowAny  # 新增这行







from django.conf import settings
from django.utils import timezone
from django.db import transaction
from django.core.exceptions import ObjectDoesNotExist
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.throttling import AnonRateThrottle
from rest_framework.permissions import AllowAny
from rest_framework_simplejwt.tokens import RefreshToken
from .models import UserMain, AdminProfile


# 获取客户端真实IP的函数
def huoquKehuduanIP(request):
    """
    获取客户端的真实IP地址
    考虑反向代理（如Nginx）的情况
    """
    # 优先从HTTP_X_FORWARDED_FOR获取（经过代理的情况）
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        # 可能有多个IP，取第一个
        ip = x_forwarded_for.split(',')[0].strip()
        if ip:
            return ip

    # 如果没有代理，直接从REMOTE_ADDR获取
    ip = request.META.get('REMOTE_ADDR', '')

    # 如果还是获取不到，返回默认值
    if not ip:
        ip = '0.0.0.0'

    return ip


# 获取用户代理信息（用于更详细的追踪）
def huoquYonghuDaili(request):
    """
    获取用户浏览器/设备信息
    """
    user_agent = request.META.get('HTTP_USER_AGENT', '')

    # 这里可以添加更复杂的用户代理解析
    # 为简化，我们只返回原始字符串的前100个字符
    return user_agent[:100] if user_agent else ''







class WechatMiniProgramLoginView(APIView):
    """
    微信小程序登录接口
    """
    throttle_classes = [AnonRateThrottle]
    permission_classes = [AllowAny]

    def post(self, request):
        try:
            code = request.data.get('code', '').strip()
            if not code:
                return Response({'code': 1, 'msg': '微信授权码不能为空', 'data': None},
                                status=status.HTTP_400_BAD_REQUEST)

            # 获取微信openid和unionid
            wechat_data = self.get_wechat_openid(code)
            if not wechat_data or 'openid' not in wechat_data:
                error_msg = wechat_data.get('errmsg', '微信授权失败')
                return Response({'code': 2, 'msg': f'微信登录失败: {error_msg}', 'data': None},
                                status=status.HTTP_400_BAD_REQUEST)

            openid = wechat_data['openid']
            session_key = wechat_data.get('session_key', '')
            unionid = wechat_data.get('unionid', '')  # 🆕【新增】获取unionid

            # 获取客户端真实IP
            kehuduan_ip = self.huoquKehuduanIP(request)

            with transaction.atomic():
                # 创建或获取用户
                user_main, created = UserMain.objects.select_for_update().get_or_create(
                    openid=openid,
                    defaults={'yonghuid': self.shengchengYonghuID(), 'user_type': 'normal'}
                )

                # 🆕【新增】保存unionid
                if unionid and unionid != user_main.unionid:
                    user_main.unionid = unionid

                cunchu_ip = kehuduan_ip
                user_main.ip = cunchu_ip
                user_main.last_login_time = timezone.now()
                user_main.save()

                if created:
                    UserBoss.objects.create(user=user_main, nickname='板板大人')

                # 检查扩展表
                dashou_status = 0
                shangjia_status = 0
                guanshi_status = 0
                boss_nickname = '微信用户'

                try:
                    boss_profile = UserBoss.objects.get(user=user_main)
                    boss_nickname = boss_profile.nickname if boss_profile.nickname else '微信用户'
                except UserBoss.DoesNotExist:
                    pass

                try:
                    UserDashou.objects.get(user=user_main)
                    dashou_status = 1
                except UserDashou.DoesNotExist:
                    dashou_status = None

                try:
                    UserShangjia.objects.get(user=user_main)
                    shangjia_status = 1
                except UserShangjia.DoesNotExist:
                    shangjia_status = None

                try:
                    UserGuanshi.objects.get(user=user_main)
                    guanshi_status = 1
                except UserGuanshi.DoesNotExist:
                    guanshi_status = None
                try:
                    UserZuzhang.objects.get(user=user_main)
                    zuzhang_status = 1
                except UserZuzhang.DoesNotExist:
                    zuzhang_status = None

                # 在检查 zuzhang 扩展表之后，插入以下代码
                try:
                    kg = UserShenheguan.objects.get(user=user_main)
                    kaoheguan_status = 1 if kg.zhuangtai == 1 else 0
                except UserShenheguan.DoesNotExist:
                    kaoheguan_status = 0


                # 生成JWT token
                refresh = RefreshToken.for_user(user_main)
                token = str(refresh.access_token)

                # 计算订单数量
                order_counts = self.jisuanDingdanShuliang(user_main.yonghuid)

                # 获取群配置
                group_info = self.huoquQunPeizhi()

            # 返回数据
            response_data = {
                'token': token,
                'nicheng': boss_nickname,
                'uid': user_main.yonghuid,
                'touxiang': user_main.avatar or '',
                'shangjiastatus': shangjia_status,
                'dashoustatus': dashou_status,
                'guanshistatus': guanshi_status,
                'kaoheguanstatus': kaoheguan_status,
                'zuzhangstatus': zuzhang_status,
                'dingdantiaoshu': order_counts,
                'dashouqun': group_info.get('dashouqun', ''),
                'dashouqunid': group_info.get('dashouqunid', ''),
                'guanshiqun': group_info.get('guanshiqun', ''),
                'guanshiqunid': group_info.get('guanshiqunid', '')
            }

            return Response({'code': 0, 'msg': '登录成功', 'data': response_data})

        except Exception as e:
            import logging
            logger = logging.getLogger(__name__)
            error_openid = locals().get('openid', 'N/A')
            logger.error(f"微信登录异常 - openid: {error_openid}, 错误类型: {type(e).__name__}, 错误详情: {str(e)}",
                         exc_info=True)

            return Response({'code': 99, 'msg': '系统繁忙，请稍后重试', 'data': None},
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def get_wechat_openid(self, code):
        """
        调用微信接口获取openid和unionid
        """
        try:
            appid = getattr(settings, 'WEIXIN_APPID', '')
            secret = getattr(settings, 'WEIXIN_SECRET', '')

            if not appid or not secret:
                raise ValueError('微信配置未设置')

            url = 'https://api.weixin.qq.com/sns/jscode2session'
            params = {'appid': appid, 'secret': secret, 'js_code': code, 'grant_type': 'authorization_code'}

            response = requests.get(url, params=params, timeout=10)
            result = response.json()

            if 'openid' in result:
                return {'openid': result['openid'], 'session_key': result.get('session_key', ''),
                        'unionid': result.get('unionid', '')}
            else:
                errcode = result.get('errcode', 'unknown')
                errmsg = result.get('errmsg', '未知错误')
                return {'errmsg': f'[{errcode}]{errmsg}'}

        except requests.exceptions.Timeout:
            return {'errmsg': '请求微信接口超时'}
        except Exception as e:
            return {'errmsg': f'请求微信接口异常: {str(e)}'}

    def shengchengYonghuID(self):
        """
        生成7位数字用户ID
        """
        for _ in range(10):
            timestamp_part = str(int(time.time()))[-5:].zfill(5)
            random_part = str(random.randint(0, 99)).zfill(2)
            user_id = timestamp_part + random_part

            if len(user_id) == 7 and user_id.isdigit():
                if not UserMain.objects.filter(yonghuid=user_id).exists():
                    return user_id

        raise Exception('生成用户ID失败')

    def huoquKehuduanIP(self, request):
        """
        获取客户端真实IP地址
        """
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0].strip()
            if ip:
                return ip

        ip = request.META.get('REMOTE_ADDR', '')
        return ip if ip else '0.0.0.0'

    def jisuanDingdanShuliang(self, yonghuid):
        """
        统计订单数量
        """
        try:
            if not DingdanPingtai.objects.filter(laoban_id=yonghuid).exists():
                return {'daifuwu': 0, 'fuwuzhong': 0, 'yiwancheng': 0, 'yituikuan': 0}

            dingdan_ids = DingdanPingtai.objects.filter(laoban_id=yonghuid).values_list('dingdan__id', flat=True)

            from django.db.models import Q, Count
            from django.db.models import Case, When, IntegerField

            results = Dingdan.objects.filter(id__in=dingdan_ids).aggregate(
                daifuwu=Count(Case(When(Q(zhuangtai=1) | Q(zhuangtai=7), then=1), output_field=IntegerField())),
                fuwuzhong=Count(Case(When(zhuangtai=2, then=1), output_field=IntegerField())),
                yiwancheng=Count(Case(When(zhuangtai=3, then=1), output_field=IntegerField())),
                yituikuan=Count(Case(When(zhuangtai=5, then=1), output_field=IntegerField()))
            )

            return {
                'daifuwu': results['daifuwu'] or 0,
                'fuwuzhong': results['fuwuzhong'] or 0,
                'yiwancheng': results['yiwancheng'] or 0,
                'yituikuan': results['yituikuan'] or 0
            }

        except Exception:
            return {'daifuwu': 0, 'fuwuzhong': 0, 'yiwancheng': 0, 'yituikuan': 0}

    def huoquQunPeizhi(self):
        """
        获取群配置信息
        """
        try:
            qun_configs = Qunpeizhi.objects.filter(id__in=[1, 2])

            result = {
                'dashouqun': '',
                'dashouqunid': '',
                'guanshiqun': '',
                'guanshiqunid': ''
            }

            for config in qun_configs:
                if config.id == 1:
                    result['dashouqun'] = config.neirong or ''
                    result['dashouqunid'] = config.qunid or ''
                elif config.id == 2:
                    result['guanshiqun'] = config.neirong or ''
                    result['guanshiqunid'] = config.qunid or ''

            return result

        except Exception:
            return {
                'dashouqun': '',
                'dashouqunid': '',
                'guanshiqun': '',
                'guanshiqunid': ''
            }


# views/weixin_official.py - 完整文件
import hashlib
import time
import logging
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
from django.utils import timezone
from xml.etree import ElementTree as ET
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.conf import settings
from .models import OfficialAccountUser

logger = logging.getLogger(__name__)



class WeixinOfficialCallbackView(APIView):
    """
    微信服务号回调接口
    处理用户关注、取消关注等事件
    核心：有关注事件就存，不管有没有UnionID
    """
    throttle_classes = []
    permission_classes = [AllowAny]
    authentication_classes = []

    def get(self, request):
        """验证服务器配置（微信官方要求）"""
        try:
            signature = request.GET.get('signature', '')
            timestamp = request.GET.get('timestamp', '')
            nonce = request.GET.get('nonce', '')
            echostr = request.GET.get('echostr', '')

            token = getattr(settings, 'WEIXIN_OFFICIAL_TOKEN', '')

            if not token:
                logger.error("服务号Token未配置")
                return HttpResponse('Token not configured', status=500)

            # 验证签名
            tmp_list = sorted([token, timestamp, nonce])
            tmp_str = ''.join(tmp_list)
            hash_str = hashlib.sha1(tmp_str.encode()).hexdigest()

            if hash_str == signature:
                return HttpResponse(echostr)
            else:
                logger.error(f"签名验证失败")
                return HttpResponse('Signature verification failed', status=403)

        except Exception as e:
            logger.error(f"验证服务器异常: {str(e)}")
            return HttpResponse('Internal Server Error', status=500)

    def post(self, request):
        """处理事件推送（关注、取关）"""
        try:
            xml_str = request.body.decode('utf-8')
            logger.info(f"收到服务号事件，原始数据（前200字符）: {xml_str[:200]}")

            root = ET.fromstring(xml_str)

            msg_type = root.find('MsgType').text
            from_user = root.find('FromUserName').text  # 服务号OpenID

            if msg_type == 'event':
                event = root.find('Event').text

                if event == 'subscribe':
                    return self.handle_subscribe_event(root, from_user)
                elif event == 'unsubscribe':
                    return self.handle_unsubscribe_event(root, from_user)
                else:
                    # 其他事件（如菜单点击）直接返回success
                    return HttpResponse('success')

            # 非事件消息也直接返回success
            return HttpResponse('success')

        except Exception as e:
            logger.error(f"处理服务号事件异常: {str(e)}", exc_info=True)
            # 即使异常也返回success，避免微信服务器重试
            return HttpResponse('success')

    def handle_subscribe_event(self, root, from_user):
        """处理用户关注事件 - 简化版：有就存，没有拉倒"""
        try:
            # 尝试获取UnionID（有就有，没有也没关系）
            unionid_elem = root.find('UnionId')
            unionid = unionid_elem.text if unionid_elem is not None else None

            logger.info(f"用户关注，OpenID: {from_user}, UnionID: {unionid}")

            # 核心逻辑：更新或创建记录
            obj, created = OfficialAccountUser.objects.update_or_create(
                official_openid=from_user,
                defaults={
                    'unionid': unionid,
                    'is_subscribed': True,
                    'subscribe_time': timezone.now()
                }
            )

            action = "新建" if created else "更新"
            logger.info(f"{action}用户记录成功: OpenID={from_user}")

            # 回复欢迎消息（可选）
            return self.generate_text_response(root, "感谢关注星阙网络服务！平台有新订单时您会收到通知。")

        except Exception as e:
            logger.error(f"处理关注事件异常: {str(e)}", exc_info=True)
            # 依然返回success，不让微信重试
            return HttpResponse('success')

    def handle_unsubscribe_event(self, root, from_user):
        """处理用户取消关注事件 - 简化版：标记为未订阅"""
        try:
            updated_count = OfficialAccountUser.objects.filter(
                official_openid=from_user
            ).update(is_subscribed=False)

            if updated_count > 0:
                logger.info(f"用户取消关注，已标记为未订阅: {from_user}")
            else:
                logger.info(f"用户取消关注，但记录不存在（无需处理）: {from_user}")

            return HttpResponse('success')

        except Exception as e:
            logger.error(f"处理取消关注事件异常: {str(e)}", exc_info=True)
            return HttpResponse('success')

    def generate_text_response(self, root, content):
        """生成文本消息响应"""
        try:
            to_user = root.find('ToUserName').text
            from_user = root.find('FromUserName').text

            response_xml = f"""<xml>
<ToUserName><![CDATA[{from_user}]]></ToUserName>
<FromUserName><![CDATA[{to_user}]]></FromUserName>
<CreateTime>{int(time.time())}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[{content}]]></Content>
</xml>"""

            return HttpResponse(response_xml, content_type='application/xml')

        except Exception as e:
            logger.error(f"生成回复消息异常: {str(e)}")
            # 即使生成回复失败，也返回一个空的success
            return HttpResponse('success')




# yonghu/views.py
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
from rest_framework import permissions
from django.db import transaction
from rest_framework.response import Response
from rest_framework import status
from rest_framework.views import APIView
from .models import UserMain, UserBoss, UserDashou, UserShangjia, UserGuanshi
from utils.oss_utils import validate_image, upload_to_oss, delete_from_oss
import os
import uuid



class UserInfoUpdateView(APIView):
    """
    用户个人信息修改接口

    功能：
      - 上传 / 更新头像
      - 修改昵称
      - 更新手机号（支持明文 phone 或微信 getPhoneNumber 组件返回的 shoujihao_code）
        当传 shoujihao_code 时，会通过微信接口解密得到真实手机号并自动设置 shoujihao_renzheng=True
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        """
        处理 POST 请求，支持 multipart/form-data 格式
        """
        try:
            # ---------- 获取当前用户 ----------
            user_main = request.user

            # ---------- 获取或创建老板扩展表记录 ----------
            try:
                user_boss = UserBoss.objects.get(user=user_main)
            except UserBoss.DoesNotExist:
                user_boss = UserBoss.objects.create(user=user_main, nickname='微信用户')

            response_data = {}

            # ==================== 1. 处理头像上传 ====================
            avatar_file = request.FILES.get('avatar')
            if avatar_file:
                # 验证图片格式 / 大小
                is_valid, error_msg = validate_image(avatar_file)
                if not is_valid:
                    return Response({
                        'code': 1,
                        'msg': f'图片验证失败: {error_msg}',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                # 上传头像到 OSS / COS
                avatar_url = self.handle_avatar_upload(user_main, avatar_file)
                if avatar_url:
                    response_data['touxiang'] = avatar_url
                    user_main.avatar = avatar_url
                else:
                    return Response({
                        'code': 2,
                        'msg': '头像上传失败',
                        'data': None
                    }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # ==================== 2. 处理昵称更新 ====================
            nicheng = request.data.get('nicheng')
            if nicheng is not None:
                nicheng = str(nicheng).strip()
                if nicheng:
                    if len(nicheng) > 20:
                        return Response({
                            'code': 3,
                            'msg': '昵称不能超过20个字符',
                            'data': None
                        }, status=status.HTTP_400_BAD_REQUEST)

                    user_boss.nickname = nicheng
                    response_data['nicheng'] = nicheng

            # ==================== 3. 处理手机号更新 ====================
            phone =None

            shoujihao_code = request.data.get('shoujihao_code')   # 微信手机号快速验证组件返回的临时 code

            if shoujihao_code:
                # 如果前端传了 shoujihao_code，则通过微信接口解密得到真实手机号
                try:
                    phone = self._get_phone_by_code(shoujihao_code)
                    logger.info(f"手机号解密成功: {phone}")
                except Exception as e:
                    logger.error(f"手机号解密失败: {str(e)}")
                    return Response({
                        'code': 6,
                        'msg': f'获取手机号失败: {str(e)}',
                        'data': None
                    }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            if phone is not None:
                phone = str(phone).strip()
                if phone:
                    # 验证手机号格式（11 位数字）
                    if not phone.isdigit() or len(phone) != 11:
                        return Response({
                            'code': 4,
                            'msg': '请输入11位有效的手机号码',
                            'data': None
                        }, status=status.HTTP_400_BAD_REQUEST)

                    # 更新主表手机号，并标记手机号已认证
                    user_main.phone = phone
                    user_main.shoujihao_renzheng = True
                    response_data['phone'] = phone

            # ==================== 4. 检查是否有任何更新 ====================
            if not response_data:
                return Response({
                    'code': 5,
                    'msg': '没有需要更新的数据',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # ==================== 5. 事务保存 ====================
            with transaction.atomic():
                user_main.save()
                user_boss.save()

            # ==================== 6. 返回成功 ====================
            return Response({
                'code': 0,
                'msg': '更新成功',
                'data': response_data
            })

        except Exception as e:
            logger.exception("用户信息更新异常")
            return Response({
                'code': 99,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    # ==================== 原有方法：头像上传 ====================
    def handle_avatar_upload(self, user_main, avatar_file):
        """
        上传头像到 OSS / COS，并返回存储的相对路径
        """
        try:
            yonghuid = user_main.yonghuid
            if not yonghuid:
                logger.warning("用户 ID 为空，无法上传头像")
                return None

            # 获取旧头像，用于后续删除
            old_avatar_url = user_main.avatar

            # 生成新文件名
            file_extension = os.path.splitext(avatar_file.name)[1].lower()
            if not file_extension:
                file_extension = '.jpg'
            unique_filename = f"{uuid.uuid4().hex}{file_extension}"

            # OSS 文件路径：avatar/{yonghuid}/{filename}
            avatar_folder = 'avatar'
            oss_file_path = f"{avatar_folder}/{yonghuid}/{unique_filename}"

            # 删除旧头像（如果存在）
            if old_avatar_url and old_avatar_url.strip():
                delete_from_oss(old_avatar_url)

            # 上传新头像
            new_avatar_url = upload_to_oss(avatar_file, oss_file_path)
            if new_avatar_url:
                logger.info(f"头像上传成功: {oss_file_path}")
                return oss_file_path
            else:
                logger.error("头像上传失败，upload_to_oss 返回 None")
                return None

        except Exception as e:
            logger.exception("处理头像上传失败")
            return None

    # ==================== 新增方法：微信接口相关 ====================

    def _get_access_token(self):
        """
        获取微信小程序全局 access_token，带缓存
        access_token 有效期 7200 秒，提前 300 秒过期
        """
        import requests
        from django.core.cache import cache

        # 尝试从缓存中读取
        token = cache.get('wechat_access_token')
        if token:
            return token

        # 从 settings 读取 AppID 和 AppSecret
        appid = getattr(settings, 'WEIXIN_APPID', None)
        secret = getattr(settings, 'WEIXIN_SECRET', None)
        if not appid or not secret:
            raise ValueError(
                'settings.py 中缺少 WECHAT_APPID 或 WECHAT_APPSECRET，'
                '请添加:\n'
                "WECHAT_APPID = 'wx0e4be86faac4a8d1'\n"
                "WECHAT_APPSECRET = '你的小程序密钥'"
            )

        url = 'https://api.weixin.qq.com/cgi-bin/token'
        params = {
            'grant_type': 'client_credential',
            'appid': appid,
            'secret': secret
        }
        try:
            resp = requests.get(url, params=params)
            data = resp.json()
        except Exception as e:
            raise Exception(f'请求微信 access_token 接口异常: {str(e)}')

        if 'access_token' in data:
            token = data['access_token']
            # 缓存时间设 7100 秒，提前 5 分钟过期
            cache.set('wechat_access_token', token, timeout=7100)
            logger.info("成功获取微信 access_token")
            return token
        else:
            errcode = data.get('errcode')
            errmsg = data.get('errmsg')
            logger.error(f"获取 access_token 失败: errcode={errcode}, errmsg={errmsg}")
            raise Exception(f"获取 access_token 失败: {errmsg}")

    def _get_phone_by_code(self, code):
        """
        通过微信手机号快速验证组件返回的 code 换取真实手机号
        接口文档：https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-info/phone-number/getPhoneNumber.html
        """
        import requests

        # 先获取有效的 access_token
        access_token = self._get_access_token()

        # 构建请求 URL
        url = f'https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={access_token}'

        # 请求体：code 必须放在 JSON 中
        payload = {'code': code}

        try:
            resp = requests.post(url, json=payload, timeout=10)
            data = resp.json()
        except Exception as e:
            raise Exception(f'请求微信手机号解密接口异常: {str(e)}')

        errcode = data.get('errcode')
        if errcode == 0:
            phone_info = data.get('phone_info', {})
            pure_phone = phone_info.get('purePhoneNumber')
            if not pure_phone:
                raise Exception('手机号为空，可能用户未授权真实手机号')
            return pure_phone
        else:
            errmsg = data.get('errmsg')
            logger.error(f"手机号解密失败: errcode={errcode}, errmsg={errmsg}")
            raise Exception(f'微信接口错误 (errcode={errcode}): {errmsg}')


# yonghu/views.py 或 yonghu/api_views.py

from django.utils import timezone
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework import status
from .models import UserMain, UserDashou
from shangpin.models import Huiyuangoumai, Gsfenhong  # 需要导入会员模型
import logging


class DashouXinxiAPIView(APIView):
    """
    获取打手信息接口
    请求方式：POST
    认证方式：JWT Token
    返回：打手基本信息、资产信息、会员信息，金牌打手额外返回专属字段
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取当前登录用户
            current_user = request.user
            yonghuid = current_user.yonghuid

            # 2. 查询打手扩展表
            try:
                dashou_profile = current_user.dashou_profile
            except UserDashou.DoesNotExist:
                return Response({
                    'code': 400,
                    'message': '您不是打手身份',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 构建基础信息响应（原有字段完全保留）
            data = {
                'dashounicheng': dashou_profile.nicheng or '',
                'zhanghaostatus': dashou_profile.zhanghaozhuangtai,
                'zaixianzhuangtai': dashou_profile.zaixianzhuangtai,
                'dashouzhuangtai': dashou_profile.zhuangtai,
                'yongjin': str(dashou_profile.yue) if dashou_profile.yue is not None else '0.00',
                'zonge': str(dashou_profile.zonge) if dashou_profile.zonge is not None else '0.00',
                'yajin': str(dashou_profile.yajin) if dashou_profile.yajin is not None else '0.00',
                'chengjiaoliang': dashou_profile.chengjiaozongliang,
                'jiedanZongliang': dashou_profile.jiedanzongliang if dashou_profile.jiedanzongliang is not None else '0',
                'jifen': dashou_profile.jifen,
                'zuijinTixian': str(dashou_profile.jinritixian_jine) if dashou_profile.jinritixian_jine is not None else '0.00',
                'chenghao': dashou_profile.chenghao or '',

            }

            # 4. 查询会员信息（原有逻辑）
            huiyuan_list = []
            try:
                huiyuan_records = Huiyuangoumai.objects.filter(
                    yonghu_id=yonghuid
                ).select_related()

                for record in huiyuan_records:
                    # 检查会员是否过期
                    is_expired = record.jiance_shifou_daoqi()

                    # 只返回未过期的会员（huiyuan_zhuangtai = 1）
                    if record.huiyuan_zhuangtai == 1:
                        huiyuan_list.append({
                            'huiyuanid': record.huiyuan_id,
                            'huiyuanming': record.jieshao or f"会员{record.huiyuan_id}",
                            'daoqi': record.daoqi_time
                        })
            except Exception as e:
                # 会员信息查询失败不影响主要功能，返回空列表
                huiyuan_list = []

            data['clumber'] = huiyuan_list

            # 5. 如果是金牌打手，添加专属字段
            if dashou_profile.chenghao == "金牌打手":
                data.update({
                    'jiedanZongliang': dashou_profile.jiedanzongliang,          # 接单总量
                    'jinriJiedan': str(dashou_profile.jinrishouyi) if dashou_profile.jinrishouyi is not None else '0.00',  # 今日接单金额
                    'zuijinTixian': str(dashou_profile.jinritixian_jine) if dashou_profile.jinritixian_jine is not None else '0.00',  # 最近提现金额（今日已提现）
                })

            # 6. 返回成功响应
            return Response({
                'code': 200,
                'message': '获取成功',
                'data': data
            }, status=status.HTTP_200_OK)

        except Exception as e:
            # 生产环境应使用 logging 记录错误，而不是 print
            # logger.error(f"获取打手信息失败: {e}", exc_info=True)
            return Response({
                'code': 500,
                'message': f'服务器内部错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


# yonghu/views.py 或 yonghu/api_views.py

class ZaixianZhuangtaiAPIView(APIView):
    """
    更改打手在线状态接口
    请求方式：POST
    认证方式：JWT Token
    请求参数：status（0=离线，1=在线）
    返回：更新后的状态信息
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取请求参数
            new_status = request.data.get('status')

            if new_status is None:
                return Response({
                    'code': 400,
                    'message': '缺少状态参数',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 转换为整数，确保是0或1
            try:
                new_status = int(new_status)
                if new_status not in [0, 1]:
                    return Response({
                        'code': 400,
                        'message': '状态参数必须是0或1',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)
            except ValueError:
                return Response({
                    'code': 400,
                    'message': '状态参数必须是整数',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 2. 获取当前登录用户
            current_user = request.user
            yonghuid = current_user.yonghuid



            # 3. 查询打手扩展表
            try:
                dashou_profile = current_user.dashou_profile
            except UserDashou.DoesNotExist:

                return Response({
                    'code': 400,
                    'message': '您不是打手身份',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 4. 检查账号状态（是否被封禁）
            if dashou_profile.zhanghaozhuangtai != 1:

                return Response({
                    'code': 403,
                    'message': '账号状态异常，无法更改在线状态',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 5. 更新在线状态
            old_status = dashou_profile.zaixianzhuangtai

            # 如果状态没有变化，直接返回成功
            if old_status == new_status:

                return Response({
                    'code': 200,
                    'message': '状态未变化',
                    'data': {
                        'zaixianzhuangtai': new_status,
                        'status_text': '在线' if new_status == 1 else '离线'
                    }
                }, status=status.HTTP_200_OK)

            # 更新状态
            dashou_profile.zaixianzhuangtai = new_status
            dashou_profile.save()



            # 6. 返回成功响应
            return Response({
                'code': 200,
                'message': '状态更新成功',
                'data': {
                    'zaixianzhuangtai': new_status,
                    'status_text': '在线' if new_status == 1 else '离线'
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:

            return Response({
                'code': 500,
                'message': f'服务器内部错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)



from shangpin.models import Gsfenhong  # 需要导入会员模型
class GuanshiXinxiView(APIView):
    """
    获取管事信息接口
    路径：/yonghu/guanshixinxi
    方法：POST
    权限：JWT认证
    功能：获取当前管事的详细信息，包括基本信息、分红信息以及已充值打手数量
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 获取当前用户（通过JWT认证）
            current_user = request.user

            # 查询管事扩展表
            try:
                guanshi_profile = UserGuanshi.objects.get(user=current_user)

                # 🔥【新增】查询已充值打手数量（从分红表中统计）
                # Gsfenhong 表中 guanshi 字段存储管事ID（yonghuid）
                yichongzhi_count = Gsfenhong.objects.filter(guanshi=current_user.yonghuid).count()

                # 返回管事信息
                return Response({
                    'code': 200,
                    'msg': '获取成功',
                    'data': {
                        'gszhstatus': guanshi_profile.zhuangtai,                 # 管事账号状态
                        'yaoqingzongshu': guanshi_profile.yaogingshuliang,       # 邀请打手总数
                        'fenyongzonge': float(guanshi_profile.chongzhifenrun),   # 充值分佣总额
                        'fenyongtixian': float(guanshi_profile.yue),             # 可提现余额
                        'yichongzhiDashou': yichongzhi_count,                    # 已充值打手数量
                    }
                })

            except UserGuanshi.DoesNotExist:
                # 用户不是管事，返回错误
                return Response({
                    'code': 400,
                    'msg': '您还不是管事，请先注册',
                    'data': None
                }, status=400)

        except Exception as e:
            # 捕获所有异常，返回错误信息并记录日志
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"获取管事信息异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'msg': f'获取信息失败: {str(e)}',
                'data': None
            }, status=500)




# yonghu/views.py

from rest_framework import status
from django.core.exceptions import ObjectDoesNotExist




from django.db.models import Sum
from houtai.models import ShangjiaRiTongji        # 商家日统计表
class ShangJiaXinXiView(APIView):
    """
    获取商家信息接口 (POST /yonghu/shangjiaxinxi)
    权限：需JWT认证
    返回：商家基本信息 + 称号列表 + 今日/本月统计
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 获取商家扩展资料
            shangjia = request.user.shop_profile
        except ObjectDoesNotExist:
            return Response({
                'code': 4001,
                'msg': '您还未注册成为商家或商家资料不存在',
                'data': None
            }, status=status.HTTP_200_OK)

        user = request.user
        yonghuid = user.yonghuid
        today = timezone.now().date()
        this_month_start = today.replace(day=1)

        # ------------------- 1. 从 UserShangjia 获取基础字段 -------------------
        response_data = {
            'sjzhzhuangtai': shangjia.zhuangtai,      # 商家账号状态
            'fadanzong': shangjia.fabu,               # 发单总量（累计）
            'tuikuanzong': shangjia.tuikuan,          # 退款总量（累计）
            'sjyue': float(shangjia.yue),             # 商家余额
            # 'riliushui' 和 'yueliushui' 将从统计表计算，不再使用原字段
        }

        # ------------------- 2. 获取称号列表（仅限商家称号） -------------------
        chenghao_list = []
        # 查询当前用户的所有称号关联
        yonghu_chenghao_qs = YonghuChenghao.objects.filter(yonghu=user).select_related('chenghao')
        for yc in yonghu_chenghao_qs:
            chenghao_obj = yc.chenghao
            # 只保留类型为“商家”的称号
            if chenghao_obj.leixing == 'shangjia':
                chenghao_list.append({
                    'mingcheng': chenghao_obj.mingcheng,
                    'texiao_json': chenghao_obj.texiao_miaoshu,  # 前端需要的特效描述
                    # 如果还需要其他字段（如图标URL）可在此添加，打手端有 texiao_json
                })
        response_data['chenghao_list'] = chenghao_list

        # ------------------- 3. 从 ShangjiaRiTongji 获取今日统计 -------------------
        try:
            today_stat = ShangjiaRiTongji.objects.get(yonghuid=yonghuid, riqi=today)
            jinri_paifa_dingdan = today_stat.paifa_dingdan_shu
            jinri_paifa_jine = float(today_stat.paifa_jine)
            jinri_tuikuan_dingdan = today_stat.tuikuan_dingdan_shu
        except ShangjiaRiTongji.DoesNotExist:
            jinri_paifa_dingdan = 0
            jinri_paifa_jine = 0.00
            jinri_tuikuan_dingdan = 0

        response_data['jinripaidan'] = jinri_paifa_dingdan          # 今日派单数（新增）
        response_data['jinrituikuan'] = jinri_tuikuan_dingdan       # 今日退款数（新增）
        response_data['riliushui'] = jinri_paifa_jine               # 今日流水（派发总金额）

        # ------------------- 4. 从 ShangjiaRiTongji 获取本月统计 -------------------
        month_stats = ShangjiaRiTongji.objects.filter(
            yonghuid=yonghuid,
            riqi__gte=this_month_start,
            riqi__lte=today
        ).aggregate(
            total_paifa_jine=Sum('paifa_jine'),
            total_paifa_dingdan=Sum('paifa_dingdan_shu')
        )
        yue_paifa_jine = float(month_stats.get('total_paifa_jine') or 0.00)
        # yue_paifa_dingdan = month_stats.get('total_paifa_dingdan') or 0  # 如果前端不需要可不加

        response_data['yueliushui'] = yue_paifa_jine                # 今月流水（派发总金额）

        # （可选）如果前端还需要今月派单总数，取消下面注释
        # response_data['jinyuepaidan'] = yue_paifa_dingdan

        return Response({
            'code': 200,
            'msg': '获取商家信息成功',
            'data': response_data
        }, status=status.HTTP_200_OK)




'''class ShangJiaXinXiView(APIView):
    """
    获取商家信息接口 (POST /yonghu/shangjiaxinxi)
    权限：需JWT认证
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 关键：使用 get() 方法。如果反向关联不存在，会抛出 UserShangjia.DoesNotExist 异常。
            shangjia = request.user.shop_profile
            # 如果反向关系存在，但你想更显式地查询，也可以这样写（效果相同）：
            # shangjia = UserShangjia.objects.get(user=request.user)

        except ObjectDoesNotExist:
            # 捕获“不存在”异常，说明当前用户还没有商家扩展资料
            return Response({
                'code': 4001,  # 你可以定义特定的业务错误码
                'msg': '您还未注册成为商家或商家资料不存在',
                'data': None
            }, status=status.HTTP_200_OK) # 业务错误，HTTP状态码通常仍用200

        # 构建返回给前端的数据
        response_data = {
            'sjzhzhuangtai': shangjia.zhuangtai,  # 商家账号状态
            'fadanzong': shangjia.fabu,            # 发单总量
            'tuikuanzong': shangjia.tuikuan,       # 退款总量
            'sjyue': float(shangjia.yue),          # 商家余额
            'riliushui': float(shangjia.jinriliushui),  # 今日流水
            'yueliushui': float(shangjia.jinyueliushui), # 今月流水
        }

        return Response({
            'code': 200,
            'msg': '获取商家信息成功',
            'data': response_data
        })'''




class BossBiaoshiView(APIView):
    """
    获取用户的GoEasy标识 - 极简实现
    POST /yonghu/bossbiaoshi
    需要JWT Token认证
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 1. 直接从request.user获取用户
        user = request.user

        # 2. 获取yonghuid（确保用户已登录）
        if not user or not hasattr(user, 'yonghuid'):
            return Response({
                'code': 401,
                'msg': '用户未认证或用户信息不完整'
            }, status=401)

        # 3. 生成标识：Boss + yonghuid（与前端约定）
        boss_biaoshi = f"Boss{user.yonghuid}"

        # 4. 返回给前端
        return Response({
            'code': 200,
            'msg': '获取成功',
            'data': {
                'boss_biaoshi': boss_biaoshi,
                'yonghuid': user.yonghuid,
                'user_type': user.user_type
            }
        })


"""
阿龙电竞陪玩平台 - 邀请码相关API接口
"""

from utils.yaoqingma_utils import chuangjianYaoqingma, yanzhengYaoqingmaWeiyixing


class YaoqingmaView(APIView):
    """
    获取或生成管事邀请码
    访问路径: /api/yonghu/yaoqingma/
    请求方法: GET
    权限要求: JWT Token认证通过的用户
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        """
        获取当前用户的邀请码
        逻辑:
          1. 通过JWT获取当前用户 (request.user)
          2. 反向查询UserGuanshi扩展表
          3. 验证管事状态(zhuangtai=1)
          4. 已有邀请码直接返回，没有则生成并保存
        """
        # 获取当前认证用户
        current_user = request.user

        # 1. 使用反向查询获取管事扩展信息 (性能最优方式)
        try:
            guanshi_profile = current_user.guanshi_profile
        except UserGuanshi.DoesNotExist:
            # 用户不是管事，没有扩展表记录
            return Response({
                'code': 403,
                'message': '当前用户不是管事身份，无法生成邀请码',
                'data': None
            }, status=status.HTTP_403_FORBIDDEN)

        # 2. 验证管事状态 (zhuangtai 必须等于 1)
        if guanshi_profile.zhuangtai != 1:
            return Response({
                'code': 403,
                'message': '管事账号状态异常，无法生成邀请码',
                'data': None
            }, status=status.HTTP_403_FORBIDDEN)

        # 3. 检查是否已存在邀请码
        existing_yaoqingma = guanshi_profile.yaoqingma

        # 如果存在且非空，直接返回
        if existing_yaoqingma and existing_yaoqingma.strip() != '':
            return Response({
                'code': 200,
                'message': '成功获取现有邀请码',
                'data': {
                    'yaoqingma': existing_yaoqingma,
                    'is_new': False  # 标记是否为新生成的
                }
            })

        # 4. 生成新的邀请码 (使用用户ID字符串)
        # 注意: 这里使用yonghuid，不是主键id，如你要求的"123456"这种形式
        yonghuid_str = str(current_user.yonghuid)
        new_yaoqingma = chuangjianYaoqingma(yonghuid_str)

        # 5. 验证生成的邀请码格式
        if not yanzhengYaoqingmaWeiyixing(new_yaoqingma):
            return Response({
                'code': 500,
                'message': '邀请码生成失败，格式验证错误',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # 6. 保存到数据库 (使用事务确保数据一致性)
        try:
            with transaction.atomic():
                guanshi_profile.yaoqingma = new_yaoqingma
                guanshi_profile.save()
        except Exception as e:
            # 这里可以记录日志
            return Response({
                'code': 500,
                'message': f'保存邀请码到数据库失败: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # 7. 返回新生成的邀请码
        return Response({
            'code': 200,
            'message': '成功生成新的邀请码',
            'data': {
                'yaoqingma': new_yaoqingma,
                'is_new': True  # 标记是新生成的
            }
        })



"""
阿龙电竞陪玩平台 - 打手注册及相关API接口
"""

from shangpin.models import Huiyuangoumai  # 导入会员购买模型
from utils.yaoqingma_utils import chuangjianYaoqingma  # 导入之前写的邀请码生成算法

import traceback

_dashou_zhuce_logger = logging.getLogger('yonghu.dashouzhuce')


class DashouZhuceView(APIView):
    """
    打手注册接口 (通过管事邀请码)
    访问路径: /api/yonghu/dashouzhuce/
    请求方法: POST
    权限要求: JWT Token认证通过的用户
    请求体: { "inviteCode": "AbC123..." }
    """
    permission_classes = [IsAuthenticated]

    def _log_dashou_zhuce_error(self, invite_code, yonghuid, exc):
        """500 时打印完整堆栈，便于排查（gunicorn/1panel 可抓 stderr）。"""
        err_text = traceback.format_exc()
        _dashou_zhuce_logger.exception(
            '打手注册失败 inviteCode=%s yonghuid=%s error=%s',
            invite_code, yonghuid, exc,
        )
        print(
            f'[DashouZhuce ERROR] inviteCode={invite_code} yonghuid={yonghuid} error={exc}\n{err_text}',
            flush=True,
        )

    def post(self, request):
        yaoqingma = ''
        current_user = request.user
        yonghuid = getattr(current_user, 'yonghuid', '')

        try:
            # 1. 获取并验证邀请码参数
            yaoqingma = request.data.get('inviteCode')
            if not yaoqingma:
                return Response({
                    'code': 400,
                    'message': '邀请码不能为空',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            yaoqingma = yaoqingma.strip()
            if len(yaoqingma) > 100:
                return Response({
                    'code': 400,
                    'message': '邀请码长度超过限制',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 2. 检查用户是否已是打手 (使用反向查询，性能最优)
            try:
                dashou_profile = current_user.dashou_profile
                # 用户已是打手，直接返回现有信息
                return self.fanhuiXianyouDashouXinxi(dashou_profile, current_user)
            except UserDashou.DoesNotExist:
                # 用户不是打手，继续注册流程
                pass

            # 3. 根据邀请码查找对应的管事
            try:
                guanshi_profile = UserGuanshi.objects.select_related('user').get(yaoqingma=yaoqingma)
            except UserGuanshi.DoesNotExist:
                return Response({
                    'code': 404,
                    'message': '邀请码无效或不存在',
                    'data': None
                }, status=status.HTTP_404_NOT_FOUND)

            # 4. 验证管事状态
            '''if guanshi_profile.zhuangtai != 1:
                return Response({
                    'code': 403,
                    'message': '该邀请码对应的管事账号已被禁用',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)'''

            # 5. 核心：在数据库事务中创建用户的所有身份
            with transaction.atomic():
                guanshi_yonghuid = guanshi_profile.user.yonghuid

                dashou_profile = UserDashou.objects.create(
                    user=current_user,
                    nicheng='大手子',
                    chenghao='普通大手',
                    yaoqingren=guanshi_yonghuid,
                )

                locked_guanshi = UserGuanshi.objects.select_for_update().get(pk=guanshi_profile.pk)
                locked_guanshi.yaogingshuliang += 1
                locked_guanshi.save()

                # 管事每日统计（邀请打手）— 失败不影响注册主流程
                try:
                    from decimal import Decimal
                    from houtai.utils import update_guanshi_daily_by_action
                    update_guanshi_daily_by_action(
                        yonghuid=guanshi_yonghuid,
                        action=1,
                        amount=Decimal('0.00')
                    )
                    _dashou_zhuce_logger.info('管事每日统计更新成功（邀请打手）：管事%s', guanshi_yonghuid)
                except Exception as stat_err:
                    _dashou_zhuce_logger.warning('管事每日统计更新失败（邀请打手）：%s', stat_err)

            # 6. 注册成功，返回信息
            fanhui_data = self.zhuangbeiFanhuiShuju(dashou_profile, current_user, is_new=True)
            return Response({
                'code': 200,
                'message': '注册成功！已开通打手、商家、管事身份。',
                'data': fanhui_data
            })

        except Exception as e:
            self._log_dashou_zhuce_error(yaoqingma, yonghuid, e)
            return Response({
                'code': 500,
                'message': f'注册过程中发生系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def fanhuiXianyouDashouXinxi(self, dashou_profile, current_user):
        """处理已是打手的用户，返回其现有信息"""
        fanhui_data = self.zhuangbeiFanhuiShuju(dashou_profile, current_user, is_new=False)
        return Response({
            'code': 200,
            'message': '您已是打手，返回当前信息。',
            'data': fanhui_data
        })

    def zhuangbeiFanhuiShuju(self, dashou_profile, current_user, is_new=False):
        """准备返回给前端的打手数据，字段名严格匹配前端"""



        # 构建基础信息
        data = {
            'dashounicheng': dashou_profile.nicheng,
            'zhanghaostatus': dashou_profile.zhanghaozhuangtai,
            'yongjin': str(dashou_profile.yue),  # Decimal转字符串
            'zonge': str(dashou_profile.zonge),
            'yajin': str(dashou_profile.yajin),
            'chenghao': dashou_profile.chenghao,
            'jinfen': dashou_profile.jifen,
            'chengjiaoliang': dashou_profile.chengjiaozongliang,
            'zaixianzhuangtai': dashou_profile.zaixianzhuangtai,
            'dashouzhuangtai': dashou_profile.zhuangtai,
        }

        # 查询并处理会员列表 (clumber)
        # 使用当前用户的yonghuid进行查询
        huiyuan_goumai_list = []
        if not is_new:  # 如果是新用户，直接返回空列表，无需查询
            goumai_records = Huiyuangoumai.objects.filter(yonghu_id=current_user.yonghuid)
            for record in goumai_records:
                # 调用方法检查是否到期，此方法内部会更新状态
                shifou_daoqi = record.jiance_shifou_daoqi()
                huiyuan_goumai_list.append({
                    'huiyuan_id': record.huiyuan_id,
                    'huiyuan_zhuangtai': record.huiyuan_zhuangtai,
                    'daoqi_time': record.daoqi_time.isoformat() if record.daoqi_time else None,
                    'shifou_daoqi': shifou_daoqi,
                    'jieshao': record.jieshao
                })

        data['clumber'] = huiyuan_goumai_list
        return data




from django.core.paginator import Paginator, EmptyPage


'''class GuanshiYaoqingDashouListView(APIView):
    """
    管事获取邀请的打手列表接口
    访问路径: /api/yonghu/gshqyqds/
    请求方法: POST
    权限要求: JWT Token认证通过的用户（管事）
    请求体: {
        "page": 1,      // 当前页码（从1开始）
        "pageSize": 30  // 每页条数
    }
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        """
        获取当前管事邀请的打手列表（分页）
        """
        try:
            current_user = request.user

            # 1. 获取并验证分页参数
            page = int(request.data.get('page', 1))
            page_size = int(request.data.get('pageSize', 30))

            if page < 1 or page_size < 1:
                return Response({
                    'code': 400,
                    'message': '分页参数必须大于0',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 限制每页最大数量，防止恶意请求
            if page_size > 100:
                page_size = 100

            # 2. 获取当前管事的用户ID（yonghuid）
            guanshi_yonghuid = current_user.yonghuid

            with transaction.atomic():
                # 3. 【性能关键】联表查询：一次性获取打手扩展表及其关联的主表信息
                # 使用 select_related('user') 将打手表和用户主表在SQL层进行JOIN，避免N+1查询
                # 过滤条件：打手表的邀请人ID(yaoqingren)等于当前管事的用户ID
                dashou_queryset = UserDashou.objects.select_related('user').filter(
                    yaoqingren=guanshi_yonghuid
                ).order_by('-create_time')  # 按创建时间倒序，最新的在前面

                # 4. 使用Django分页器进行分页（比手动切片更规范，能自动处理异常页码）
                paginator = Paginator(dashou_queryset, page_size)

                try:
                    current_page_data = paginator.page(page)
                except EmptyPage:
                    # 如果请求的页码超出范围，返回空列表
                    current_page_data = []
                    has_more = False
                    total_count = len(dashou_queryset)
                else:
                    # 计算是否还有更多数据
                    has_more = current_page_data.has_next()
                    total_count = paginator.count

                # 5. 构建打手列表数据
                dashou_list = []
                for dashou in current_page_data:
                    # 直接从联表查询结果中获取主表信息（dashou.user）
                    user_main = dashou.user

                    dashou_list.append({
                        'uid': user_main.yonghuid,  # 从主表获取用户ID
                        'nicheng': dashou.nicheng or '打手子',  # 打手昵称
                        'zaixianzhuangtai': dashou.zaixianzhuangtai,  # 在线状态
                        'zhanghaozhuangtai': dashou.zhanghaozhuangtai,  # 账号状态
                        'touxiang': user_main.avatar or '',  # 头像相对URL（前端需拼接OSS地址）
                        # 以下为额外信息，前端可能显示在卡片上
                        'jiedanzongliang': dashou.jiedanzongliang,  # 接单总量
                        'chengjiaozongliang': dashou.chengjiaozongliang,  # 成交总量
                        'yue': str(dashou.zonge),  # 可提现余额（Decimal转字符串）
                    })

                # 6. 获取管事的邀请总数（从管事扩展表获取）
                try:
                    guanshi_profile = current_user.guanshi_profile
                    yaoqingzongshu = guanshi_profile.yaogingshuliang
                except:
                    # 如果获取失败（理论上不会，因为用户已登录且是管事），则从查询结果计数
                    yaoqingzongshu = total_count

                # 7. 构建响应数据
                response_data = {
                    'dashouList': dashou_list,  # 打手列表
                    'yaoqingzongshu': yaoqingzongshu,  # 邀请打手总数
                    'currentPage': page,  # 当前页码
                    'pageSize': page_size,  # 每页条数
                    'totalCount': total_count,  # 符合条件的总记录数
                    'hasMore': has_more,  # 是否还有更多数据（前端据此决定是否显示"上拉加载"）
                }

                return Response({
                    'code': 200,
                    'message': '获取成功',
                    'data': response_data
                })

        except ValueError:
            # 分页参数转换错误
            return Response({
                'code': 400,
                'message': '分页参数格式错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            # 记录详细的异常信息，便于调试
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f'获取打手列表失败: {str(e)}', exc_info=True)

            return Response({
                'code': 500,
                'message': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)'''




class HuoQuYaoQingRenView(APIView):
    """
    获取当前打手的邀请人信息
    POST /yonghu/hqwdyqr
    Headers: Authorization: Bearer <token>
    返回邀请人的用户ID、昵称（来自老板扩展表）、头像相对URL
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            current_user = request.user                     # 当前登录用户
            yonghuid = current_user.yonghuid                # 7位用户ID

            # 1. 校验打手身份及账号状态（只检查账号状态，不检查接单状态）
            try:
                dashou = UserDashou.objects.get(user=current_user)
                if dashou.zhanghaozhuangtai != 1:
                    return Response({
                        'code': 403,
                        'message': '您的账号已被封禁，无法查看邀请人',
                        'data': None
                    })
            except UserDashou.DoesNotExist:
                return Response({
                    'code': 404,
                    'message': '您还不是打手，无法查看邀请人',
                    'data': None
                })

            # 2. 获取邀请人ID
            yaoqingren_id = dashou.yaoqingren
            if not yaoqingren_id:
                return Response({
                    'code': 404,
                    'message': '您没有邀请人',
                    'data': None
                })

            # 3. 查询邀请人主表（头像）
            try:
                inviter_main = UserMain.objects.get(yonghuid=yaoqingren_id)
                touxiang = inviter_main.avatar or ''
            except UserMain.DoesNotExist:
                return Response({
                    'code': 404,
                    'message': '邀请人信息不存在',
                    'data': None
                })

            # 4. 查询老板扩展表（昵称），如果没有则使用空字符串
            nicheng = ''
            try:
                boss = UserBoss.objects.get(user=inviter_main)
                nicheng = boss.nickname or ''
            except UserBoss.DoesNotExist:
                pass  # 邀请人可能不是老板，昵称留空

            response_data = {
                'uid': yaoqingren_id,
                'nicheng': nicheng,
                'touxiang': touxiang                   # 相对路径，前端自行拼接
            }

            return Response({
                'code': 200,
                'message': '获取成功',
                'data': response_data
            })

        except Exception as e:
            logger.error(f'获取邀请人失败: {str(e)}', exc_info=True)
            return Response({
                'code': 500,
                'message': '系统繁忙，请稍后重试',
                'data': None
            })

class GuanshiYaoqingDashouListView(APIView):
    """
    管事获取已邀请打手列表（支持筛选、搜索、分页）
    POST /api/yonghu/gshqyqds/
    Headers: Authorization: Bearer <token>
    Body:
    {
        "page": 1,                // 页码，从1开始
        "pageSize": 30,           // 每页条数，最大100
        "keyword": "",            // 搜索关键词（用户ID或昵称）
        "zhanghaozhuangtai": 1,  // 账号状态：1=正常，2=封禁（可选）
        "zaixianzhuangtai": 1    // 在线状态：1=在线，2=离线（可选）
    }
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            current_user = request.user
            guanshi_yonghuid = current_user.yonghuid

            # 1. 分页参数
            page = int(request.data.get('page', 1))
            page_size = int(request.data.get('pageSize', 30))
            if page < 1 or page_size < 1:
                return Response({'code': 400, 'message': '分页参数必须大于0'}, status=400)
            if page_size > 100:
                page_size = 100

            # 2. 筛选参数
            keyword = request.data.get('keyword', '').strip()
            zhanghaozhuangtai = request.data.get('zhanghaozhuangtai')  # 可选：1=正常，2=封禁
            zaixianzhuangtai = request.data.get('zaixianzhuangtai')    # 可选：1=在线，2=离线

            # 3. 基础查询：当前管事邀请的所有打手
            base_qs = UserDashou.objects.select_related('user').filter(
                yaoqingren=guanshi_yonghuid
            )

            # 4. 全局统计（不受筛选影响，直接基于 base_qs）
            total_all = base_qs.count()
            zaixian_all = base_qs.filter(zaixianzhuangtai=1).count()
            zhengchang_all = base_qs.filter(zhanghaozhuangtai=1).count()
            fengjin_all = total_all - zhengchang_all

            # 5. 应用筛选条件
            if keyword:
                base_qs = base_qs.filter(
                    Q(nicheng__icontains=keyword) | Q(user__yonghuid__icontains=keyword)
                )
            if zhanghaozhuangtai is not None:
                try:
                    val = int(zhanghaozhuangtai)
                    if val == 1:
                        base_qs = base_qs.filter(zhanghaozhuangtai=1)
                    else:
                        base_qs = base_qs.exclude(zhanghaozhuangtai=1)
                except (ValueError, TypeError):
                    pass
            if zaixianzhuangtai is not None:
                try:
                    val = int(zaixianzhuangtai)
                    if val == 1:
                        base_qs = base_qs.filter(zaixianzhuangtai=1)
                    else:
                        base_qs = base_qs.exclude(zaixianzhuangtai=1)
                except (ValueError, TypeError):
                    pass

            # 6. 排序和分页
            base_qs = base_qs.order_by('-create_time')
            paginator = Paginator(base_qs, page_size)
            try:
                page_obj = paginator.page(page)
            except EmptyPage:
                page_obj = []
                has_more = False
                filtered_total = paginator.count if paginator.count else 0
            else:
                has_more = page_obj.has_next()
                filtered_total = paginator.count

            # 7. 构建打手列表
            dashou_list = []
            for dashou in page_obj:
                user_main = dashou.user
                dashou_list.append({
                    'uid': user_main.yonghuid,
                    'nicheng': dashou.nicheng or '打手',
                    'zaixianzhuangtai': dashou.zaixianzhuangtai,
                    'zhanghaozhuangtai': dashou.zhanghaozhuangtai,
                    'touxiang': user_main.avatar or '',
                    'jiedanzongliang': dashou.jiedanzongliang,
                    'chengjiaozongliang': dashou.chengjiaozongliang,
                    'tuikuanliang': dashou.tuikuanliang,
                    'yue': str(dashou.zonge),
                })

            # 8. 获取管事邀请总数（来自管事扩展表）
            try:
                yaoqingzongshu = current_user.guanshi_profile.yaogingshuliang
            except Exception:
                yaoqingzongshu = total_all

            response_data = {
                'dashouList': dashou_list,
                'yaoqingzongshu': yaoqingzongshu,      # 邀请总数（全局）
                'totalCount': filtered_total,           # 当前筛选条件下的总数
                'zaixianCount': zaixian_all,            # 全局在线
                'zhengchangCount': zhengchang_all,      # 全局正常
                'fengjinCount': fengjin_all,            # 全局封禁
                'currentPage': page,
                'pageSize': page_size,
                'hasMore': has_more,
            }

            return Response({'code': 200, 'message': '获取成功', 'data': response_data})

        except ValueError:
            return Response({'code': 400, 'message': '分页参数格式错误'}, status=400)
        except Exception as e:
            logger.error(f'获取打手列表失败: {str(e)}', exc_info=True)
            return Response({'code': 500, 'message': '系统错误'}, status=500)


from rest_framework.views import APIView
from rest_framework import permissions, status
from rest_framework.response import Response
from django.db import transaction
from .models import UserMain, UserDashou, UserGuanshi, Tixianjilu
import os
import uuid
from utils.oss_utils import validate_image, upload_to_oss, delete_from_oss

class TixianXinxiHuoquView(APIView):
    """
    获取用户提现收款信息接口
    返回用户已设置的手机号、收款码、收款账号
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        """
        处理获取收款信息的POST请求
        直接返回用户当前的收款设置
        """
        try:
            # 从request.user获取当前用户
            user_main = request.user

            # 🔥【修改开始 - 使用Decimal，字段名是lilu】
            # 查询打手提现费率 (fadanpingtai='5')
            dashou_rate_obj = Lilubiao.objects.filter(fadanpingtai='5').first()
            dashou_rate = decimal.Decimal(str(dashou_rate_obj.lilu)) if dashou_rate_obj else decimal.Decimal('0.00')

            # 查询管事提现费率 (fadanpingtai='6')
            guanshi_rate_obj = Lilubiao.objects.filter(fadanpingtai='6').first()
            guanshi_rate = decimal.Decimal(str(guanshi_rate_obj.lilu)) if guanshi_rate_obj else decimal.Decimal('0.00')
            # 🔥【修改结束】

            # 构建返回数据
            response_data = {
                'txdianhua': user_main.phone if user_main.phone else '',
                'txtupian': user_main.zhifu if user_main.zhifu else '',
                'txzh': user_main.skzhanghao if user_main.skzhanghao else '',
                # 🔥【修改开始】
                'dashou_rate': dashou_rate,   # 打手提现费率
                'guanshi_rate': guanshi_rate, # 管事提现费率
                # 🔥【修改结束】
            }

            # 返回成功响应
            return Response({
                'code': 0,
                'msg': '获取成功',
                'data': response_data
            })

        except Exception as e:
            return Response({
                'code': 99,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


'''class TixianXinxiHuoquView(APIView):
    """
    获取用户提现收款信息接口
    返回用户已设置的手机号、收款码、收款账号
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        """
        处理获取收款信息的POST请求
        直接返回用户当前的收款设置
        """
        try:
            # 从request.user获取当前用户
            user_main = request.user

            # 构建返回数据
            response_data = {
                'txdianhua': user_main.phone if user_main.phone else '',
                'txtupian': user_main.zhifu if user_main.zhifu else '',
                'txzh': user_main.skzhanghao if user_main.skzhanghao else ''
            }

            # 返回成功响应
            return Response({
                'code': 0,
                'msg': '获取成功',
                'data': response_data
            })

        except Exception as e:
            return Response({
                'code': 99,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


from rest_framework.parsers import MultiPartParser, FormParser'''


class ShoukuanXinxiShangchuanView(APIView):
    """
    上传用户收款信息接口
    支持同时上传手机号、收款账号、收款码图片
    使用multipart/form-data格式
    """
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser,JSONParser)

    def post(self, request):
        """
        处理上传收款信息的POST请求
        验证并保存用户的收款设置
        """
        try:
            # 获取当前用户
            user_main = request.user
            yonghuid = user_main.yonghuid

            # 准备响应数据
            response_data = {}

            # 1. 验证必填字段：手机号必须要有
            txdianhua = request.data.get('txdianhua', '').strip()
            if not txdianhua:
                return Response({
                    'code': 1,
                    'msg': '收款人电话不能为空',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 验证手机号格式（11位数字）
            if not txdianhua.isdigit() or len(txdianhua) != 11:
                return Response({
                    'code': 2,
                    'msg': '请输入11位有效的手机号码',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 2. 获取收款账号（可能为空）
            txzh = request.data.get('txzh', '').strip()

            # 3. 处理收款码图片上传（如果有）
            txtupian_file = request.FILES.get('file')  # 注意：前端upload.js使用'file'作为字段名
            txtupian_url = ''

            if txtupian_file:
                # 验证图片
                is_valid, error_msg = validate_image(txtupian_file)
                if not is_valid:
                    return Response({
                        'code': 3,
                        'msg': f'图片验证失败: {error_msg}',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                # 上传收款码图片
                txtupian_url = self.handle_shoukuanma_upload(user_main, txtupian_file)
                if txtupian_url:
                    response_data['txtupian'] = txtupian_url
                else:
                    return Response({
                        'code': 4,
                        'msg': '收款码上传失败',
                        'data': None
                    }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            else:
                response_data['txtupian'] = ''

            # 4. 验证收款账号和收款码至少有一个
            if not txzh and not txtupian_url:
                return Response({
                    'code': 5,
                    'msg': '请填写收款账号或上传收款码',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 5. 保存所有信息到数据库
            with transaction.atomic():
                user_main.phone = txdianhua
                user_main.skzhanghao = txzh if txzh else ''

                # 只有上传了图片才更新zhifu字段
                if txtupian_url:
                    user_main.zhifu = txtupian_url

                user_main.save()

            # 6. 构建完整的返回数据
            response_data['txdianhua'] = txdianhua
            response_data['txzh'] = txzh if txzh else ''

            # 7. 返回成功响应
            return Response({
                'code': 0,
                'msg': '收款信息设置成功',
                'data': response_data
            })

        except Exception as e:
            import traceback
            traceback.print_exc()  # 打印详细错误信息到控制台
            return Response({
                'code': 99,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def handle_shoukuanma_upload(self, user_main, image_file):
        """
        处理收款码图片上传到腾讯云COS
        存储路径: tixian/{yonghuid}/{yonghuid}.扩展名
        """
        try:
            yonghuid = user_main.yonghuid
            if not yonghuid:
                return None

            # 获取旧收款码URL
            old_shoukuanma_url = user_main.zhifu

            # 生成文件扩展名
            file_name = image_file.name
            file_extension = os.path.splitext(file_name)[1].lower()
            if not file_extension:
                file_extension = '.jpg'

            # 构建OSS文件路径: tixian/{yonghuid}/{yonghuid}{扩展名}
            # 使用用户ID作为文件名，确保同一用户多次上传会覆盖
            oss_file_name = f"{yonghuid}{file_extension}"
            oss_file_path = f"tixian/{yonghuid}/{oss_file_name}"

            # 删除旧收款码（如果存在）
            if old_shoukuanma_url and old_shoukuanma_url.strip():
                delete_from_oss(old_shoukuanma_url)

            # 上传新收款码到OSS
            new_shoukuanma_url = upload_to_oss(image_file, oss_file_path)

            if new_shoukuanma_url:
                # 返回相对路径（从tixian文件夹开始）
                return oss_file_path
            else:
                return None

        except Exception as e:
            print(f"处理收款码上传失败: {e}")
            return None


from rest_framework.views import APIView
from rest_framework import permissions, status
from rest_framework.response import Response
from django.db import transaction
from django.db.models import F
import decimal
import traceback
from .models import UserMain, UserDashou, UserGuanshi, Tixianjilu,UserShenheguan















from utils.fadan_utils import check_fadan_qiangdan_eligible


# ========== 订单状态常量（请根据您的实际业务修改）==========
# 假设状态值：已完成=9，已退款=10（示例，实际以您的项目为准）
ORDER_STATUS_COMPLETED = 3   # 订单已完成
ORDER_STATUS_REFUNDED = 5   # 订单已退款
# 进行中状态（不可提现）例如：待接单、已接单、进行中等，您需要定义排除列表
FORBIDDEN_STATUS_FOR_WITHDRAW = [1, 2, 3, 4, 5, 6, 7, 8]  # 除已完成和已退款外的所有状态


class TixianShenqingView(APIView):
    """
    用户提现申请接口（完整版）
    支持类型：
        1-打手佣金提现
        2-管事分红提现
        3-组长分红提现
        4-审核官分佣提现
        5-打手押金提现（退出平台）
        6-商家余额提现（退出平台）
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            user_main = request.user
            yonghuid = user_main.yonghuid

            # 1. 获取并验证参数
            leixing = request.data.get('leixing')
            jine = request.data.get('jine')
            fangshi = request.data.get('fangshi')
            txskfs = request.data.get('txskfs', 0)

            # 罚单检查（共用）
            fadan_ok, fadan_msg = check_fadan_qiangdan_eligible(yonghuid, 2)
            if not fadan_ok:
                return Response({'code': 400, 'msg': fadan_msg})

            # 参数完整性
            missing = []
            if leixing is None: missing.append('leixing')
            if jine is None: missing.append('jine')
            if fangshi is None: missing.append('fangshi')
            if missing:
                return Response({'code': 1, 'msg': f'缺少参数: {", ".join(missing)}'},
                                status=status.HTTP_400_BAD_REQUEST)

            try:
                leixing = int(leixing)
                jine = decimal.Decimal(str(jine))
                fangshi = int(fangshi)
                txskfs = int(txskfs)
            except (ValueError, TypeError, decimal.InvalidOperation) as e:
                return Response({'code': 2, 'msg': f'参数格式错误: {str(e)}'},
                                status=status.HTTP_400_BAD_REQUEST)

            if jine <= decimal.Decimal('0'):
                return Response({'code': 3, 'msg': '提现金额必须大于0'},
                                status=status.HTTP_400_BAD_REQUEST)

            # 支持的提现类型（1-6）
            if leixing not in [1, 2, 3, 4, 5, 6]:
                return Response({'code': 4, 'msg': '无效的提现类型'},
                                status=status.HTTP_400_BAD_REQUEST)

            if fangshi not in [1, 2]:
                return Response({'code': 5, 'msg': '无效的收款方式，只能是1(微信)或2(支付宝)'},
                                status=status.HTTP_400_BAD_REQUEST)

            # 2. 获取对应费率及手续费
            current_rate = decimal.Decimal('0.00')
            rate_key = {
                1: '5',   # 打手佣金
                2: '6',   # 管事分红
                3: '8',   # 组长分红
                4: '9',   # 审核官分佣
                5: '11',  # 打手押金提现
                6: '10',  # 商家余额提现
            }.get(leixing)

            if rate_key:
                rate_obj = Lilubiao.objects.filter(fadanpingtai=rate_key).first()
                if rate_obj:
                    current_rate = decimal.Decimal(str(rate_obj.lilu))
                else:
                    return Response({'code': 41, 'msg': f'提现费率未配置（类型{leixing}）'},
                                    status=status.HTTP_400_BAD_REQUEST)

            shouxufei = jine * current_rate
            shijidaozhang = jine - shouxufei
            if shijidaozhang <= decimal.Decimal('0'):
                return Response({'code': 6, 'msg': '提现金额过低，扣除手续费后无实际到账'},
                                status=status.HTTP_400_BAD_REQUEST)

            # 3. 根据提现类型执行校验和扣款
            nicheng = ''
            if leixing == 1:
                result = self._check_dashou_commission_withdraw(user_main, jine)
                if result['code'] != 0:
                    return Response(result, status=status.HTTP_400_BAD_REQUEST)
                nicheng = result['data']['nicheng']
                # 扣款（佣金）
                with transaction.atomic():
                    profile = UserDashou.objects.select_for_update().get(user=user_main)
                    if profile.yue < jine:
                        return Response({'code': 13, 'msg': '余额不足'})
                    profile.yue = F('yue') - jine
                    profile.save()
            elif leixing == 2:
                result = self._check_guanshi_dividend_withdraw(user_main, jine)
                if result['code'] != 0:
                    return Response(result, status=status.HTTP_400_BAD_REQUEST)
                with transaction.atomic():
                    profile = UserGuanshi.objects.select_for_update().get(user=user_main)
                    if profile.yue < jine:
                        return Response({'code': 22, 'msg': '余额不足'})
                    profile.yue = F('yue') - jine
                    profile.save()
                nicheng = "管事用户"
            elif leixing == 3:
                result = self._check_zuzhang_withdraw(user_main, jine)
                if result['code'] != 0:
                    return Response(result, status=status.HTTP_400_BAD_REQUEST)
                with transaction.atomic():
                    profile = UserZuzhang.objects.select_for_update().get(user=user_main)
                    if profile.ketixian_jine < jine:
                        return Response({'code': 32, 'msg': '可提现金额不足'})
                    profile.ketixian_jine = F('ketixian_jine') - jine
                    profile.save()
                nicheng = user_main.nicheng if hasattr(user_main, 'nicheng') else ''
            elif leixing == 4:
                result = self._check_shenheguan_withdraw(user_main, jine)
                if result['code'] != 0:
                    return Response(result, status=status.HTTP_400_BAD_REQUEST)
                with transaction.atomic():
                    profile = UserShenheguan.objects.select_for_update().get(user=user_main)
                    if profile.yue < jine:
                        return Response({'code': 42, 'msg': '可提现金额不足'})
                    profile.yue = F('yue') - jine
                    profile.save()
                nicheng = "审核官"
            elif leixing == 5:
                # 打手押金提现（退出）
                result = self._check_dashou_yajin_withdraw(user_main, jine)
                if result['code'] != 0:
                    return Response(result, status=status.HTTP_400_BAD_REQUEST)
                with transaction.atomic():
                    profile = UserDashou.objects.select_for_update().get(user=user_main)
                    if profile.yajin < jine:
                        return Response({'code': 53, 'msg': '押金余额不足'})
                    profile.yajin = F('yajin') - jine
                    # 押金提现后封禁打手账号
                    profile.zhanghaozhuangtai = 0  # 0表示禁用
                    profile.save()
                nicheng = profile.nicheng or ''
            elif leixing == 6:
                # 商家余额提现（退出）
                result = self._check_shangjia_withdraw(user_main, jine)
                if result['code'] != 0:
                    return Response(result, status=status.HTTP_400_BAD_REQUEST)
                with transaction.atomic():
                    profile = UserShangjia.objects.select_for_update().get(user=user_main)
                    if profile.yue < jine:
                        return Response({'code': 63, 'msg': '商家余额不足'})
                    profile.yue = F('yue') - jine
                    # 注意：是否封禁商家账号？根据需求，用户未明确要求封禁，暂时只扣款，可后续扩展。
                    profile.save()
                nicheng = profile.nicheng or ''

            # 4. 创建提现记录（先扣款后创建，确保资金安全）
            try:
                avatar = user_main.avatar or ''
                phone = user_main.phone or ''
                zhifu = user_main.zhifu or ''
                skzhanghao = user_main.skzhanghao or ''
                tixian_record = Tixianjilu.objects.create(
                    yonghuid=yonghuid,
                    avatar=avatar,
                    phone=phone,
                    nicheng=nicheng,
                    leixing=leixing,
                    zhifu=zhifu,
                    skzhanghao=skzhanghao,
                    jine=shijidaozhang,      # 记录实际到账金额
                    zhuangtai=1,              # 审核中
                    fangshi=fangshi,
                    shenheid=None,
                    bhliyou='',
                )
            except Exception as e:
                return Response({'code': 99, 'msg': f'创建提现记录失败: {str(e)}'},
                                status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 5. 返回成功响应
            return Response({
                'code': 0,
                'msg': '提现申请提交成功',
                'data': {
                    'tixian_id': tixian_record.id,
                    'leixing': leixing,
                    'jine': str(jine.quantize(decimal.Decimal('0.01'))),
                    'fangshi': fangshi,
                    'zhuangtai': 1,
                    'create_time': tixian_record.create_time.strftime('%Y-%m-%d %H:%M:%S'),
                    'current_rate': str(current_rate.quantize(decimal.Decimal('0.0000'))),
                    'shouxufei': str(shouxufei.quantize(decimal.Decimal('0.01'))),
                    'shijidaozhang': str(shijidaozhang.quantize(decimal.Decimal('0.01'))),
                    'tip': f'本次提现手续费率{current_rate * 100}%，手续费{shouxufei}元，实际到账{shijidaozhang}元'
                }
            })

        except Exception as e:
            traceback.print_exc()
            return Response({'code': 99, 'msg': f'系统错误: {str(e)}'},
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    # ==================== 校验函数 ====================

    def _check_dashou_commission_withdraw(self, user_main, jine):
        """打手佣金提现校验"""
        try:
            dashou = UserDashou.objects.get(user=user_main)
        except ObjectDoesNotExist:
            return {'code': 10, 'msg': '您不是打手身份，无法提现佣金'}

        if dashou.zhanghaozhuangtai != 1:
            return {'code': 11, 'msg': '打手账号已被封禁，无法提现'}
        if dashou.zhuangtai != 1:
            return {'code': 12, 'msg': '您有订单进行中，请完成后提现'}
        if dashou.jifen != 10:
            return {'code': 15, 'msg': '积分不足10分，请补充积分后提现'}
        if dashou.yue < jine:
            return {'code': 13, 'msg': f'余额不足，当前余额: {dashou.yue}'}

        return {'code': 0, 'msg': 'ok', 'data': {'nicheng': dashou.nicheng or ''}}

    def _check_guanshi_dividend_withdraw(self, user_main, jine):
        """管事分红提现校验"""
        try:
            guanshi = UserGuanshi.objects.get(user=user_main)
        except ObjectDoesNotExist:
            return {'code': 20, 'msg': '您不是管事身份，无法提现分红'}
        if guanshi.zhuangtai != 1:
            return {'code': 21, 'msg': '管事账号已被封禁，无法提现'}
        if guanshi.yue < jine:
            return {'code': 22, 'msg': f'余额不足，当前余额: {guanshi.yue}'}
        return {'code': 0, 'msg': 'ok', 'data': {}}

    def _check_zuzhang_withdraw(self, user_main, jine):
        """组长分红提现校验"""
        try:
            zuzhang = UserZuzhang.objects.get(user=user_main)
        except ObjectDoesNotExist:
            return {'code': 30, 'msg': '您不是组长身份，无法提现组长分红'}
        if zuzhang.zhuangtai != 1:
            return {'code': 31, 'msg': '组长账号已被封禁，无法提现'}
        if zuzhang.ketixian_jine < jine:
            return {'code': 32, 'msg': f'可提现金额不足，当前可提: {zuzhang.ketixian_jine}'}
        return {'code': 0, 'msg': 'ok', 'data': {}}

    from django.db.models import Q

    def _check_shangjia_withdraw(self, user_main, jine):
        """
        商家余额提现校验（退出平台）
        包含：订单、自身罚单、申请的罚单检查
        """
        try:
            shangjia = UserShangjia.objects.get(user=user_main)
        except ObjectDoesNotExist:
            return {'code': 60, 'msg': '您不是商家身份，无法提现商家余额'}

        if shangjia.zhuangtai != 1:
            return {'code': 61, 'msg': '商家账号已被禁用，无法提现'}
        if shangjia.yue < jine:
            return {'code': 62, 'msg': f'商家余额不足，当前余额: {shangjia.yue}'}

        # 订单检查（使用 Q 取反）
        unfinished_orders = DingdanShangjia.objects.filter(
            shangjia_id=user_main.yonghuid,
        ).exclude(
            dingdan__zhuangtai__in=[ORDER_STATUS_COMPLETED, ORDER_STATUS_REFUNDED]
        ).exists()
        if unfinished_orders:
            return {'code': 63, 'msg': '您还有未完成或未退款的订单，请先处理完毕再提现余额'}

        # 自身被处罚的罚单检查（状态不是已缴纳(2)和已驳回(4)）
        self_fadan = Fadan.objects.filter(
            beichufa_id=user_main.yonghuid,
        ).exclude(
            zhuangtai__in=[2, 4]
        ).exists()
        if self_fadan:
            return {'code': 64, 'msg': '您有未处理完毕的自身罚单（待缴纳/申诉中），请先处理'}

        # 申请的对他人处罚罚单检查（状态不是已缴纳(2)和已驳回(4)）
        applied_fadan = Fadan.objects.filter(
            shenqing_chufa=user_main.yonghuid,
        ).exclude(
            zhuangtai__in=[2, 4]
        ).exists()
        if applied_fadan:
            return {'code': 65, 'msg': '您发起的对其他用户的处罚尚未处理完毕（待缴纳/申诉中），请等待完结'}

        return {'code': 0, 'msg': 'ok', 'data': {'nicheng': shangjia.nicheng or ''}}

    def _check_dashou_yajin_withdraw(self, user_main, jine):
        """
        打手押金提现校验（退出平台）
        要求：无进行中的订单，无未结算订单，自身罚单需已处理
        """
        try:
            dashou = UserDashou.objects.get(user=user_main)
        except ObjectDoesNotExist:
            return {'code': 50, 'msg': '您不是打手身份，无法提取押金'}

        if dashou.zhanghaozhuangtai != 1:
            return {'code': 51, 'msg': '打手账号已禁用，无法提取押金'}
        if dashou.zhuangtai != 1:
            return {'code': 52, 'msg': '您有订单进行中，请完成后提取押金'}
        if dashou.yajin < jine:
            return {'code': 53, 'msg': f'押金余额不足，当前押金: {dashou.yajin}'}

        # 订单检查（使用 exclude + __in）
        unfinished_orders = Dingdan.objects.filter(
            jiedan_dashou_id=user_main.yonghuid,
        ).exclude(
            zhuangtai__in=[ORDER_STATUS_COMPLETED, ORDER_STATUS_REFUNDED]
        ).exists()
        if unfinished_orders:
            return {'code': 54, 'msg': '您还有未完成或未退款的订单，请先处理完毕再提取押金'}

        # 自身罚单检查
        self_fadan = Fadan.objects.filter(
            beichufa_id=user_main.yonghuid,
        ).exclude(
            zhuangtai__in=[2, 4]
        ).exists()
        if self_fadan:
            return {'code': 55, 'msg': '您有未处理完毕的自身罚单（待缴纳/申诉中），请先处理'}

        return {'code': 0, 'msg': 'ok', 'data': {'nicheng': dashou.nicheng or ''}}

'''class TixianShenqingView(APIView):
    """
    用户提现申请接口（修复版）
    支持打手佣金提现、管事分红提现、组长分红提现
    严格校验所有业务条件，修复400错误问题
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        """
        处理提现申请的POST请求
        加强参数验证和错误处理
        """
        try:
            # 获取当前用户
            user_main = request.user
            yonghuid = user_main.yonghuid

            # 1. 获取并严格验证前端参数
            leixing = request.data.get('leixing')  # 提现类型：1-佣金 2-分红 3-组长分红
            jine = request.data.get('jine')
            fangshi = request.data.get('fangshi')
            txskfs = request.data.get('txskfs', 0)

            # ==================== 【新增】罚单检查 ====================
            from utils.fadan_utils import check_fadan_qiangdan_eligible
            fadan_ok, fadan_msg = check_fadan_qiangdan_eligible(request.user.yonghuid, 2)
            if not fadan_ok:
                return Response({'code': 400, 'msg': fadan_msg})
            # =========================================================

            # 验证必需参数是否存在
            missing_params = []
            if leixing is None:
                missing_params.append('leixing')
            if jine is None:
                missing_params.append('jine')
            if fangshi is None:
                missing_params.append('fangshi')

            if missing_params:
                return Response({
                    'code': 1,
                    'msg': f'缺少必需参数: {", ".join(missing_params)}',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 验证参数类型和格式
            try:
                leixing = int(leixing)
                if isinstance(jine, str):
                    jine = decimal.Decimal(jine)
                else:
                    jine = decimal.Decimal(str(jine))
                fangshi = int(fangshi)
                txskfs = int(txskfs)
            except (ValueError, TypeError, decimal.InvalidOperation) as e:
                return Response({
                    'code': 2,
                    'msg': f'参数格式错误: {str(e)}',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 验证提现金额必须大于0
            if jine <= decimal.Decimal('0'):
                return Response({
                    'code': 3,
                    'msg': '提现金额必须大于0',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 验证提现类型有效性（新增类型3）
            if leixing not in [1, 2, 3,4]:
                return Response({
                    'code': 4,
                    'msg': '无效的提现类型，只能是1(佣金)、2(分红)或3(组长分红)',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 验证收款方式有效性
            if fangshi not in [1, 2]:
                return Response({
                    'code': 5,
                    'msg': '无效的收款方式，只能是1(微信)或2(支付宝)',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 🔥【组长支持】获取对应费率（增加组长）
            current_rate = decimal.Decimal('0.00')
            if leixing == 1:
                dashou_rate_obj = Lilubiao.objects.filter(fadanpingtai='5').first()
                if dashou_rate_obj:
                    current_rate = decimal.Decimal(str(dashou_rate_obj.lilu))
            elif leixing == 2:
                guanshi_rate_obj = Lilubiao.objects.filter(fadanpingtai='6').first()
                if guanshi_rate_obj:
                    current_rate = decimal.Decimal(str(guanshi_rate_obj.lilu))
            elif leixing == 3:
                # 组长提现费率 (fadanpingtai='8')
                zuzhang_rate_obj = Lilubiao.objects.filter(fadanpingtai='8').first()
                if zuzhang_rate_obj:
                    current_rate = decimal.Decimal(str(zuzhang_rate_obj.lilu))
                else:
                    return Response({
                        'code': 31,
                        'msg': '组长费率未配置，无法提现',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

            elif leixing == 4:
                # 审核官提现费率 (fadanpingtai='9'，数字可自定义)
                kaoheguan_rate_obj = Lilubiao.objects.filter(fadanpingtai='9').first()
                if kaoheguan_rate_obj:
                    current_rate = decimal.Decimal(str(kaoheguan_rate_obj.lilu))
                else:
                    return Response({
                        'code': 41,
                        'msg': '审核官费率未配置，无法提现',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)


            # 计算手续费和实际到账金额
            shouxufei = jine * current_rate
            shijidaozhang = jine - shouxufei

            # 验证手续费和实际到账金额的有效性
            if shijidaozhang <= decimal.Decimal('0'):
                return Response({
                    'code': 6,
                    'msg': '提现金额过低，扣除手续费后无实际到账',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 2. 根据提现类型进行不同的校验
            if leixing == 1:
                # 佣金提现 - 打手
                result = self.yanzheng_dashou_tixian(user_main, jine)
                if result['code'] != 0:
                    return Response(result, status=status.HTTP_400_BAD_REQUEST)

                dashou_info = result['data']
                nicheng = dashou_info.get('nicheng', '')

                # 使用事务更新打手余额
                try:
                    with transaction.atomic():
                        dashou_profile = UserDashou.objects.select_for_update().get(user=user_main)
                        if dashou_profile.yue < jine:
                            return Response({
                                'code': 13,
                                'msg': '余额不足，无法提现',
                                'data': None
                            }, status=status.HTTP_400_BAD_REQUEST)
                        dashou_profile.yue = F('yue') - jine
                        dashou_profile.save()
                        dashou_profile.refresh_from_db()
                except Exception as e:
                    return Response({
                        'code': 99,
                        'msg': f'更新余额失败: {str(e)}',
                        'data': None
                    }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            elif leixing == 2:
                # 分红提现 - 管事
                result = self.yanzheng_guanshi_tixian(user_main, jine)
                if result['code'] != 0:
                    return Response(result, status=status.HTTP_400_BAD_REQUEST)

                nicheng = "管事用户"

                try:
                    with transaction.atomic():
                        guanshi_profile = UserGuanshi.objects.select_for_update().get(user=user_main)
                        if guanshi_profile.yue < jine:
                            return Response({
                                'code': 22,
                                'msg': '余额不足，无法提现',
                                'data': None
                            }, status=status.HTTP_400_BAD_REQUEST)
                        guanshi_profile.yue = F('yue') - jine
                        guanshi_profile.save()
                        guanshi_profile.refresh_from_db()
                except Exception as e:
                    return Response({
                        'code': 99,
                        'msg': f'更新余额失败: {str(e)}',
                        'data': None
                    }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 🔥【组长支持】新增组长提现分支
            elif leixing == 3:
                # 组长分红提现
                result = self.yanzheng_zuzhang_tixian(user_main, jine)
                if result['code'] != 0:
                    return Response(result, status=status.HTTP_400_BAD_REQUEST)

                zuzhang_info = result['data']
                nicheng = zuzhang_info.get('nicheng', '')

                try:
                    with transaction.atomic():
                        zuzhang_profile = UserZuzhang.objects.select_for_update().get(user=user_main)
                        if zuzhang_profile.ketixian_jine < jine:
                            return Response({
                                'code': 32,
                                'msg': '组长可提现金额不足',
                                'data': None
                            }, status=status.HTTP_400_BAD_REQUEST)
                        # 扣除申请金额
                        zuzhang_profile.ketixian_jine = F('ketixian_jine') - jine
                        zuzhang_profile.save()
                        zuzhang_profile.refresh_from_db()
                except Exception as e:
                    return Response({
                        'code': 99,
                        'msg': f'更新组长余额失败: {str(e)}',
                        'data': None
                    }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


            # 🔥【审核官支持】新增审核官提现分支
            elif leixing == 4:
                # 审核官分佣提现
                result = self.yanzheng_kaoheguan_tixian(user_main, jine)
                if result['code'] != 0:
                    return Response(result, status=status.HTTP_400_BAD_REQUEST)

                kaoheguan_info = result['data']
                nicheng = kaoheguan_info.get('nicheng', '')

                try:
                    with transaction.atomic():
                        kaoheguan_profile = UserShenheguan.objects.select_for_update().get(user=user_main)
                        if kaoheguan_profile.yue < jine:
                            return Response({
                                'code': 42,
                                'msg': '审核官可提现金额不足',
                                'data': None
                            }, status=status.HTTP_400_BAD_REQUEST)
                        # 扣除申请金额
                        kaoheguan_profile.yue = F('yue') - jine
                        kaoheguan_profile.save()
                        kaoheguan_profile.refresh_from_db()
                except Exception as e:
                    return Response({
                        'code': 99,
                        'msg': f'更新审核官余额失败: {str(e)}',
                        'data': None
                    }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 3. 创建提现记录
            try:
                avatar = user_main.avatar if user_main.avatar else ''
                phone = user_main.phone if user_main.phone else ''
                zhifu = user_main.zhifu if user_main.zhifu else ''
                skzhanghao = user_main.skzhanghao if user_main.skzhanghao else ''

                # 对于打手或组长，从扩展表获取昵称
                if leixing == 1:
                    try:
                        dashou_profile = UserDashou.objects.get(user=user_main)
                        nicheng = dashou_profile.nicheng if dashou_profile.nicheng else ''
                    except UserDashou.DoesNotExist:
                        nicheng = ''
                elif leixing == 3:
                    # 组长昵称从组长扩展表获取（如果需要）
                    try:
                        zuzhang_profile = UserZuzhang.objects.get(user=user_main)
                        # 组长扩展表可能没有昵称字段，可以从UserMain获取
                        nicheng = user_main.nicheng if hasattr(user_main, 'nicheng') else ''
                    except UserZuzhang.DoesNotExist:
                        nicheng = ''

                # 4. 在创建提现记录时（约第 180 行），对审核官类型的昵称处理（可选）：
                # 在 elif leixing == 3: 的组长昵称获取之后，追加：
                elif leixing == 4:
                #审核官昵称可从扩展表或UserMain获取（如果扩展表没有昵称字段）
                    try:
                        kaoheguan_profile = UserShenheguan.objects.get(user=user_main)
                        # 审核官扩展表通常没有昵称，可用 '审核官' 或从 UserMain 取
                        nicheng = '审核官'  # 或者 user_main.nicheng if hasattr(user_main, 'nicheng') else '审核官'
                    except UserShenheguan.DoesNotExist:
                        nicheng = ''

                tixian_jilu = Tixianjilu.objects.create(
                    yonghuid=yonghuid,
                    avatar=avatar,
                    phone=phone,
                    nicheng=nicheng,
                    leixing=leixing,
                    zhifu=zhifu,
                    skzhanghao=skzhanghao,
                    jine=shijidaozhang,      # 记录实际到账金额
                    zhuangtai=1,
                    fangshi=fangshi,
                    shenheid=None,
                    bhliyou='',
                )

                # 4. 返回成功响应
                return Response({
                    'code': 0,
                    'msg': '提现申请提交成功',
                    'data': {
                        'tixian_id': tixian_jilu.id,
                        'leixing': leixing,
                        'jine': str(jine.quantize(decimal.Decimal('0.01'))),
                        'fangshi': fangshi,
                        'zhuangtai': 1,
                        'create_time': tixian_jilu.create_time.strftime('%Y-%m-%d %H:%M:%S'),
                        'current_rate': str(current_rate.quantize(decimal.Decimal('0.0000'))),
                        'shouxufei': str(shouxufei.quantize(decimal.Decimal('0.01'))),
                        'shijidaozhang': str(shijidaozhang.quantize(decimal.Decimal('0.01'))),
                        'tip': f'本次提现手续费率{current_rate * 100}%，手续费{shouxufei}元，实际到账{shijidaozhang}元'
                    }
                })

            except Exception as e:
                traceback.print_exc()
                return Response({
                    'code': 99,
                    'msg': f'创建提现记录失败: {str(e)}',
                    'data': None
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        except Exception as e:
            traceback.print_exc()
            return Response({
                'code': 99,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    # 原有校验函数不变

    def yanzheng_kaoheguan_tixian(self, user_main, jine):
        """
        校验审核官分佣提现条件
        """
        try:
            # 查询审核官扩展表
            try:
                kaoheguan_profile = UserShenheguan.objects.get(user=user_main)
            except UserShenheguan.DoesNotExist:
                return {
                    'code': 40,
                    'msg': '您不是审核官身份，无法提现分佣',
                    'data': None
                }

            # 校验1: 审核官账号状态 (zhuangtai != 1)
            if kaoheguan_profile.zhuangtai != 1:
                return {
                    'code': 41,
                    'msg': '审核官账号已被封禁，无法提现',
                    'data': None
                }

            # 校验2: 可提现金额是否足够 (yue < jine)
            if kaoheguan_profile.yue < jine:
                return {
                    'code': 42,
                    'msg': f'审核官可提现金额不足，当前可提: {kaoheguan_profile.yue}，申请金额: {jine}',
                    'data': None
                }

            # 所有校验通过
            return {
                'code': 0,
                'msg': '校验通过',
                'data': {
                    'nicheng': '审核官',  # 可根据需要调整
                    'yue': kaoheguan_profile.yue
                }
            }

        except Exception as e:
            return {
                'code': 99,
                'msg': f'审核官提现校验过程出错: {str(e)}',
                'data': None
            }

    def yanzheng_dashou_tixian(self, user_main, jine):
        """
        校验打手佣金提现条件（修复版）
        修正了状态判断逻辑
        """
        try:
            # print(f"开始校验打手提现 - 用户: {user_main.yonghuid}, 金额: {jine}")

            # 查询打手扩展表
            try:
                dashou_profile = UserDashou.objects.get(user=user_main)
                # print(
                #     f"打手信息 - 状态: {dashou_profile.zhuangtai}, 账号状态: {dashou_profile.zhanghaozhuangtai}, 积分: {dashou_profile.jifen}, 余额: {dashou_profile.yue}")
            except UserDashou.DoesNotExist:
                # print("打手扩展表记录不存在")
                return {
                    'code': 10,
                    'msg': '您不是打手身份，无法提现佣金',
                    'data': None
                }

            # 校验1: 打手账号状态 (zhanghaozhuangtai != 1 则封禁)
            if dashou_profile.zhanghaozhuangtai != 1:
                return {
                    'code': 11,
                    'msg': '打手账号已被封禁，无法提现',
                    'data': None
                }

            # 校验2: 打手接单状态 (zhuangtai != 1 则有订单进行中) - 修复这里
            if dashou_profile.zhuangtai != 1:
                return {
                    'code': 12,
                    'msg': '您有订单进行中，请完成后提现',
                    'data': None
                }

            # 校验3: 积分检查 (jifen != 10 则不足) - 新增
            if dashou_profile.jifen != 10:
                return {
                    'code': 15,  # 使用新的错误码
                    'msg': '积分不足10分，请补充积分后提现',
                    'data': None
                }

            # 校验4: 余额是否足够 (yue < jine)
            if dashou_profile.yue < jine:
                return {
                    'code': 13,
                    'msg': f'余额不足，当前余额: {dashou_profile.yue}，提现金额: {jine}',
                    'data': None
                }

            # print("打手提现校验通过")

            # 所有校验通过
            return {
                'code': 0,
                'msg': '校验通过',
                'data': {
                    'nicheng': dashou_profile.nicheng if dashou_profile.nicheng else '',
                    'yue': dashou_profile.yue,
                    'jifen': dashou_profile.jifen
                }
            }

        except Exception as e:
            # print(f"打手提现校验异常: {e}")
            return {
                'code': 99,
                'msg': f'校验过程出错: {str(e)}',
                'data': None
            }

    def yanzheng_guanshi_tixian(self, user_main, jine):
        """
        校验管事分红提现条件
        """
        try:
            # print(f"开始校验管事提现 - 用户: {user_main.yonghuid}, 金额: {jine}")

            # 查询管事扩展表
            try:
                guanshi_profile = UserGuanshi.objects.get(user=user_main)
                # print(f"管事信息 - 状态: {guanshi_profile.zhuangtai}, 余额: {guanshi_profile.yue}")
            except UserGuanshi.DoesNotExist:
                # print("管事扩展表记录不存在")
                return {
                    'code': 20,
                    'msg': '您不是管事身份，无法提现分红',
                    'data': None
                }

            # 校验1: 管事账号状态 (zhuangtai != 1)
            if guanshi_profile.zhuangtai != 1:
                return {
                    'code': 21,
                    'msg': '管事账号已被封禁，无法提现',
                    'data': None
                }

            # 校验2: 余额是否足够 (yue < jine)
            if guanshi_profile.yue < jine:
                return {
                    'code': 22,
                    'msg': f'余额不足，当前余额: {guanshi_profile.yue}，提现金额: {jine}',
                    'data': None
                }

            # print("管事提现校验通过")

            # 所有校验通过
            return {
                'code': 0,
                'msg': '校验通过',
                'data': {
                    'yue': guanshi_profile.yue
                }
            }

        except Exception as e:
            # print(f"管事提现校验异常: {e}")
            return {
                'code': 99,
                'msg': f'校验过程出错: {str(e)}',
                'data': None
            }


    # 🔥【组长支持】新增组长校验函数
    def yanzheng_zuzhang_tixian(self, user_main, jine):
        """
        校验组长分红提现条件
        """
        try:
            # 查询组长扩展表
            try:
                zuzhang_profile = UserZuzhang.objects.get(user=user_main)
            except UserZuzhang.DoesNotExist:
                return {
                    'code': 30,
                    'msg': '您不是组长身份，无法提现组长分红',
                    'data': None
                }

            # 校验1: 组长账号状态 (zhuangtai != 1)
            if zuzhang_profile.zhuangtai != 1:
                return {
                    'code': 31,
                    'msg': '组长账号已被封禁，无法提现',
                    'data': None
                }

            # 校验2: 可提现金额是否足够
            if zuzhang_profile.ketixian_jine < jine:
                return {
                    'code': 32,
                    'msg': f'组长可提现金额不足，当前可提: {zuzhang_profile.ketixian_jine}，申请金额: {jine}',
                    'data': None
                }

            # 所有校验通过
            return {
                'code': 0,
                'msg': '校验通过',
                'data': {
                    'nicheng': user_main.nicheng if hasattr(user_main, 'nicheng') else '',
                    'ketixian_jine': zuzhang_profile.ketixian_jine
                }
            }

        except Exception as e:
            return {
                'code': 99,
                'msg': f'组长提现校验过程出错: {str(e)}',
                'data': None
            }'''







class TixianJiluHuoquViewV2(APIView):
    """
    提现记录获取接口
    mode=1：手动提现记录（默认，兼容旧版）
    mode=2：自动提现审核记录（含 shenhe_jilu_id / shenhe_danhao，支持 zhuangtai 筛选）
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            from .models import TixianAutoRecord, TixianShenheJilu

            user_main = request.user
            yonghuid = user_main.yonghuid
            page = request.data.get('page', 1)
            limit = request.data.get('limit', 50)
            mode = int(request.data.get('mode', 1) or 1)
            zhuangtai_filter = int(request.data.get('zhuangtai', 0) or 0)

            try:
                page = int(page)
                limit = int(limit)
                if page < 1 or limit < 1:
                    return Response({'code': 1, 'msg': '参数错误', 'data': None},
                                    status=status.HTTP_400_BAD_REQUEST)
            except (TypeError, ValueError):
                return Response({'code': 1, 'msg': '参数格式错误', 'data': None},
                                status=status.HTTP_400_BAD_REQUEST)

            if limit > 100:
                limit = 100
            offset = (page - 1) * limit

            qs = Tixianjilu.objects.filter(yonghuid=yonghuid)
            if mode == 2:
                # 自动提现：含新审核关联记录；zhuangtai>0 时按状态筛选
                if zhuangtai_filter > 0:
                    qs = qs.filter(zhuangtai=zhuangtai_filter)
            qs = qs.order_by('-create_time')

            records_queryset = qs.values(
                'id', 'leixing', 'jine', 'zhuangtai', 'create_time', 'fangshi',
                'phone', 'skzhanghao', 'zhifu', 'bhliyou',
                'shenhe_jilu_id', 'shenhe_danhao',
            )[offset:offset + limit + 1]

            records_list = list(records_queryset)
            has_more = len(records_list) > limit
            records_to_return = records_list[:limit] if has_more else records_list

            # 批量取审核表 fail_reason
            audit_ids = [r['shenhe_jilu_id'] for r in records_to_return if r.get('shenhe_jilu_id')]
            audit_map = {}
            if audit_ids:
                for a in TixianShenheJilu.objects.filter(id__in=audit_ids).values(
                    'id', 'fail_reason', 'shenqing_jine', 'shenhe_danhao'
                ):
                    audit_map[a['id']] = a

            # 批量取自动打款失败原因
            danhao_list = [r['shenhe_danhao'] for r in records_to_return if r.get('shenhe_danhao')]
            auto_fail_map = {}
            if danhao_list:
                for ar in TixianAutoRecord.objects.filter(
                    shenhe_danhao__in=danhao_list, zhuangtai=2
                ).order_by('-create_time').values('shenhe_danhao', 'fail_reason'):
                    if ar['shenhe_danhao'] not in auto_fail_map:
                        auto_fail_map[ar['shenhe_danhao']] = ar['fail_reason']

            formatted_records = []
            for record in records_to_return:
                audit = audit_map.get(record.get('shenhe_jilu_id')) if record.get('shenhe_jilu_id') else None
                fail_reason = ''
                if audit and audit.get('fail_reason'):
                    fail_reason = audit['fail_reason']
                elif record.get('shenhe_danhao'):
                    fail_reason = auto_fail_map.get(record['shenhe_danhao'], '') or ''

                jine_val = float(record['jine']) if record['jine'] else 0.00
                if mode == 2 and audit and audit.get('shenqing_jine') is not None:
                    jine_val = float(audit['shenqing_jine'])

                shenhe_danhao_val = record.get('shenhe_danhao') or (audit.get('shenhe_danhao') if audit else '')
                formatted_records.append({
                    'id': record['id'],
                    'tixianjilu_id': record['id'],
                    'tixian_id': record['id'],
                    'leixing': record['leixing'],
                    'jine': jine_val,
                    'zhuangtai': record['zhuangtai'],
                    'create': record['create_time'].strftime('%Y-%m-%d %H:%M:%S'),
                    'fangshi': record['fangshi'],
                    'txdianhua': record['phone'] or '',
                    'txzh': record['skzhanghao'] or '',
                    'txtupian': record['zhifu'] or '',
                    'shibaiyuanyin': record['bhliyou'] or '',
                    'bhliyou': record['bhliyou'] or '',
                    'fail_reason': fail_reason,
                    'shenhe_jilu_id': record.get('shenhe_jilu_id'),
                    'shenhe_danhao': shenhe_danhao_val,
                })

            return Response({
                'code': 0,
                'msg': '获取成功',
                'data': {
                    'list': formatted_records,
                    'has_more': has_more,
                    'page': page,
                    'limit': limit,
                    'current_count': len(formatted_records),
                },
            })

        except Exception as e:
            return Response({
                'code': 99,
                'msg': f'系统错误: {str(e)}',
                'data': None,
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
'''class TixianJiluHuoquViewV2(APIView):
    """
    提现记录获取接口（优化版）
    使用更高效的查询方式，减少数据库压力
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            # 获取当前用户
            user_main = request.user
            yonghuid = user_main.yonghuid

            # 获取分页参数
            page = request.data.get('page', 1)
            limit = request.data.get('limit', 50)

            # 参数验证
            try:
                page = int(page)
                limit = int(limit)
                if page < 1 or limit < 1:
                    return Response({
                        'code': 1,
                        'msg': '参数错误',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)
            except:
                return Response({
                    'code': 1,
                    'msg': '参数格式错误',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 限制最大查询数量
            if limit > 100:
                limit = 100

            # 计算偏移量
            offset = (page - 1) * limit

            # 高效查询：只查询需要的字段，使用切片限制数量
            # 这里查询limit+1条，用于判断是否还有更多数据
            query_limit = limit + 1
            records_queryset = Tixianjilu.objects.filter(
                yonghuid=yonghuid
            ).order_by('-create_time').values(
                'leixing', 'jine', 'zhuangtai', 'create_time', 'fangshi'
            )[offset:offset + query_limit]

            # 转换为列表
            records_list = list(records_queryset)
            records_count = len(records_list)

            # 判断是否有更多数据
            has_more = records_count > limit

            # 如果查询到的数量大于limit，只返回limit条
            if has_more:
                records_to_return = records_list[:limit]
            else:
                records_to_return = records_list

            # 格式化数据
            formatted_records = []
            for record in records_to_return:
                formatted_records.append({
                    'leixing': record['leixing'],
                    'jine': float(record['jine']) if record['jine'] else 0.00,
                    'zhuangtai': record['zhuangtai'],
                    'create': record['create_time'].strftime('%Y-%m-%d %H:%M:%S'),
                    'fangshi': record['fangshi']
                })

            # 构建响应
            response_data = {
                'list': formatted_records,
                'has_more': has_more,
                'page': page,
                'limit': limit,
                'current_count': len(formatted_records)
            }

            return Response({
                'code': 0,
                'msg': '获取成功',
                'data': response_data
            })

        except Exception as e:
            return Response({
                'code': 99,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)'''


# yonghu/views.py
import jwt
import datetime



class AdminLoginView(APIView):
    """
    管理员登录接口
    路径：/yonghu/adlog/
    方法：POST
    字段：zhanghao（账号）, mima（密码）, ip（二次验证码）
    """

    # 限制匿名用户访问频率，防止暴力破解
    throttle_classes = [AnonRateThrottle]
    # 允许任何人访问（登录接口不需要认证）
    permission_classes = [AllowAny]

    def post(self, request):
        """
        处理管理员登录请求
        安全策略：任何错误都返回401，不透露具体信息
        """
        try:
            # 1. 获取客户端真实IP和用户代理信息
            kehuduan_ip = huoquKehuduanIP(request)
            yonghu_daili = huoquYonghuDaili(request)

            # 2. 获取前端传递的数据
            data = request.data

            # 检查必需字段是否存在
            bixu_ziduan = ['zhanghao', 'mima', 'ip']
            for ziduan in bixu_ziduan:
                if ziduan not in data:
                    # 字段缺失，返回401
                    return Response(
                        {'code': 401, 'msg': '登录失败', 'data': None},
                        status=status.HTTP_401_UNAUTHORIZED
                    )

            # 提取并清理数据
            zhanghao = data.get('zhanghao', '').strip()
            mima = data.get('mima', '').strip()
            erci_yanzhengma = data.get('ip', '').strip()  # 二次验证码（前端叫ip）

            # 简单验证字段非空
            if not zhanghao or not mima or not erci_yanzhengma:
                return Response(
                    {'code': 401, 'msg': '登录失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 3. 使用事务确保数据一致性
            with transaction.atomic():
                # 【优化点1】使用select_related一次性获取管理员扩展表
                # 只查询管理员类型的用户
                user = UserMain.objects.filter(
                    phone=zhanghao,  # 手机号作为账号
                    password=mima,  # 密码
                    user_type='admin'  # 必须是管理员类型
                ).select_related('admin_profile').first()

                # 如果用户不存在或不是管理员，返回401
                if not user:
                    return Response(
                        {'code': 401, 'msg': '登录失败', 'data': None},
                        status=status.HTTP_401_UNAUTHORIZED
                    )

                # 【优化点2】检查管理员扩展表是否存在
                if not hasattr(user, 'admin_profile'):
                    return Response(
                        {'code': 401, 'msg': '登录失败', 'data': None},
                        status=status.HTTP_401_UNAUTHORIZED
                    )

                # 【优化点3】验证二次密码（管理员扩展表中的password字段）
                admin_profile = user.admin_profile
                if admin_profile.password != erci_yanzhengma:
                    return Response(
                        {'code': 401, 'msg': '登录失败', 'data': None},
                        status=status.HTTP_401_UNAUTHORIZED
                    )

                # 4. 更新用户登录信息
                # 获取当前时间
                now_time = timezone.now()

                # 处理IP地址长度问题
                # 如果原ip字段长度不够，截取前11个字符（保持兼容性）
                if len(kehuduan_ip) > 11:
                    # 如果ip字段长度限制是11，我们截取前11个字符
                    # 建议在数据库中修改ip字段为50长度
                    cunchu_ip = kehuduan_ip[:11]
                else:
                    cunchu_ip = kehuduan_ip

                # 更新用户信息
                user.ip = cunchu_ip  # 存储客户端IP
                user.last_login_time = now_time  # 更新最后登录时间
                user.save()

                # 【优化点4】生成JWT token（使用和微信登录相同的方式）
                # 使用djangorestframework-simplejwt生成token
                refresh = RefreshToken.for_user(user)
                token = str(refresh.access_token)

                # 5. 准备返回数据
                # 返回用户基本信息（可根据需要调整）
                response_data = {
                    'token': token,
                    'yonghuid': user.yonghuid,
                    'phone': user.phone or '',
                    'user_type': user.user_type,
                    'last_login_time': now_time.strftime('%Y-%m-%d %H:%M:%S') if now_time else '',
                }

                # 可以添加管理员特定信息
                if hasattr(user, 'admin_profile'):
                    response_data['wechat'] = user.admin_profile.wechat or ''

                return Response({
                    'code': 0,
                    'msg': '登录成功',
                    'data': response_data
                })

        except Exception as e:
            # 【安全点】任何异常都返回401，不暴露具体错误信息
            # 记录日志用于排查问题，但前端只收到通用错误信息
            # 这里可以添加日志记录，比如：
            # import logging
            # logging.error(f'管理员登录异常: {str(e)}', exc_info=True)

            return Response(
                {'code': 401, 'msg': '登录失败', 'data': None},
                status=status.HTTP_401_UNAUTHORIZED
            )


# yonghu/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from django.db import transaction
from django.core.exceptions import ObjectDoesNotExist
import json

# 导入模型
from yonghu.models import UserMain, AdminProfile
from peizhi.models import Szjilu


class AdminFinancialDataView(APIView):
    """
    管理员财务数据接口
    路径：/yonghu/adhq/
    方法：POST
    认证：JWT Token
    权限：仅管理员
    返回：收支记录数据
    """

    # 使用JWT认证
    permission_classes = [IsAuthenticated]

    def post(self, request):
        """
        处理管理员财务数据请求
        安全策略：任何错误都返回401，不透露具体信息
        """
        try:
            # 1. 获取前端传递的数据
            data = request.data

            # 检查必需字段
            if 'zhanghao' not in data:
                return Response(
                    {'code': 401, 'msg': '请求参数错误', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            qianzhanghao = data.get('zhanghao', '').strip()

            # 简单验证字段非空
            if not qianzhanghao:
                return Response(
                    {'code': 401, 'msg': '请求参数错误', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 获取当前登录用户（JWT认证后，request.user就是UserMain实例）
            dangqianyonghu = request.user

            # 3. 验证用户类型是否为admin
            if not hasattr(dangqianyonghu, 'user_type') or dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'msg': '权限不足', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证前端传递的账号与当前用户的phone字段是否一致
            if not dangqianyonghu.phone or dangqianyonghu.phone != qianzhanghao:
                return Response(
                    {'code': 401, 'msg': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 验证管理员扩展表是否存在（反向查询）
            # 使用高效的ORM查询，避免额外的数据库查询
            try:
                # 使用select_related一次性获取管理员扩展表
                # 注意：这里假设user_type='admin'的用户都有admin_profile
                yonghu_xiangxi = UserMain.objects.select_related('admin_profile').get(
                    pk=dangqianyonghu.pk,
                    user_type='admin'
                )

                # 检查管理员扩展表是否存在
                if not hasattr(yonghu_xiangxi, 'admin_profile'):
                    return Response(
                        {'code': 401, 'msg': '身份验证失败', 'data': None},
                        status=status.HTTP_401_UNAUTHORIZED
                    )

            except UserMain.DoesNotExist:
                return Response(
                    {'code': 401, 'msg': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 查询收支记录表（Szjilu）
            # 使用高效的ORM查询，获取最新的一条记录
            # 注意：根据你的业务需求，这里获取最新的一条记录
            # 如果需要汇总多条记录，可以使用aggregate进行聚合查询

            # 方法1：获取最新的一条记录（假设表中只有一条汇总记录）
            shouzhijilu = Szjilu.objects.order_by('-create_time').first()

            # 方法2：如果表中可能有多条记录，需要汇总，可以使用以下方式：
            # from django.db.models import Sum
            # zonghe = Szjilu.objects.aggregate(
            #     zongliushui=Sum('zongls'),
            #     zongshouyi=Sum('zongsy'),
            #     zongzhichu=Sum('zongzc'),
            #     jrls=Sum('jrls'),
            #     jrzc=Sum('jrzc')
            # )

            # 准备返回数据
            if shouzhijilu:
                # 有记录的情况
                huizongshuju = {
                    'zongliushui': float(shouzhijilu.zongls or 0),
                    'zongshouyi': float(shouzhijilu.zongsy or 0),
                    'zongzhichu': float(shouzhijilu.zongzc or 0),
                    'jrls': float(shouzhijilu.jrls or 0),
                    'jrzc': float(shouzhijilu.jrzc or 0)
                }
            else:
                # 没有记录的情况，返回默认值
                huizongshuju = {
                    'zongliushui': 0.00,
                    'zongshouyi': 0.00,
                    'zongzhichu': 0.00,
                    'jrls': 0.00,
                    'jrzc': 0.00
                }

            # 7. 返回成功响应
            return Response({
                'code': 0,
                'msg': '获取成功',
                'data': huizongshuju
            })

        except Exception as e:
            # 【安全策略】任何异常都返回401，不暴露具体错误信息
            # 这里可以记录日志，但不返回给前端
            # import logging
            # logging.error(f'管理员财务数据接口异常: {str(e)}', exc_info=True)

            return Response(
                {'code': 401, 'msg': '获取失败', 'data': None},
                status=status.HTTP_401_UNAUTHORIZED
            )






# shangpin/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser
import logging

logger = logging.getLogger(__name__)


class AdGetOrderTypes(APIView):
    """
    后台获取订单类型列表接口
    前端调用地址: /shangpin/getOrderTypes
    前端需要字段: id, biaoti, tupian_url
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            # 1. 获取参数
            qianzhanghao = request.data.get('zhanghao', '').strip()

            if not qianzhanghao:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. 身份验证（按你说的方式）
            dangqianyonghu = request.user

            # 验证手机号
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证管理员身份
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 3. 验证管理员扩展表
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AttributeError:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 4. 查询订单类型（商品类型）表
            # 注意：这里需要根据你实际的模型名调整
            # 如果模型名不是ShangpinType，请告诉我正确的模型名

            # 假设模型名是ShangpinLeixing（因为我之前看到你有商品类型表）
            # 你需要告诉我确切的模型名
            try:
                # 请替换为你的实际模型名
                from shangpin.models import ShangpinLeixing  # 或者 ShangpinType
                # 只查询前端需要的三个字段
                shangpin_types = ShangpinLeixing.objects.all().only('id', 'jieshao', 'tupian_url')

                # 构建响应数据
                type_list = [
                    {
                        'id': item.id,
                        'biaoti': item.jieshao or '',
                        'tupian_url': item.tupian_url or ''
                    }
                    for item in shangpin_types
                ]


                return Response({
                    'code': 0,
                    'message': '获取成功',
                    'data': type_list
                })

            except Exception as e:
                logger.error(f"查询商品类型表失败: {str(e)}")
                # 如果表不存在，返回空数组
                return Response({
                    'code': 0,
                    'message': '获取成功',
                    'data': []
                })

        except Exception as e:
            logger.error(f"获取订单类型异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )





# yonghu/views.py 或 dingdan/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser
import logging
from django.db.models import Q, Count
import time

logger = logging.getLogger(__name__)


class AdGetDingdanList(APIView):
    """
    后台订单列表获取接口
    前端调用地址: /yonghu/adddhq
    前端需要字段: dingdan_id, jieshao, zhuangtai, leixing, fadanpingtai, jiage, tupian_url, fadanshijian
    统计字段: stats.platform.total, stats.platform.completed, stats.merchant.total, stats.merchant.completed
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            # 1. 获取参数（严格按前端传的字段名）
            qianzhanghao = request.data.get('zhanghao', '').strip()
            page = int(request.data.get('page', 1))
            page_size = int(request.data.get('pageSize', 30))

            # 搜索相关参数
            dingdan_id = request.data.get('dingdan_id', '').strip()

            # 筛选相关参数（严格按前端字段名）
            fadanpingtai = request.data.get('fadanpingtai')  # 前端叫 fadanpingtai
            leixing = request.data.get('leixing')  # 前端叫 leixing
            zhuangtai = request.data.get('zhuangtai', '')  # 前端叫 zhuangtai

            if not qianzhanghao:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. 身份验证（与你说的完全一样）
            dangqianyonghu = request.user

            # 验证手机号
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证管理员身份
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 3. 验证管理员扩展表
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AttributeError:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 4. 导入订单模型
            from dingdan.models import Dingdan  # 你的订单主表模型

            # 5. 构建查询条件（严格按前端字段名映射到数据库字段）
            query_conditions = Q()

            # 判断是否为搜索模式
            is_search_mode = bool(dingdan_id)

            if is_search_mode:
                # 搜索模式：只按订单ID查询
                query_conditions &= Q(dingdan_id=dingdan_id)
            else:
                # 筛选模式

                # 发单平台筛选（前端: fadanpingtai -> 数据库: fadan_pingtai）
                if fadanpingtai is not None:
                    try:
                        fadanpingtai_int = int(fadanpingtai)
                        if fadanpingtai_int in [1, 2]:
                            query_conditions &= Q(fadan_pingtai=fadanpingtai_int)
                    except (ValueError, TypeError):
                        pass

                # 订单类型筛选（前端: leixing -> 数据库: leixing_id）
                if leixing is not None:
                    try:
                        leixing_int = int(leixing)
                        query_conditions &= Q(leixing_id=leixing_int)
                    except (ValueError, TypeError):
                        pass

                # 订单状态筛选（前端: zhuangtai -> 数据库: zhuangtai）
                if zhuangtai and zhuangtai != 'all':
                    try:
                        # 处理多个状态，如 "1,7"
                        status_list = [int(s.strip()) for s in zhuangtai.split(',') if s.strip()]
                        if status_list:
                            query_conditions &= Q(zhuangtai__in=status_list)
                    except (ValueError, TypeError):
                        pass

            # 6. 获取统计数据（平台订单和商家订单）
            # 注意：这里统计所有订单，不考虑筛选条件
            try:
                # 平台订单统计 (fadan_pingtai=1)
                platform_total = Dingdan.objects.filter(fadan_pingtai=1).count()
                platform_completed = Dingdan.objects.filter(fadan_pingtai=1, zhuangtai=3).count()

                # 商家订单统计 (fadan_pingtai=2)
                merchant_total = Dingdan.objects.filter(fadan_pingtai=2).count()
                merchant_completed = Dingdan.objects.filter(fadan_pingtai=2, zhuangtai=3).count()

                platform_stats = {
                    'total': platform_total,
                    'completed': platform_completed
                }
                merchant_stats = {
                    'total': merchant_total,
                    'completed': merchant_completed
                }
            except Exception as e:
                logger.warning(f"统计数据查询失败: {str(e)}")
                platform_stats = {'total': 0, 'completed': 0}
                merchant_stats = {'total': 0, 'completed': 0}

            # 7. 执行分页查询（只查询主表，不查扩展表）
            start_time = time.time()

            # 计算分页
            offset = (page - 1) * page_size

            # 查询符合条件的订单总数
            total_count = Dingdan.objects.filter(query_conditions).count()

            # 查询当前页的数据（只查询主表，只查询前端需要的字段）
            dingdan_list = Dingdan.objects.filter(query_conditions).only(
                'dingdan_id', 'jieshao', 'zhuangtai', 'leixing_id',
                'fadan_pingtai', 'jine', 'tupian', 'create_time'
            ).order_by('-create_time')[offset:offset + page_size]

            query_time = time.time() - start_time
            logger.info(f"订单查询完成，耗时: {query_time:.3f}s，查询条数: {len(dingdan_list)}")

            # 8. 构建响应数据（严格按前端需要的字段）
            result_list = []

            for dingdan in dingdan_list:
                # 注意：这里字段名必须与前端完全一致
                order_data = {
                    'dingdan_id': dingdan.dingdan_id or '',
                    'jieshao': dingdan.jieshao or '',
                    'zhuangtai': dingdan.zhuangtai or 1,
                    'leixing': dingdan.leixing_id or 0,  # 前端需要 leixing
                    'fadanpingtai': dingdan.fadan_pingtai or 1,  # 前端需要 fadanpingtai
                    'jiage': float(dingdan.jine) if dingdan.jine else 0.00,  # 价格对应 jine 字段
                    'tupian_url': dingdan.tupian or '',  # 图片对应 tupian 字段
                    'fadanshijian': dingdan.create_time.strftime('%Y-%m-%d %H:%M:%S') if dingdan.create_time else ''
                }
                result_list.append(order_data)

            # 9. 判断是否有更多数据
            current_loaded_count = offset + len(result_list)
            has_more = len(result_list) >= page_size and current_loaded_count < total_count

            # 10. 构建完整响应（严格按前端需要的结构）
            response_data = {
                'stats': {
                    'platform': platform_stats,
                    'merchant': merchant_stats
                },
                'list': result_list,
                'hasMore': has_more,
                'total': total_count,
                'currentPage': page,
                'pageSize': page_size
            }

            return Response({
                'code': 0,
                'message': '获取成功',
                'data': response_data
            })

        except Exception as e:
            logger.error(f"获取订单列表异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )





from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser
from rest_framework import status
from django.db import transaction
import logging

# 获取日志器
logger = logging.getLogger(__name__)


class AdYaoQingDaShou(APIView):
    """
    后台获取邀请码接口（用于邀请打手）
    权限: JWT Token认证 + 管理员身份验证
    前端调用: POST /yonghu/adyqds
    参数: {
        "zhanghao": "管理员账号"
    }
    返回: {
        "code": 0,
        "message": "成功",
        "data": {
            "yaoqingma": "邀请码"
        }
    }
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            # 1. 获取前端参数
            qianzhanghao = request.data.get('zhanghao', '').strip()

            if not qianzhanghao:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. JWT Token身份验证
            dangqianyonghu = request.user

            # 3. 验证手机号是否匹配
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证用户类型是否为管理员
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 验证管理员扩展表是否存在
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AttributeError:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 获取用户ID（yonghuid），如果获取不到就用'123456'
            yonghuid_str = getattr(dangqianyonghu, 'yonghuid', '123456')

            # 7. 尝试获取或创建管事扩展表
            try:
                # 尝试获取现有的管事扩展表
                guanshi_profile = dangqianyonghu.guanshi_profile
            except AttributeError:
                # 管事扩展表不存在，创建一个
                try:
                    from yonghu.models import UserGuanshi

                    # 创建默认的管事扩展表
                    guanshi_profile = UserGuanshi.objects.create(
                        user=dangqianyonghu,
                        yaoqingma='',  # 暂时为空，后面生成
                        dianhua='',  # 默认空
                        wechat='',  # 默认空
                        yaogingshuliang=0,  # 邀请数量为0
                        zhuangtai=1,  # 正常状态
                        jinrichongzhi=0,  # 今日充值0
                        jinyuechongzhi=0,  # 今月充值0
                        chongzhifenrun=0,  # 充值分佣0
                        yue=0  # 余额0
                    )
                    #logger.info(f"为管理员{dangqianyonghu.yonghuid}创建了管事扩展表")
                except Exception as e:
                    logger.error(f"创建管事扩展表失败: {str(e)}")
                    return Response(
                        {'code': 500, 'message': '创建用户信息失败', 'data': None},
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR
                    )

            # 8. 检查是否已有邀请码
            existing_yaoqingma = guanshi_profile.yaoqingma

            if existing_yaoqingma and existing_yaoqingma.strip():
                # 已有邀请码，直接返回
                return Response({
                    'code': 0,
                    'message': '成功获取邀请码',
                    'data': {
                        'yaoqingma': existing_yaoqingma
                    }
                })

            # 9. 生成新的邀请码
            try:
                # 导入邀请码生成工具
                from utils.yaoqingma_generator import chuangjianYaoqingma

                # 生成邀请码
                new_yaoqingma = chuangjianYaoqingma(str(yonghuid_str))

                # 验证邀请码格式
                from utils.yaoqingma_generator import yanzhengYaoqingmaWeiyixing
                if not yanzhengYaoqingmaWeiyixing(new_yaoqingma):
                    raise Exception('邀请码格式验证失败')

            except ImportError:
                # 如果导入失败，使用简单方法生成邀请码
                import time
                import random
                import string

                timestamp = str(int(time.time()))
                random_str = ''.join(random.choices(string.ascii_uppercase + string.digits, k=8))
                new_yaoqingma = f"GL{timestamp[-6:]}{random_str}"

                logger.warning(f"使用简单方法生成邀请码: {new_yaoqingma}")
            except Exception as e:
                logger.error(f"生成邀请码失败: {str(e)}")
                return Response(
                    {'code': 500, 'message': '生成邀请码失败', 'data': None},
                    status=status.HTTP_500_INTERNAL_SERVER_ERROR
                )

            # 10. 保存邀请码到数据库
            try:
                with transaction.atomic():
                    guanshi_profile.yaoqingma = new_yaoqingma
                    guanshi_profile.save()

                    logger.info(f"管理员{dangqianyonghu.yonghuid}生成邀请码: {new_yaoqingma}")
            except Exception as e:
                logger.error(f"保存邀请码失败: {str(e)}")
                return Response(
                    {'code': 500, 'message': '保存邀请码失败', 'data': None},
                    status=status.HTTP_500_INTERNAL_SERVER_ERROR
                )

            # 11. 返回成功响应
            return Response({
                'code': 0,
                'message': '成功生成邀请码',
                'data': {
                    'yaoqingma': new_yaoqingma
                }
            })

        except Exception as e:
            logger.error(f"获取邀请码接口异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )



from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser
from rest_framework import status
from django.db.models import Q
import logging

logger = logging.getLogger(__name__)


class AdGuanLiYongHu(APIView):
    """
    后台用户管理列表接口
    权限: JWT Token认证 + 管理员身份验证
    前端调用: POST /yonghu/adgl
    参数: {
        "zhanghao": "管理员账号",
        "user_type": "用户类型(1-4)",
        "keyword": "搜索关键词(可选)",
        "page": "页码(从1开始)",
        "page_size": "每页数量"
    }
    返回: {
        "code": 0,
        "message": "成功",
        "data": {
            "list": [用户列表],
            "stats": {"1": 总数, "2": 总数, "3": 总数, "4": 总数},
            "has_more": true/false
        }
    }
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            # 1. 获取前端参数
            qianzhanghao = request.data.get('zhanghao', '').strip()
            user_type = request.data.get('user_type')
            keyword = request.data.get('keyword', '').strip()
            page = int(request.data.get('page', 1))
            page_size = int(request.data.get('page_size', 30))

            # 验证参数
            if not qianzhanghao or not user_type:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. JWT Token身份验证
            dangqianyonghu = request.user

            # 3. 验证手机号是否匹配
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证用户类型是否为管理员
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 验证管理员扩展表是否存在
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AttributeError:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 根据用户类型选择查询的模型
            user_type_int = int(user_type)

            if user_type_int not in [1, 2, 3, 4]:
                return Response(
                    {'code': 400, 'message': '用户类型错误', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 7. 统计四种用户类型的总数
            stats = self._get_user_stats()

            # 8. 根据用户类型查询用户列表
            user_list, has_more = self._query_users_by_type(
                user_type_int, keyword, page, page_size
            )

            # 9. 构建返回数据
            return Response({
                'code': 0,
                'message': '成功',
                'data': {
                    'list': user_list,
                    'stats': stats,
                    'has_more': has_more
                }
            })

        except ValueError:
            logger.error("参数类型错误")
            return Response(
                {'code': 400, 'message': '参数类型错误', 'data': None},
                status=status.HTTP_400_BAD_REQUEST
            )
        except Exception as e:
            logger.error(f"用户管理列表接口异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

    def _get_user_stats(self):
        """
        获取四种用户类型的统计数量
        """
        try:
            from yonghu.models import UserBoss, UserDashou, UserGuanshi, UserShangjia

            stats = {
                '1': UserBoss.objects.count(),
                '2': UserDashou.objects.count(),
                '3': UserGuanshi.objects.count(),
                '4': UserShangjia.objects.count()
            }

            return stats

        except Exception as e:
            logger.error(f"获取用户统计失败: {str(e)}")
            return {'1': 0, '2': 0, '3': 0, '4': 0}

    def _query_users_by_type(self, user_type_int, keyword, page, page_size):
        """
        根据用户类型查询用户列表
        返回: (用户列表, 是否还有更多数据)
        """
        try:
            # 计算偏移量
            offset = (page - 1) * page_size

            if user_type_int == 1:
                return self._query_boss_users(keyword, offset, page_size)
            elif user_type_int == 2:
                return self._query_dashou_users(keyword, offset, page_size)
            elif user_type_int == 3:
                return self._query_guanshi_users(keyword, offset, page_size)
            elif user_type_int == 4:
                return self._query_shangjia_users(keyword, offset, page_size)
            else:
                return [], False

        except Exception as e:
            logger.error(f"查询用户列表失败: {str(e)}")
            return [], False

    def _query_boss_users(self, keyword, offset, limit):
        """查询普通用户（老板）"""
        try:
            from yonghu.models import UserBoss

            queryset = UserBoss.objects.select_related('user')

            if keyword:
                queryset = queryset.filter(
                    Q(user__yonghuid__icontains=keyword) |
                    Q(nickname__icontains=keyword)
                )

            # 获取总数
            total_count = queryset.count()

            # 获取当前页的数据
            users = list(queryset.order_by('-create_time')[offset:offset + limit])

            # 计算是否有更多数据
            current_count = len(users)
            has_more = (offset + current_count) < total_count



            # 构建返回数据
            user_list = []
            for boss in users:
                user_main = boss.user

                user_data = {
                    'yonghuid': user_main.yonghuid,
                    'avatar': user_main.avatar or '',
                    'nicheng': boss.nickname or '',
                }

                user_list.append(user_data)

            return user_list, has_more

        except Exception as e:
            logger.error(f"查询老板用户失败: {str(e)}")
            return [], False

    def _query_dashou_users(self, keyword, offset, limit):
        """查询打手用户"""
        try:
            from yonghu.models import UserDashou

            queryset = UserDashou.objects.select_related('user')

            if keyword:
                queryset = queryset.filter(
                    Q(user__yonghuid__icontains=keyword) |
                    Q(nicheng__icontains=keyword) |
                    Q(chenghao__icontains=keyword)
                )

            # 获取总数
            total_count = queryset.count()

            # 获取当前页的数据
            dashou_list = list(queryset.order_by('-create_time')[offset:offset + limit])

            # 计算是否有更多数据
            current_count = len(dashou_list)
            has_more = (offset + current_count) < total_count



            # 构建返回数据
            user_list = []
            for dashou in dashou_list:
                user_main = dashou.user

                user_data = {
                    'yonghuid': user_main.yonghuid,
                    'avatar': user_main.avatar or '',
                    'zaixianzhuangtai': dashou.zaixianzhuangtai,
                    'zhanghaozhuangtai': dashou.zhanghaozhuangtai,
                    'nicheng': dashou.nicheng or '',
                    'zhuangtai': dashou.zhuangtai,
                }

                user_list.append(user_data)

            return user_list, has_more

        except Exception as e:
            logger.error(f"查询打手用户失败: {str(e)}")
            return [], False

    def _query_guanshi_users(self, keyword, offset, limit):
        """查询管事用户"""
        try:
            from yonghu.models import UserGuanshi

            queryset = UserGuanshi.objects.select_related('user')

            if keyword:
                queryset = queryset.filter(
                    Q(user__yonghuid__icontains=keyword)
                )

            # 获取总数
            total_count = queryset.count()

            # 获取当前页的数据
            guanshi_list = list(queryset.order_by('-create_time')[offset:offset + limit])

            # 计算是否有更多数据
            current_count = len(guanshi_list)
            has_more = (offset + current_count) < total_count



            # 构建返回数据
            user_list = []
            for guanshi in guanshi_list:
                user_main = guanshi.user

                user_data = {
                    'yonghuid': user_main.yonghuid,
                    'avatar': user_main.avatar or '',
                    'zhanghaozhuangtai': guanshi.zhuangtai,
                    'nicheng': f'管事{user_main.yonghuid}',
                }

                user_list.append(user_data)

            return user_list, has_more

        except Exception as e:
            logger.error(f"查询管事用户失败: {str(e)}")
            return [], False

    def _query_shangjia_users(self, keyword, offset, limit):
        """查询商家用户"""
        try:
            from yonghu.models import UserShangjia

            queryset = UserShangjia.objects.select_related('user')

            if keyword:
                queryset = queryset.filter(
                    Q(user__yonghuid__icontains=keyword) |
                    Q(nicheng__icontains=keyword)
                )

            # 获取总数
            total_count = queryset.count()

            # 获取当前页的数据
            shangjia_list = list(queryset.order_by('-create_time')[offset:offset + limit])

            # 计算是否有更多数据
            current_count = len(shangjia_list)
            has_more = (offset + current_count) < total_count



            # 构建返回数据
            user_list = []
            for shangjia in shangjia_list:
                user_main = shangjia.user

                user_data = {
                    'yonghuid': user_main.yonghuid,
                    'avatar': user_main.avatar or '',
                    'zhanghaozhuangtai': shangjia.zhuangtai,
                    'nicheng': shangjia.nicheng or '',
                }

                user_list.append(user_data)

            return user_list, has_more

        except Exception as e:
            logger.error(f"查询商家用户失败: {str(e)}")
            return [], False


from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser
from rest_framework import status
from django.db.models import Q
import logging

logger = logging.getLogger(__name__)


class CfGuanLi(APIView):
    """
    后台处罚管理列表接口
    权限: JWT Token认证 + 管理员身份验证
    前端调用: POST /yonghu/cfgl
    参数: {
        "zhanghao": "管理员账号",
        "qingqiu_tongji": true/false,  # 是否只请求统计信息
        "sqzhuangtai": 0 或 [1,2],     # 处罚申请状态筛选（可选）
        "page": "页码(从1开始)",       # 分页参数
        "page_size": "每页数量"        # 分页参数
    }
    返回: {
        "code": 0,
        "message": "成功",
        "data": {
            "list": [处罚记录列表],
            "zongshu": 总数,
            "daichuli": 待处理数量,
            "yichuli": 已处理数量,
            "haiyougengduo": true/false
        }
    }
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            # 1. 获取前端参数
            qianzhanghao = request.data.get('zhanghao', '').strip()
            qingqiu_tongji = request.data.get('qingqiu_tongji', False)
            sqzhuangtai = request.data.get('sqzhuangtai')
            page = int(request.data.get('page', 1))
            page_size = int(request.data.get('page_size', 30))

            # 验证参数
            if not qianzhanghao:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. JWT Token身份验证
            dangqianyonghu = request.user

            # 3. 验证手机号是否匹配
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证用户类型是否为管理员
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 验证管理员扩展表是否存在
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AttributeError:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 导入模型
            from dingdan.models import Chufajilu

            # 7. 获取统计信息（总是需要统计）
            zongshu = Chufajilu.objects.count()
            daichuli = Chufajilu.objects.filter(sqzhuangtai__in=[0, 3]).count()
            yichuli = Chufajilu.objects.filter(sqzhuangtai__in=[1, 2]).count()

            # 8. 如果只请求统计信息，直接返回
            if qingqiu_tongji:
                return Response({
                    'code': 0,
                    'message': '成功',
                    'data': {
                        'zongshu': zongshu,
                        'daichuli': daichuli,
                        'yichuli': yichuli
                    }
                })

            # 9. 构建查询集
            queryset = Chufajilu.objects.all()

            # 10. 根据状态筛选
            if sqzhuangtai is not None:
                if isinstance(sqzhuangtai, list):
                    # 如果是数组，表示多个状态
                    queryset = queryset.filter(sqzhuangtai__in=sqzhuangtai)
                else:
                    # 单个状态
                    queryset = queryset.filter(sqzhuangtai=sqzhuangtai)

            # 11. 获取总数（用于分页计算）
            total_count = queryset.count()

            # 12. 计算分页偏移量
            offset = (page - 1) * page_size

            # 13. 分页查询
            chufa_list = list(queryset.order_by('-create_time')[offset:offset + page_size])

            # 🔴【新增】高效获取图片信息
            if chufa_list:
                # 收集所有需要查询的组合
                dingdan_ids = []
                yonghu_combinations = []  # 保存 (dingdan_id, yonghuid) 组合

                for chufa in chufa_list:
                    if chufa.dingdan_id:
                        dingdan_ids.append(chufa.dingdan_id)
                        # 商家图片组合
                        if chufa.qingqiuid:
                            yonghu_combinations.append((chufa.dingdan_id, chufa.qingqiuid))
                        # 打手图片组合
                        if chufa.dashouid:
                            yonghu_combinations.append((chufa.dingdan_id, chufa.dashouid))

                # 去重
                dingdan_ids = list(set(dingdan_ids))
                yonghu_combinations = list(set(yonghu_combinations))

                # 🔴【新增】批量查询图片表（高效查询，避免循环）
                tupian_mapping = {}
                if yonghu_combinations:
                    # 导入图片模型
                    from dingdan.models import Chufatupian

                    # 构建查询条件
                    from django.db.models import Q
                    query_conditions = Q()
                    for dingdan_id, yonghuid in yonghu_combinations:
                        query_conditions |= Q(dingdan_id=dingdan_id, yonghuid=yonghuid)

                    # 批量查询
                    tupian_queryset = Chufatupian.objects.filter(query_conditions).values(
                        'dingdan_id', 'yonghuid', 'tupian'
                    )

                    # 构建映射：key为"dingdan_id_yonghuid"，value为图片URL列表
                    for item in tupian_queryset:
                        key = f"{item['dingdan_id']}_{item['yonghuid']}"
                        if key not in tupian_mapping:
                            tupian_mapping[key] = []
                        if item['tupian']:
                            tupian_mapping[key].append(item['tupian'])
            else:
                tupian_mapping = {}

            # 🔴【修改】14. 构建返回数据 - 添加图片和申诉理由字段
            chufa_data = []
            for chufa in chufa_list:
                # 🔴【新增】获取商家证据图片
                zhengju_tupian = []
                if chufa.dingdan_id and chufa.qingqiuid:
                    key = f"{chufa.dingdan_id}_{chufa.qingqiuid}"
                    zhengju_tupian = tupian_mapping.get(key, [])

                # 🔴【新增】获取打手申诉图片
                shensu_tupian = []
                if chufa.dingdan_id and chufa.dashouid:
                    key = f"{chufa.dingdan_id}_{chufa.dashouid}"
                    shensu_tupian = tupian_mapping.get(key, [])

                chufa_data.append({
                    'dashouid': chufa.dashouid,
                    'qingqiuid': chufa.qingqiuid,
                    'chuliid': chufa.chuliid,
                    'cfliyou': chufa.cfliyou,
                    'sqzhuangtai': chufa.sqzhuangtai,
                    'bhliyou': chufa.bhliyou,
                    'jifen': chufa.jifen,
                    'dingdan_id': chufa.dingdan_id,
                    'create_time': chufa.create_time,
                    'update_time': chufa.update_time,
                    # 🔴【新增】申诉理由字段
                    'ssliyou': chufa.ssliyou or '',
                    # 🔴【新增】商家证据图片
                    'zhengju_tupian': zhengju_tupian,
                    # 🔴【新增】打手申诉图片
                    'shensu_tupian': shensu_tupian,
                })

            # 15. 计算是否还有更多数据
            current_count = len(chufa_list)
            haiyougengduo = (offset + current_count) < total_count

            return Response({
                'code': 0,
                'message': '成功',
                'data': {
                    'list': chufa_data,
                    'zongshu': zongshu,
                    'daichuli': daichuli,
                    'yichuli': yichuli,
                    'haiyougengduo': haiyougengduo
                }
            })

        except ValueError:
            return Response(
                {'code': 400, 'message': '参数类型错误', 'data': None},
                status=status.HTTP_400_BAD_REQUEST
            )
        except Exception as e:
            logger.error(f"处罚管理列表接口异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )



'''class CfGuanLi(APIView):
    """
    后台处罚管理列表接口
    权限: JWT Token认证 + 管理员身份验证
    前端调用: POST /yonghu/cfgl
    参数: {
        "zhanghao": "管理员账号",
        "qingqiu_tongji": true/false,  # 是否只请求统计信息
        "sqzhuangtai": 0 或 [1,2],     # 处罚申请状态筛选（可选）
        "page": "页码(从1开始)",       # 分页参数
        "page_size": "每页数量"        # 分页参数
    }
    返回: {
        "code": 0,
        "message": "成功",
        "data": {
            "list": [处罚记录列表],
            "zongshu": 总数,
            "daichuli": 待处理数量,
            "yichuli": 已处理数量,
            "haiyougengduo": true/false
        }
    }
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            # 1. 获取前端参数
            qianzhanghao = request.data.get('zhanghao', '').strip()
            qingqiu_tongji = request.data.get('qingqiu_tongji', False)
            sqzhuangtai = request.data.get('sqzhuangtai')
            page = int(request.data.get('page', 1))
            page_size = int(request.data.get('page_size', 30))

            # 验证参数
            if not qianzhanghao:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. JWT Token身份验证
            dangqianyonghu = request.user

            # 3. 验证手机号是否匹配
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证用户类型是否为管理员
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 验证管理员扩展表是否存在
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AttributeError:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 导入模型
            from dingdan.models import Chufajilu

            # 7. 获取统计信息（总是需要统计）
            zongshu = Chufajilu.objects.count()
            daichuli = Chufajilu.objects.filter(sqzhuangtai=0).count()
            yichuli = Chufajilu.objects.filter(sqzhuangtai__in=[1, 2]).count()

            # 8. 如果只请求统计信息，直接返回
            if qingqiu_tongji:
                return Response({
                    'code': 0,
                    'message': '成功',
                    'data': {
                        'zongshu': zongshu,
                        'daichuli': daichuli,
                        'yichuli': yichuli
                    }
                })

            # 9. 构建查询集
            queryset = Chufajilu.objects.all()

            # 10. 根据状态筛选
            if sqzhuangtai is not None:
                if isinstance(sqzhuangtai, list):
                    # 如果是数组，表示多个状态
                    queryset = queryset.filter(sqzhuangtai__in=sqzhuangtai)
                else:
                    # 单个状态
                    queryset = queryset.filter(sqzhuangtai=sqzhuangtai)

            # 11. 获取总数（用于分页计算）
            total_count = queryset.count()

            # 12. 计算分页偏移量
            offset = (page - 1) * page_size

            # 13. 分页查询
            chufa_list = list(queryset.order_by('-create_time')[offset:offset + page_size])

            # 14. 构建返回数据
            chufa_data = []
            for chufa in chufa_list:
                chufa_data.append({
                    'dashouid': chufa.dashouid,
                    'qingqiuid': chufa.qingqiuid,
                    'chuliid': chufa.chuliid,
                    'cfliyou': chufa.cfliyou,
                    'sqzhuangtai': chufa.sqzhuangtai,
                    'bhliyou': chufa.bhliyou,
                    'jifen': chufa.jifen,
                    'dingdan_id': chufa.dingdan_id,
                    'create_time': chufa.create_time,
                    'update_time': chufa.update_time
                })

            # 15. 计算是否还有更多数据
            current_count = len(chufa_list)
            haiyougengduo = (offset + current_count) < total_count

            return Response({
                'code': 0,
                'message': '成功',
                'data': {
                    'list': chufa_data,
                    'zongshu': zongshu,
                    'daichuli': daichuli,
                    'yichuli': yichuli,
                    'haiyougengduo': haiyougengduo
                }
            })

        except ValueError:
            return Response(
                {'code': 400, 'message': '参数类型错误', 'data': None},
                status=status.HTTP_400_BAD_REQUEST
            )
        except Exception as e:
            logger.error(f"处罚管理列表接口异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )'''




logger = logging.getLogger(__name__)


class AdTongYiChuFa(APIView):
    """
    后台同意/驳回处罚接口（已修复重复记录问题）
    权限: JWT Token认证 + 管理员身份验证
    前端调用: POST /yonghu/adtycf
    参数: {
        "zhanghao": "管理员账号",
        "dingdan_id": "订单ID",
        "caozuo": 1或2,  # 1=同意处罚，2=拒绝处罚
        "bohui_liyou": "拒绝理由"  # 拒绝处罚时必填
    }
    返回: {
        "code": 0,
        "message": "成功",
        "data": null
    }
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            # 1. 获取前端参数
            qianzhanghao = request.data.get('zhanghao', '').strip()
            dingdan_id = request.data.get('dingdan_id', '').strip()
            caozuo = request.data.get('caozuo')  # 1=同意，2=拒绝
            bohui_liyou = request.data.get('bohui_liyou', '').strip()

            # 验证参数
            if not qianzhanghao or not dingdan_id or caozuo is None:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证操作类型
            if caozuo not in [1, 2]:
                return Response(
                    {'code': 400, 'message': '操作类型错误', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 如果是拒绝处罚，需要拒绝理由
            if caozuo == 2 and not bohui_liyou:
                return Response(
                    {'code': 400, 'message': '拒绝处罚需要填写理由', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. JWT Token身份验证
            dangqianyonghu = request.user

            # 3. 验证手机号是否匹配
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证用户类型是否为管理员
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 验证管理员扩展表是否存在
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AttributeError:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 使用事务保证数据一致性
            with transaction.atomic():
                # 7. 导入模型
                from dingdan.models import Chufajilu, Dingdan, DingdanShangjia
                from yonghu.models import UserDashou

                # 8. 🔴 修复：查询处罚记录（处理重复记录问题）
                # 使用 filter().first() 而不是 get()，以防出现多条记录
                chufajilu = Chufajilu.objects.filter(
                    dingdan_id=dingdan_id,
                    sqzhuangtai__in=[0, 3]  # 🔴【修改】包括待处理和申诉中状态
                ).order_by('-create_time').first()  # 取最新的一条

                if not chufajilu:
                    # 如果没有待处理的处罚记录，检查是否有已处理的
                    exists_processed = Chufajilu.objects.filter(dingdan_id=dingdan_id).exists()
                    if exists_processed:
                        return Response(
                            {'code': 400, 'message': '该处罚记录已处理', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                    else:
                        return Response(
                            {'code': 404, 'message': '处罚记录不存在', 'data': None},
                            status=status.HTTP_404_NOT_FOUND
                        )

                # 9. 验证处罚记录状态（必须是待处理或申诉中状态才能处理）
                if chufajilu.sqzhuangtai not in [0, 3]:  # 🔴【修改】包括待处理(0)和申诉中(3)
                    return Response(
                        {'code': 400, 'message': '该处罚记录已处理', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 10. 🔴 修复：检查是否有重复的待处理/申诉中记录，并记录警告
                duplicate_count = Chufajilu.objects.filter(
                    dingdan_id=dingdan_id,
                    sqzhuangtai__in=[0, 3]  # 🔴【修改】包括待处理和申诉中
                ).count()

                if duplicate_count > 1:
                    # 记录警告日志
                    logger.warning(f"订单ID {dingdan_id} 存在 {duplicate_count} 条待处理/申诉中处罚记录，处理最新的一条")

                    # 🔴 可选：将其他重复的待处理/申诉中记录标记为已拒绝
                    # 防止用户重复提交相同订单的处罚申请
                    duplicate_records = Chufajilu.objects.filter(
                        dingdan_id=dingdan_id,
                        sqzhuangtai__in=[0, 3]  # 🔴【修改】包括待处理和申诉中
                    ).exclude(id=chufajilu.id)

                    for dup in duplicate_records:
                        dup.sqzhuangtai = 2  # 已拒绝
                        dup.chuliid = qianzhanghao
                        dup.bhliyou = "系统自动拒绝：存在重复处罚记录"
                        dup.save()

                # 11. 根据操作类型处理
                if caozuo == 1:
                    # 同意处罚 - 不扣分，只改状态
                    # 11.1 检查打手是否存在
                    if not chufajilu.dashouid:
                        return Response(
                            {'code': 400, 'message': '被处罚打手ID不存在', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )

                    # 11.2 查询打手扩展表（只是验证存在性）
                    try:
                        dashou = UserDashou.objects.get(user__yonghuid=chufajilu.dashouid)
                    except UserDashou.DoesNotExist:
                        return Response(
                            {'code': 404, 'message': '被处罚打手不存在', 'data': None},
                            status=status.HTTP_404_NOT_FOUND
                        )

                    # 🔴【修改】11.3 同意处罚时不扣分（因为申请时已经扣了），只更新状态
                    chufajilu.sqzhuangtai = 1  # 已处罚
                    chufajilu.chuliid = qianzhanghao  # 处理人ID为管理员账号
                    chufajilu.save()

                    # 11.4 更新商家订单扩展表
                    try:
                        dingdan = Dingdan.objects.get(dingdan_id=dingdan_id)
                        if hasattr(dingdan, 'shangjia_kuozhan'):
                            shangjia_kuozhan = dingdan.shangjia_kuozhan
                            shangjia_kuozhan.sqzhuangtai = 1  # 已处罚
                            shangjia_kuozhan.save()
                    except (Dingdan.DoesNotExist, AttributeError):
                        # 如果订单或扩展表不存在，继续执行，不中断
                        pass

                    logger.info(f"同意处罚成功：订单ID={dingdan_id}，打手ID={chufajilu.dashouid}")

                elif caozuo == 2:
                    # 拒绝处罚 - 需要返还积分（加分）
                    # 🔴【新增】11.5 返还打手积分（加5分）
                    if chufajilu.jifen > 0:
                        try:
                            dashou = UserDashou.objects.get(user__yonghuid=chufajilu.dashouid)

                            # 🔴【新增】安全验证：必须积分小于等于5分才允许加分
                            if dashou.jifen <= 5:  # 判断积分是否小于等于5分
                                dashou.jifen += chufajilu.jifen  # 加5分
                                dashou.save()
                                logger.info(
                                    f"拒绝处罚，给打手{dashou.user.yonghuid}返还积分{chufajilu.jifen}分，当前积分{dashou.jifen}")
                            else:
                                # 积分已超过5分，可能是异常情况，记录警告但不中断处理
                                logger.warning(
                                    f"拒绝处罚时打手积分异常：打手ID={chufajilu.dashouid}，当前积分{dashou.jifen}已超过5分，不再加分")
                        except UserDashou.DoesNotExist:
                            # 打手不存在，记录错误，但继续处理状态
                            logger.error(f"拒绝处罚时打手不存在：打手ID={chufajilu.dashouid}")

                    # 11.6 更新处罚记录
                    chufajilu.sqzhuangtai = 2  # 已拒绝
                    chufajilu.chuliid = qianzhanghao  # 处理人ID为管理员账号
                    chufajilu.bhliyou = bohui_liyou  # 拒绝理由
                    chufajilu.save()

                    # 11.7 更新商家订单扩展表
                    try:
                        dingdan = Dingdan.objects.get(dingdan_id=dingdan_id)
                        if hasattr(dingdan, 'shangjia_kuozhan'):
                            shangjia_kuozhan = dingdan.shangjia_kuozhan
                            shangjia_kuozhan.sqzhuangtai = 2  # 已拒绝
                            shangjia_kuozhan.bhliyou = bohui_liyou  # 拒绝理由
                            shangjia_kuozhan.save()
                    except (Dingdan.DoesNotExist, AttributeError):
                        # 如果订单或扩展表不存在，继续执行，不中断
                        pass

                    logger.info(f"拒绝处罚成功：订单ID={dingdan_id}，拒绝理由={bohui_liyou}")

                # 12. 返回成功响应
                return Response({
                    'code': 0,
                    'message': '处理成功',
                    'data': None
                })

        except ValueError:
            return Response(
                {'code': 400, 'message': '参数类型错误', 'data': None},
                status=status.HTTP_400_BAD_REQUEST
            )
        except Exception as e:
            logger.error(f"处理处罚接口异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )



'''class AdTongYiChuFa(APIView):
    """
    后台同意/驳回处罚接口（已修复重复记录问题）
    权限: JWT Token认证 + 管理员身份验证
    前端调用: POST /yonghu/adtycf
    参数: {
        "zhanghao": "管理员账号",
        "dingdan_id": "订单ID",
        "caozuo": 1或2,  # 1=同意处罚，2=驳回处罚
        "bohui_liyou": "驳回理由"  # 驳回处罚时必填
    }
    返回: {
        "code": 0,
        "message": "成功",
        "data": null
    }
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            # 1. 获取前端参数
            qianzhanghao = request.data.get('zhanghao', '').strip()
            dingdan_id = request.data.get('dingdan_id', '').strip()
            caozuo = request.data.get('caozuo')  # 1=同意，2=驳回
            bohui_liyou = request.data.get('bohui_liyou', '').strip()

            # 验证参数
            if not qianzhanghao or not dingdan_id or caozuo is None:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证操作类型
            if caozuo not in [1, 2]:
                return Response(
                    {'code': 400, 'message': '操作类型错误', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 如果是驳回处罚，需要驳回理由
            if caozuo == 2 and not bohui_liyou:
                return Response(
                    {'code': 400, 'message': '驳回处罚需要填写理由', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. JWT Token身份验证
            dangqianyonghu = request.user

            # 3. 验证手机号是否匹配
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证用户类型是否为管理员
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 验证管理员扩展表是否存在
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AttributeError:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 使用事务保证数据一致性
            with transaction.atomic():
                # 7. 导入模型
                from dingdan.models import Chufajilu, Dingdan, DingdanShangjia
                from yonghu.models import UserDashou

                # 8. 🔴 修复：查询处罚记录（处理重复记录问题）
                # 使用 filter().first() 而不是 get()，以防出现多条记录
                chufajilu = Chufajilu.objects.filter(
                    dingdan_id=dingdan_id,
                    sqzhuangtai=0  # 只查询待处理状态的记录
                ).order_by('-create_time').first()  # 取最新的一条

                if not chufajilu:
                    # 如果没有待处理的处罚记录，检查是否有已处理的
                    exists_processed = Chufajilu.objects.filter(dingdan_id=dingdan_id).exists()
                    if exists_processed:
                        return Response(
                            {'code': 400, 'message': '该处罚记录已处理', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                    else:
                        return Response(
                            {'code': 404, 'message': '处罚记录不存在', 'data': None},
                            status=status.HTTP_404_NOT_FOUND
                        )

                # 9. 验证处罚记录状态（必须是待处理状态才能处理）
                if chufajilu.sqzhuangtai != 0:
                    return Response(
                        {'code': 400, 'message': '该处罚记录已处理', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 10. 🔴 修复：检查是否有重复的待处理记录，并记录警告
                duplicate_count = Chufajilu.objects.filter(
                    dingdan_id=dingdan_id,
                    sqzhuangtai=0
                ).count()

                if duplicate_count > 1:
                    # 记录警告日志
                    logger.warning(f"订单ID {dingdan_id} 存在 {duplicate_count} 条待处理处罚记录，处理最新的一条")

                    # 🔴 可选：将其他重复的待处理记录标记为已驳回
                    # 防止用户重复提交相同订单的处罚申请
                    duplicate_records = Chufajilu.objects.filter(
                        dingdan_id=dingdan_id,
                        sqzhuangtai=0
                    ).exclude(id=chufajilu.id)

                    for dup in duplicate_records:
                        dup.sqzhuangtai = 2  # 已驳回
                        dup.chuliid = qianzhanghao
                        dup.bhliyou = "系统自动驳回：存在重复处罚记录"
                        dup.save()

                # 11. 根据操作类型处理
                if caozuo == 1:
                    # 同意处罚
                    # 11.1 检查打手是否存在
                    if not chufajilu.dashouid:
                        return Response(
                            {'code': 400, 'message': '被处罚打手ID不存在', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )

                    # 11.2 查询打手扩展表
                    try:
                        dashou = UserDashou.objects.get(user__yonghuid=chufajilu.dashouid)
                    except UserDashou.DoesNotExist:
                        return Response(
                            {'code': 404, 'message': '被处罚打手不存在', 'data': None},
                            status=status.HTTP_404_NOT_FOUND
                        )

                    # 11.3 扣除打手积分（确保积分不为负数）
                    jifen_kouchu = chufajilu.jifen
                    if jifen_kouchu > 0:
                        # 检查积分是否足够
                        if dashou.jifen < jifen_kouchu:
                            # 如果积分不足，设置为0
                            dashou.jifen = 0
                        else:
                            dashou.jifen -= jifen_kouchu
                        dashou.save()

                    # 11.4 更新处罚记录
                    chufajilu.sqzhuangtai = 1  # 已处罚
                    chufajilu.chuliid = qianzhanghao  # 处理人ID为管理员账号
                    chufajilu.save()

                    # 11.5 更新商家订单扩展表
                    try:
                        dingdan = Dingdan.objects.get(dingdan_id=dingdan_id)
                        if hasattr(dingdan, 'shangjia_kuozhan'):
                            shangjia_kuozhan = dingdan.shangjia_kuozhan
                            shangjia_kuozhan.sqzhuangtai = 1  # 已处罚
                            shangjia_kuozhan.save()
                    except (Dingdan.DoesNotExist, AttributeError):
                        # 如果订单或扩展表不存在，继续执行，不中断
                        pass

                    #logger.info(f"同意处罚成功：订单ID={dingdan_id}，打手ID={chufajilu.dashouid}，扣除积分={jifen_kouchu}")

                elif caozuo == 2:
                    # 驳回处罚
                    # 11.6 更新处罚记录
                    chufajilu.sqzhuangtai = 2  # 已驳回
                    chufajilu.chuliid = qianzhanghao  # 处理人ID为管理员账号
                    chufajilu.bhliyou = bohui_liyou  # 驳回理由
                    chufajilu.save()

                    # 11.7 更新商家订单扩展表
                    try:
                        dingdan = Dingdan.objects.get(dingdan_id=dingdan_id)
                        if hasattr(dingdan, 'shangjia_kuozhan'):
                            shangjia_kuozhan = dingdan.shangjia_kuozhan
                            shangjia_kuozhan.sqzhuangtai = 2  # 已驳回
                            shangjia_kuozhan.bhliyou = bohui_liyou  # 驳回理由
                            shangjia_kuozhan.save()
                    except (Dingdan.DoesNotExist, AttributeError):
                        # 如果订单或扩展表不存在，继续执行，不中断
                        pass

                    #logger.info(f"驳回处罚成功：订单ID={dingdan_id}，驳回理由={bohui_liyou}")

                # 12. 返回成功响应
                return Response({
                    'code': 0,
                    'message': '处理成功',
                    'data': None
                })

        except ValueError:
            return Response(
                {'code': 400, 'message': '参数类型错误', 'data': None},
                status=status.HTTP_400_BAD_REQUEST
            )
        except Exception as e:
            logger.error(f"处理处罚接口异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )'''


'''class AdTongYiChuFa(APIView):
    """
    后台同意/驳回处罚接口
    权限: JWT Token认证 + 管理员身份验证
    前端调用: POST /yonghu/adtycf
    参数: {
        "zhanghao": "管理员账号",
        "dingdan_id": "订单ID",
        "caozuo": 1或2,  # 1=同意处罚，2=驳回处罚
        "bohui_liyou": "驳回理由"  # 驳回处罚时必填
    }
    返回: {
        "code": 0,
        "message": "成功",
        "data": null
    }
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            # 1. 获取前端参数
            qianzhanghao = request.data.get('zhanghao', '').strip()
            dingdan_id = request.data.get('dingdan_id', '').strip()
            caozuo = request.data.get('caozuo')  # 1=同意，2=驳回
            bohui_liyou = request.data.get('bohui_liyou', '').strip()

            # 验证参数
            if not qianzhanghao or not dingdan_id or caozuo is None:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证操作类型
            if caozuo not in [1, 2]:
                return Response(
                    {'code': 400, 'message': '操作类型错误', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 如果是驳回处罚，需要驳回理由
            if caozuo == 2 and not bohui_liyou:
                return Response(
                    {'code': 400, 'message': '驳回处罚需要填写理由', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. JWT Token身份验证
            dangqianyonghu = request.user

            # 3. 验证手机号是否匹配
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证用户类型是否为管理员
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 验证管理员扩展表是否存在
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AttributeError:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 使用事务保证数据一致性
            with transaction.atomic():
                # 7. 导入模型
                from dingdan.models import Chufajilu, Dingdan, DingdanShangjia
                from yonghu.models import UserDashou

                # 8. 查询处罚记录
                try:
                    chufajilu = Chufajilu.objects.get(dingdan_id=dingdan_id)
                except Chufajilu.DoesNotExist:
                    return Response(
                        {'code': 404, 'message': '处罚记录不存在', 'data': None},
                        status=status.HTTP_404_NOT_FOUND
                    )

                # 9. 验证处罚记录状态（必须是待处理状态才能处理）
                if chufajilu.sqzhuangtai != 0:
                    return Response(
                        {'code': 400, 'message': '该处罚记录已处理', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 10. 根据操作类型处理
                if caozuo == 1:
                    # 同意处罚
                    # 10.1 检查打手是否存在
                    if not chufajilu.dashouid:
                        return Response(
                            {'code': 400, 'message': '被处罚打手ID不存在', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )

                    # 10.2 查询打手扩展表
                    try:
                        dashou = UserDashou.objects.get(user__yonghuid=chufajilu.dashouid)
                    except UserDashou.DoesNotExist:
                        return Response(
                            {'code': 404, 'message': '被处罚打手不存在', 'data': None},
                            status=status.HTTP_404_NOT_FOUND
                        )

                    # 10.3 扣除打手积分（确保积分不为负数）
                    jifen_kouchu = chufajilu.jifen
                    if jifen_kouchu > 0:
                        # 检查积分是否足够
                        if dashou.jifen < jifen_kouchu:
                            # 如果积分不足，设置为0
                            dashou.jifen = 0
                        else:
                            dashou.jifen -= jifen_kouchu
                        dashou.save()

                    # 10.4 更新处罚记录
                    chufajilu.sqzhuangtai = 1  # 已处罚
                    chufajilu.chuliid = qianzhanghao  # 处理人ID为管理员账号
                    chufajilu.save()

                    # 10.5 更新商家订单扩展表
                    try:
                        dingdan = Dingdan.objects.get(dingdan_id=dingdan_id)
                        shangjia_kuozhan = dingdan.shangjia_kuozhan
                        shangjia_kuozhan.sqzhuangtai = 1  # 已处罚
                        shangjia_kuozhan.save()
                    except (Dingdan.DoesNotExist, AttributeError):
                        # 如果订单或扩展表不存在，继续执行，不中断
                        pass

                    #logger.info(f"同意处罚成功：订单ID={dingdan_id}，打手ID={chufajilu.dashouid}，扣除积分={jifen_kouchu}")

                elif caozuo == 2:
                    # 驳回处罚
                    # 10.6 更新处罚记录
                    chufajilu.sqzhuangtai = 2  # 已驳回
                    chufajilu.chuliid = qianzhanghao  # 处理人ID为管理员账号
                    chufajilu.bhliyou = bohui_liyou  # 驳回理由
                    chufajilu.save()

                    # 10.7 更新商家订单扩展表
                    try:
                        dingdan = Dingdan.objects.get(dingdan_id=dingdan_id)
                        shangjia_kuozhan = dingdan.shangjia_kuozhan
                        shangjia_kuozhan.sqzhuangtai = 2  # 已驳回
                        shangjia_kuozhan.bhliyou = bohui_liyou  # 驳回理由
                        shangjia_kuozhan.save()
                    except (Dingdan.DoesNotExist, AttributeError):
                        # 如果订单或扩展表不存在，继续执行，不中断
                        pass

                    #logger.info(f"驳回处罚成功：订单ID={dingdan_id}，驳回理由={bohui_liyou}")

                # 11. 返回成功响应
                return Response({
                    'code': 0,
                    'message': '处理成功',
                    'data': None
                })

        except ValueError:
            return Response(
                {'code': 400, 'message': '参数类型错误', 'data': None},
                status=status.HTTP_400_BAD_REQUEST
            )
        except Exception as e:
            logger.error(f"处理处罚接口异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )'''





# yonghu/views.py
from django.utils import timezone
from datetime import timedelta
from decimal import Decimal
from django.db import transaction
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework import status
from .models import (
    UserMain, UserBoss, UserDashou, UserShangjia, UserGuanshi,
    AdminProfile, Xiugaijilu
)
from shangpin.models import Huiyuan, Huiyuangoumai


class AdckyhxqView(APIView):
    """
    获取用户详情接口
    前端需要传递: zhanghao, uid, user_type
    返回用户信息和会员列表
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # ==================== 管理员身份验证 ====================
            # 1. 验证JWT Token
            if not request.user.is_authenticated:
                return Response({
                    'code': 401,
                    'message': '未认证',
                    'data': None
                }, status=status.HTTP_401_UNAUTHORIZED)

            # 2. 验证用户类型为管理员
            if request.user.user_type != 'admin':
                return Response({
                    'code': 403,
                    'message': '权限不足',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 3. 验证管理员扩展表存在
            admin_profile = getattr(request.user, 'admin_profile', None)
            if not admin_profile:
                return Response({
                    'code': 403,
                    'message': '管理员信息不完整',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 4. 验证管理员账号（phone）与前端传递的zhanghao一致
            zhanghao = request.data.get('zhanghao')
            if not zhanghao or request.user.phone != zhanghao:
                return Response({
                    'code': 401,
                    'message': '账号验证失败',
                    'data': None
                }, status=status.HTTP_401_UNAUTHORIZED)
            # ==================== 身份验证结束 ====================

            # 获取业务参数
            uid = request.data.get('uid')  # 用户ID (yonghuid)
            user_type = request.data.get('user_type')  # 用户类型 (1,2,3,4)

            if not uid or not user_type:
                return Response({
                    'code': 400,
                    'message': '参数缺失',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 验证用户类型
            try:
                user_type = int(user_type)
                if user_type not in [1, 2, 3, 4]:
                    raise ValueError
            except ValueError:
                return Response({
                    'code': 400,
                    'message': '用户类型无效',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 查询用户主表 - 使用select_related优化查询
            user_main = UserMain.objects.filter(yonghuid=uid).first()
            if not user_main:
                return Response({
                    'code': 404,
                    'message': '用户不存在',
                    'data': None
                }, status=status.HTTP_404_NOT_FOUND)

            # 构建响应数据
            response_data = {
                'user_info': {},
                'member_list': [],
                'all_member_list': []
            }

            # 通用字段（所有用户都有）
            user_info = {
                'yonghuid': user_main.yonghuid,
                'avatar': user_main.avatar,
                'phone': user_main.phone,
                'ip': user_main.ip,
                'create_time': user_main.create_time,
                'update_time': user_main.update_time,
                'user_type': user_type
            }

            # 根据用户类型查询扩展信息
            if user_type == 1:  # 老板
                # 使用select_related预取boss_profile
                user_main = UserMain.objects.filter(yonghuid=uid).select_related('boss_profile').first()
                if user_main.boss_profile:
                    boss_profile = user_main.boss_profile
                    user_info.update({
                        'nickname': boss_profile.nickname,
                        'zonge': boss_profile.zonge,
                        'alldingdan': boss_profile.alldingdan,
                        'alltui': boss_profile.alltui,
                        'create_time_boss': boss_profile.create_time
                    })

            elif user_type == 2:  # 打手
                # 使用select_related预取dashou_profile
                user_main = UserMain.objects.filter(yonghuid=uid).select_related('dashou_profile').first()
                if user_main.dashou_profile:
                    dashou_profile = user_main.dashou_profile

                    # 构建打手信息
                    user_info.update({
                        'nicheng': dashou_profile.nicheng,
                        'chenghao': dashou_profile.chenghao,
                        'zhuangtai': dashou_profile.zhuangtai,
                        'zaixianzhuangtai': dashou_profile.zaixianzhuangtai,
                        'zhanghaozhuangtai': dashou_profile.zhanghaozhuangtai,
                        'jieshao': dashou_profile.jieshao,
                        'jiedanzongliang': dashou_profile.jiedanzongliang,
                        'chengjiaozongliang': dashou_profile.chengjiaozongliang,
                        'tuikuanliang': dashou_profile.tuikuanliang,
                        'yue': dashou_profile.yue,  # 打手可提现余额
                        'zonge': dashou_profile.zonge,  # 打手赚取总额
                        'dianhua': dashou_profile.dianhua,
                        'wechat': dashou_profile.wechat,
                        'yaoqingren': dashou_profile.yaoqingren,
                        'jinrijiedan': dashou_profile.jinrijiedan,
                        'jinrishouyi': dashou_profile.jinrishouyi,
                        'jinyuejiedan': dashou_profile.jinyuejiedan,
                        'jinyueshouyi': dashou_profile.jinyueshouyi,
                        'jifen': dashou_profile.jifen,
                        'yajin': dashou_profile.yajin,
                        'create_time_dashou': dashou_profile.create_time
                    })

                    # 查询打手的会员信息（只返回未过期的）
                    # 使用select_related预取huiyuan信息（如果有关联的话）
                    member_records = Huiyuangoumai.objects.filter(
                        yonghu_id=uid
                    ).order_by('-create_time')

                    member_list = []
                    for record in member_records:
                        # 调用方法检查是否过期，并更新状态
                        is_expired = record.jiance_shifou_daoqi()

                        if not is_expired:  # 只返回未过期的
                            # 查询会员详情
                            huiyuan = Huiyuan.objects.filter(
                                huiyuan_id=record.huiyuan_id
                            ).first()

                            if huiyuan:
                                member_list.append({
                                    'huiyuan_id': record.huiyuan_id,
                                    'huiyuan_name': huiyuan.jieshao,
                                    'daoqi_time': record.daoqi_time,
                                    'is_active': record.huiyuan_zhuangtai == 1,
                                    'create_time': record.create_time
                                })

                    response_data['member_list'] = member_list

            elif user_type == 3:  # 管事
                # 使用select_related预取guanshi_profile
                user_main = UserMain.objects.filter(yonghuid=uid).select_related('guanshi_profile').first()
                if user_main.guanshi_profile:
                    guanshi_profile = user_main.guanshi_profile
                    user_info.update({
                        'nicheng': user_main.phone,  # 管事昵称用手机号
                        'yaoqingma': guanshi_profile.yaoqingma,
                        'dianhua': guanshi_profile.dianhua,
                        'wechat': guanshi_profile.wechat,
                        'yaogingshuliang': guanshi_profile.yaogingshuliang,
                        'zhuangtai': guanshi_profile.zhuangtai,
                        'jinrichongzhi': guanshi_profile.jinrichongzhi,
                        'jinyuechongzhi': guanshi_profile.jinyuechongzhi,
                        'chongzhifenrun': guanshi_profile.chongzhifenrun,
                        'yue': guanshi_profile.yue,  # 管事可提现余额
                        'create_time_guanshi': guanshi_profile.create_time
                    })

            elif user_type == 4:  # 商家
                # 使用select_related预取shop_profile
                user_main = UserMain.objects.filter(yonghuid=uid).select_related('shop_profile').first()
                if user_main.shop_profile:
                    shop_profile = user_main.shop_profile
                    user_info.update({
                        'nicheng': shop_profile.nicheng,
                        'zhuangtai': shop_profile.zhuangtai,
                        'dianhua': shop_profile.dianhua,
                        'wechat': shop_profile.wechat,
                        'fabu': shop_profile.fabu,
                        'tuikuan': shop_profile.tuikuan,
                        'yue': shop_profile.yue,  # 商家余额
                        'chengjiao': shop_profile.chengjiao,
                        'jinridingdan': shop_profile.jinridingdan,
                        'jinriliushui': shop_profile.jinriliushui,
                        'jinyuedingdan': shop_profile.jinyuedingdan,
                        'jinyueliushui': shop_profile.jinyueliushui,
                        'create_time_shop': shop_profile.create_time
                    })

            # 获取所有会员列表（用于前端下拉选择）
            all_huiyuan = Huiyuan.objects.all().order_by('jiage')
            all_member_list = [
                {
                    'id': huiyuan.huiyuan_id,
                    'nicheng': huiyuan.jieshao,
                    'jiage': huiyuan.jiage,
                    'jieshao': huiyuan.jtjieshao
                }
                for huiyuan in all_huiyuan
            ]

            response_data['user_info'] = user_info
            response_data['all_member_list'] = all_member_list

            return Response({
                'code': 0,
                'message': '获取成功',
                'data': response_data
            }, status=status.HTTP_200_OK)

        except Exception as e:
            return Response({
                'code': 500,
                'message': f'获取用户详情失败: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class AdcjxgView(APIView):
    """
    修改用户信息接口
    前端需要传递: zhanghao, uid, user_type, 以及其他修改的字段
    支持打手会员添加功能
    敏感字段修改会记录到修改记录表
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # ==================== 管理员身份验证 ====================
            if not request.user.is_authenticated:
                return Response({
                    'code': 401,
                    'message': '未认证',
                    'data': None
                }, status=status.HTTP_401_UNAUTHORIZED)

            if request.user.user_type != 'admin':
                return Response({
                    'code': 403,
                    'message': '权限不足',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            admin_profile = getattr(request.user, 'admin_profile', None)
            if not admin_profile:
                return Response({
                    'code': 403,
                    'message': '管理员信息不完整',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            zhanghao = request.data.get('zhanghao')
            if not zhanghao or request.user.phone != zhanghao:
                return Response({
                    'code': 401,
                    'message': '账号验证失败',
                    'data': None
                }, status=status.HTTP_401_UNAUTHORIZED)
            # ==================== 身份验证结束 ====================

            # 获取业务参数
            uid = request.data.get('uid')
            user_type = request.data.get('user_type')

            if not uid or not user_type:
                return Response({
                    'code': 400,
                    'message': '参数缺失',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            try:
                user_type = int(user_type)
                if user_type not in [1, 2, 3, 4]:
                    raise ValueError
            except ValueError:
                return Response({
                    'code': 400,
                    'message': '用户类型无效',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 查询用户主表
            user_main = UserMain.objects.filter(yonghuid=uid).first()
            if not user_main:
                return Response({
                    'code': 404,
                    'message': '用户不存在',
                    'data': None
                }, status=status.HTTP_404_NOT_FOUND)

            # 使用事务确保数据一致性
            with transaction.atomic():
                # 存储修改记录的数据
                modify_record_data = {
                    'yonghuid': uid,
                    'xiugaiid': zhanghao,
                    'leixing': user_type,
                    'qitashuoming': '',
                    'create_time': timezone.now()
                }

                # 标记是否有敏感字段被修改
                has_sensitive_change = False

                if user_type == 1:  # 老板 - 不允许修改
                    return Response({
                        'code': 403,
                        'message': '老板信息不允许修改',
                        'data': None
                    }, status=status.HTTP_403_FORBIDDEN)

                elif user_type == 2:  # 打手
                    # 获取或创建打手扩展记录
                    dashou_profile, created = UserDashou.objects.get_or_create(
                        user=user_main,
                        defaults={'nicheng': user_main.phone or f'打手{uid}'}
                    )

                    # 记录敏感字段的旧值
                    old_yue = dashou_profile.yue  # 打手可提现余额
                    old_zonge = dashou_profile.zonge  # 打手提现金额
                    old_jifen = dashou_profile.jifen  # 打手积分
                    old_yajin = dashou_profile.yajin  # 打手押金

                    # 需要更新的字段列表
                    update_fields = [
                        'chenghao', 'dianhua', 'yue', 'zonge', 'jifen',
                        'yajin', 'yaoqingren', 'jieshao', 'zhuangtai',
                        'zaixianzhuangtai', 'zhanghaozhuangtai'
                    ]

                    # 记录被修改的字段
                    modified_fields = []

                    for field in update_fields:
                        if field in request.data:
                            new_value = request.data.get(field)
                            old_value = getattr(dashou_profile, field)

                            # 检查值是否改变
                            if str(new_value) != str(old_value):
                                # 处理特殊字段类型
                                if field in ['yue', 'zonge', 'yajin']:
                                    new_value = Decimal(str(new_value))
                                    setattr(dashou_profile, field, new_value)
                                elif field in ['jifen']:
                                    new_value = int(new_value)
                                    setattr(dashou_profile, field, new_value)
                                elif field in ['zhuangtai', 'zaixianzhuangtai', 'zhanghaozhuangtai']:
                                    new_value = int(new_value)
                                    setattr(dashou_profile, field, new_value)
                                else:
                                    setattr(dashou_profile, field, new_value)

                                modified_fields.append(field)

                                # 记录敏感字段修改
                                if field == 'yue':
                                    has_sensitive_change = True
                                    modify_record_data['xiugaitijiao'] = new_value  # 使用xiugaitijiao字段记录打手余额修改
                                    modify_record_data['xiugaitijiaoq'] = old_yue
                                elif field == 'zonge':
                                    has_sensitive_change = True
                                    # zonge字段在修改记录表中可能没有直接对应，可以记录在备注中
                                    modify_record_data['qitashuoming'] += f' 打手总额从{old_zonge}修改为{new_value}'
                                elif field == 'jifen':
                                    has_sensitive_change = True
                                    modify_record_data['jifen'] = new_value
                                    modify_record_data['yjifen'] = old_jifen
                                elif field == 'yajin':
                                    has_sensitive_change = True
                                    modify_record_data['yajin'] = new_value
                                    modify_record_data['yyajin'] = old_yajin

                    # 保存打手信息
                    dashou_profile.save()

                    # 记录被修改的非敏感字段
                    non_sensitive_fields = [f for f in modified_fields if f not in ['yue', 'zonge', 'jifen', 'yajin']]
                    if non_sensitive_fields:
                        modify_record_data['qitashuoming'] += f' 修改了字段: {",".join(non_sensitive_fields)}'

                elif user_type == 3:  # 管事
                    # 获取或创建管事扩展记录
                    guanshi_profile, created = UserGuanshi.objects.get_or_create(
                        user=user_main,
                        defaults={'yaoqingma': f'GS{uid[-4:]}'}
                    )

                    # 记录敏感字段的旧值
                    old_yue = guanshi_profile.yue  # 管事可提现余额

                    update_fields = [
                        'yaogingshuliang', 'chongzhifenrun', 'yue',
                        'zhuangtai', 'dianhua', 'wechat'
                    ]

                    modified_fields = []

                    for field in update_fields:
                        if field in request.data:
                            new_value = request.data.get(field)
                            old_value = getattr(guanshi_profile, field)

                            if str(new_value) != str(old_value):
                                if field in ['chongzhifenrun', 'yue']:
                                    new_value = Decimal(str(new_value))
                                    setattr(guanshi_profile, field, new_value)
                                elif field in ['yaogingshuliang']:
                                    new_value = int(new_value)
                                    setattr(guanshi_profile, field, new_value)
                                elif field in ['zhuangtai']:
                                    new_value = int(new_value)
                                    setattr(guanshi_profile, field, new_value)
                                else:
                                    setattr(guanshi_profile, field, new_value)

                                modified_fields.append(field)

                                # 记录敏感字段修改
                                if field == 'yue':
                                    has_sensitive_change = True
                                    modify_record_data['guanshiyue'] = new_value
                                    modify_record_data['guanshiyueq'] = old_yue
                                elif field == 'chongzhifenrun':
                                    has_sensitive_change = True
                                    modify_record_data['qitashuoming'] += f' 管事分佣从{old_value}修改为{new_value}'

                    guanshi_profile.save()

                    # 记录非敏感字段
                    non_sensitive_fields = [f for f in modified_fields if f not in ['yue', 'chongzhifenrun']]
                    if non_sensitive_fields:
                        modify_record_data['qitashuoming'] += f' 修改了字段: {",".join(non_sensitive_fields)}'

                elif user_type == 4:  # 商家
                    # 获取或创建商家扩展记录
                    shop_profile, created = UserShangjia.objects.get_or_create(
                        user=user_main,
                        defaults={'nicheng': user_main.phone or f'商家{uid}'}
                    )

                    # 记录敏感字段的旧值
                    old_yue = shop_profile.yue  # 商家余额

                    update_fields = ['yue', 'zhuangtai', 'dianhua', 'wechat']

                    modified_fields = []

                    for field in update_fields:
                        if field in request.data:
                            new_value = request.data.get(field)
                            old_value = getattr(shop_profile, field)

                            if str(new_value) != str(old_value):
                                if field == 'yue':
                                    new_value = Decimal(str(new_value))
                                    setattr(shop_profile, field, new_value)
                                elif field == 'zhuangtai':
                                    new_value = int(new_value)
                                    setattr(shop_profile, field, new_value)
                                else:
                                    setattr(shop_profile, field, new_value)

                                modified_fields.append(field)

                                # 记录敏感字段修改
                                if field == 'yue':
                                    has_sensitive_change = True
                                    modify_record_data['shangjiayue'] = new_value
                                    modify_record_data['shangjiayueq'] = old_yue

                    shop_profile.save()

                    # 记录非敏感字段
                    non_sensitive_fields = [f for f in modified_fields if f != 'yue']
                    if non_sensitive_fields:
                        modify_record_data['qitashuoming'] += f' 修改了字段: {",".join(non_sensitive_fields)}'




                # 处理打手会员添加（只有打手可以添加会员）
                '''if user_type == 2 and 'huiyuan_id' in request.data and 'days' in request.data:
                    huiyuan_id = request.data.get('huiyuan_id')
                    days = int(request.data.get('days', 0))

                    if huiyuan_id and days > 0:
                        if days < 1 or days > 10000:
                            return Response({
                                'code': 400,
                                'message': '会员天数必须在1-10000之间',
                                'data': None
                            }, status=status.HTTP_400_BAD_REQUEST)

                        # 检查会员是否存在
                        huiyuan = Huiyuan.objects.filter(huiyuan_id=huiyuan_id).first()
                        if not huiyuan:
                            return Response({
                                'code': 404,
                                'message': '会员不存在',
                                'data': None
                            }, status=status.HTTP_404_NOT_FOUND)

                        # 检查是否已购买该会员
                        existing_record = Huiyuangoumai.objects.filter(
                            yonghu_id=uid,
                            huiyuan_id=huiyuan_id
                        ).first()

                        if existing_record:
                            # 续费：延长到期时间
                            if existing_record.daoqi_time < timezone.now():
                                # 已过期，从当前时间开始算
                                new_daoqi_time = timezone.now() + timedelta(days=days)
                            else:
                                # 未过期，从原到期时间开始算
                                new_daoqi_time = existing_record.daoqi_time + timedelta(days=days)

                            existing_record.daoqi_time = new_daoqi_time
                            existing_record.save()

                            # 记录会员续费
                            has_sensitive_change = True
                            modify_record_data['huiyuants'] = days
                            modify_record_data['huiyuan_id'] = huiyuan_id
                            modify_record_data['qitashuoming'] += f' 续费会员 {huiyuan.jieshao} {days}天'
                        else:
                            # 新购买
                            daoqi_time = timezone.now() + timedelta(days=days)
                            new_record = Huiyuangoumai.objects.create(
                                huiyuan_id=huiyuan_id,
                                yonghu_id=uid,
                                jieshao=huiyuan.jieshao,
                                daoqi_time=daoqi_time
                            )

                            # 记录会员购买
                            has_sensitive_change = True
                            modify_record_data['huiyuants'] = days
                            modify_record_data['huiyuan_id'] = huiyuan_id
                            modify_record_data['qitashuoming'] += f' 购买会员 {huiyuan.jieshao} {days}天'

                        # 更新会员购买次数
                        huiyuan.goumai_cishu += 1
                        huiyuan.save()'''

                # 🔥🔥🔥 后端修改：支持正负数会员天数
                # 修改会员处理逻辑部分

                if user_type == 2 and 'huiyuan_id' in request.data and 'days' in request.data:
                    huiyuan_id = request.data.get('huiyuan_id')
                    days = int(request.data.get('days', 0))

                    # 🔥 修改：允许正负数，但不能为0
                    if huiyuan_id and days != 0:
                        # 🔥 修改：检查绝对值范围
                        if abs(days) < 1 or abs(days) > 10000:
                            return Response({
                                'code': 400,
                                'message': '会员天数必须在1-10000之间（正数增加，负数减少）',
                                'data': None
                            }, status=status.HTTP_400_BAD_REQUEST)

                        # 检查会员是否存在
                        huiyuan = Huiyuan.objects.filter(huiyuan_id=huiyuan_id).first()
                        if not huiyuan:
                            return Response({
                                'code': 404,
                                'message': '会员不存在',
                                'data': None
                            }, status=status.HTTP_404_NOT_FOUND)

                        # 检查是否已购买该会员
                        existing_record = Huiyuangoumai.objects.filter(
                            yonghu_id=uid,
                            huiyuan_id=huiyuan_id
                        ).first()

                        if existing_record:
                            # 🔥🔥🔥 重要修改：支持减少天数
                            # 计算新的到期时间
                            new_daoqi_time = existing_record.daoqi_time + timedelta(days=days)

                            # 🔥 安全验证：减少天数后不能小于当前时间前90天（防止过度减少）
                            # 这个限制可以根据业务调整
                            min_allowed_time = timezone.now() - timedelta(days=90)
                            if new_daoqi_time < min_allowed_time:
                                return Response({
                                    'code': 400,
                                    'message': f'减少天数过多，调整后到期时间不能早于 {(min_allowed_time + timedelta(days=90)).strftime("%Y-%m-%d")}',
                                    'data': None
                                }, status=status.HTTP_400_BAD_REQUEST)

                            existing_record.daoqi_time = new_daoqi_time
                            existing_record.save()

                            # 记录会员操作
                            has_sensitive_change = True
                            modify_record_data['huiyuants'] = days
                            modify_record_data['huiyuan_id'] = huiyuan_id

                            if days > 0:
                                modify_record_data['qitashuoming'] += f' 续费会员 {huiyuan.jieshao} {days}天'
                                # 只有增加天数时才增加购买次数
                                huiyuan.goumai_cishu += 1
                                huiyuan.save()
                            else:
                                modify_record_data[
                                    'qitashuoming'] += f' 减少会员 {huiyuan.jieshao} {abs(days)}天'
                                # 减少天数时不增加购买次数

                        else:
                            # 🔥 修改：新购买时只能增加天数
                            if days > 0:
                                daoqi_time = timezone.now() + timedelta(days=days)
                                new_record = Huiyuangoumai.objects.create(
                                    huiyuan_id=huiyuan_id,
                                    yonghu_id=uid,
                                    jieshao=huiyuan.jieshao,
                                    daoqi_time=daoqi_time
                                )

                                # 记录会员购买
                                has_sensitive_change = True
                                modify_record_data['huiyuants'] = days
                                modify_record_data['huiyuan_id'] = huiyuan_id
                                modify_record_data['qitashuoming'] += f' 购买会员 {huiyuan.jieshao} {days}天'

                                # 更新会员购买次数
                                huiyuan.goumai_cishu += 1
                                huiyuan.save()
                            else:
                                # 🔥 不能为不存在的会员减少天数
                                return Response({
                                    'code': 400,
                                    'message': '用户未购买该会员，无法减少天数',
                                    'data': None
                                }, status=status.HTTP_400_BAD_REQUEST)

                # 如果有敏感字段被修改或会员操作，创建修改记录
                if has_sensitive_change or 'huiyuan_id' in request.data:
                    # 创建修改记录
                    Xiugaijilu.objects.create(**modify_record_data)
                elif modify_record_data.get('qitashuoming', '').strip():
                    # 只有非敏感字段修改，也记录但qitashuoming不同
                    Xiugaijilu.objects.create(**modify_record_data)

                return Response({
                    'code': 0,
                    'message': '修改成功',
                    'data': None
                }, status=status.HTTP_200_OK)

        except Exception as e:
            return Response({
                'code': 500,
                'message': f'修改失败: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


# yonghu/views.py
from django.utils import timezone
from django.db.models import Q
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework import status
from .models import UserMain, AdminProfile, Tixianjilu


# 管理员认证装饰器
def admin_required(view_func):
    """管理员权限验证装饰器"""

    def wrapped_view(self, request, *args, **kwargs):
        try:
            # 1. 验证JWT Token
            if not request.user.is_authenticated:
                return Response({
                    'code': 401,
                    'message': '未认证',
                    'data': None
                }, status=status.HTTP_401_UNAUTHORIZED)

            # 2. 验证用户类型为管理员
            if request.user.user_type != 'admin':
                return Response({
                    'code': 403,
                    'message': '权限不足',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 3. 验证管理员扩展表存在
            admin_profile = getattr(request.user, 'admin_profile', None)
            if not admin_profile:
                return Response({
                    'code': 403,
                    'message': '管理员信息不完整',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 4. 验证管理员账号（phone）与前端传递的zhanghao一致
            zhanghao = request.data.get('zhanghao')
            if not zhanghao or request.user.phone != zhanghao:
                return Response({
                    'code': 401,
                    'message': '账号验证失败',
                    'data': None
                }, status=status.HTTP_401_UNAUTHORIZED)

            return view_func(self, request, *args, **kwargs)
        except Exception as e:
            return Response({
                'code': 500,
                'message': f'权限验证异常: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    return wrapped_view


from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.utils import timezone
from django.db.models import Q
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework import status
from yonghu.models import Tixianjilu


class AddtxshView(APIView):
    """
    获取提现审核列表接口
    与用户管理页面保持一致的分页逻辑
    支持按用户ID搜索，排序改为按申请时间升序（最早申请排最前）
    """
    permission_classes = [IsAuthenticated]

    @admin_required
    def post(self, request):
        try:
            # 获取参数
            zhanghao = request.data.get('zhanghao')
            page = int(request.data.get('page', 1))
            page_size = int(request.data.get('page_size', 5))
            zhuangtai = int(request.data.get('zhuangtai', 1))
            leixing = int(request.data.get('leixing', 1))
            fangshi = request.data.get('fangshi')

            # 🔴【新增】获取搜索参数（用户ID）
            search_uid = request.data.get('search_uid', '').strip()

            if page < 1:
                page = 1

            # 计算偏移量（与用户管理页面完全一致）
            offset = (page - 1) * page_size

            # 构建查询条件
            query = Q()

            # 状态筛选
            if zhuangtai == 1:
                query &= Q(zhuangtai=1)
            elif zhuangtai == 2:
                query &= Q(zhuangtai__in=[2, 3])

            # 类型筛选
            query &= Q(leixing=leixing)

            # 收款方式筛选（可选）
            if fangshi:
                query &= Q(fangshi=int(fangshi))

            # 🔴【新增】如果搜索了用户ID，添加条件
            if search_uid:
                query &= Q(yonghuid=search_uid)

            # 🔴【修改】排序改为按申请时间升序（最早申请排最前）
            queryset = Tixianjilu.objects.filter(query).order_by('create_time')

            # 🔴【修改】分页逻辑：如果是搜索模式，不分页，返回所有匹配记录
            if search_uid:
                records = list(queryset)
                total_count = len(records)
                has_more = False  # 搜索模式没有更多数据
            else:
                total_count = queryset.count()
                records = list(queryset[offset:offset + page_size])
                current_count = len(records)
                has_more = (offset + current_count) < total_count

            # 获取状态统计（统计与搜索无关，依然按筛选条件统计）
            status_counts = {
                'awaiting': Tixianjilu.objects.filter(
                    zhuangtai=1,
                    leixing=leixing
                ).count(),
                'processed': Tixianjilu.objects.filter(
                    zhuangtai__in=[2, 3],
                    leixing=leixing
                ).count()
            }

            # 构建响应数据
            withdrawal_list = []
            for record in records:
                withdrawal_list.append({
                    'id': record.id,
                    'yonghuid': record.yonghuid,
                    'avatar': record.avatar,
                    'phone': record.phone,
                    'nicheng': record.nicheng,
                    'leixing': record.leixing,
                    'zhifu': record.zhifu,
                    'skzhanghao': record.skzhanghao,
                    'jine': str(record.jine) if record.jine else '0.00',
                    'zhuangtai': record.zhuangtai,
                    'fangshi': record.fangshi,
                    'shenheid': record.shenheid,
                    'bhliyou': record.bhliyou,
                    'create_time': record.create_time,
                    'update_time': record.update_time
                })

            return Response({
                'code': 0,
                'message': '获取成功',
                'data': {
                    'list': withdrawal_list,
                    'total_count': total_count,
                    'status_counts': status_counts,
                    'has_more': has_more
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            return Response({
                'code': 500,
                'message': f'获取提现列表失败: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)







'''class AddtxshView(APIView):
    """
    获取提现审核列表接口
    与用户管理页面保持一致的分页逻辑
    """
    permission_classes = [IsAuthenticated]

    @admin_required
    def post(self, request):
        try:
            # 获取参数
            zhanghao = request.data.get('zhanghao')
            page = int(request.data.get('page', 1))
            page_size = int(request.data.get('page_size', 5))
            zhuangtai = int(request.data.get('zhuangtai', 1))
            leixing = int(request.data.get('leixing', 1))
            fangshi = request.data.get('fangshi')

            if page < 1:
                page = 1

            # 计算偏移量（与用户管理页面完全一致）
            offset = (page - 1) * page_size

            # 构建查询条件
            query = Q()

            # 状态筛选
            if zhuangtai == 1:
                query &= Q(zhuangtai=1)
            elif zhuangtai == 2:
                query &= Q(zhuangtai__in=[2, 3])

            # 类型筛选
            query &= Q(leixing=leixing)

            # 收款方式筛选（可选）
            if fangshi:
                query &= Q(fangshi=int(fangshi))

            # 获取查询集（与用户管理页面一致）
            queryset = Tixianjilu.objects.filter(query).order_by('-update_time', '-create_time')

            # 获取总数
            total_count = queryset.count()

            # 分页数据（与用户管理页面完全一致）
            records = list(queryset[offset:offset + page_size])

            # ✅ 计算是否有更多数据（与用户管理页面完全一致）
            current_count = len(records)
            has_more = (offset + current_count) < total_count

            # 获取状态统计
            status_counts = {
                'awaiting': Tixianjilu.objects.filter(
                    zhuangtai=1,
                    leixing=leixing
                ).count(),
                'processed': Tixianjilu.objects.filter(
                    zhuangtai__in=[2, 3],
                    leixing=leixing
                ).count()
            }

            # 构建响应数据
            withdrawal_list = []
            for record in records:
                withdrawal_list.append({
                    'id': record.id,
                    'yonghuid': record.yonghuid,
                    'avatar': record.avatar,
                    'phone': record.phone,
                    'nicheng': record.nicheng,
                    'leixing': record.leixing,
                    'zhifu': record.zhifu,
                    'skzhanghao': record.skzhanghao,
                    'jine': str(record.jine) if record.jine else '0.00',
                    'zhuangtai': record.zhuangtai,
                    'fangshi': record.fangshi,
                    'shenheid': record.shenheid,
                    'bhliyou': record.bhliyou,
                    'create_time': record.create_time,
                    'update_time': record.update_time
                })

            return Response({
                'code': 0,
                'message': '获取成功',
                'data': {
                    'list': withdrawal_list,
                    'total_count': total_count,
                    'status_counts': status_counts,
                    'has_more': has_more
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            return Response({
                'code': 500,
                'message': f'获取提现列表失败: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)'''


from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from django.db import transaction
from django.utils import timezone
from peizhi.models import Szjilu  # 添加收支记录表导入


# 假设你的提现记录模型导入
# from your_app.models import Tixianjilu

class AdtixianqkView(APIView):
    """
    处理提现申请接口（已更新：添加收支记录表更新）
    """
    permission_classes = [IsAuthenticated]

    @admin_required  # 假设你有这个装饰器
    def post(self, request):
        try:
            zhanghao = request.data.get('zhanghao')
            tixian_id = request.data.get('tixian_id')
            result = int(request.data.get('result', 0))
            reason = request.data.get('reason', '')

            if not tixian_id:
                return Response({
                    'code': 400,
                    'message': '提现记录ID不能为空',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            if result not in [2, 3]:
                return Response({
                    'code': 400,
                    'message': '操作结果无效',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 如果是拒绝，需要理由
            if result == 3 and not reason:
                return Response({
                    'code': 400,
                    'message': '拒绝提现需要提供理由',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 获取提现记录
            try:
                withdrawal = Tixianjilu.objects.get(id=tixian_id)
            except Tixianjilu.DoesNotExist:
                return Response({
                    'code': 404,
                    'message': '提现记录不存在',
                    'data': None
                }, status=status.HTTP_404_NOT_FOUND)

            # 检查状态，只有待审核的可以处理
            if withdrawal.zhuangtai != 1:
                return Response({
                    'code': 400,
                    'message': '该提现申请已被处理',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # ---------- 自动提现审核新流程（有关联 shenhe_jilu_id） ----------
            if withdrawal.shenhe_jilu_id:
                from .models import TixianShenheJilu
                from .tixian_shenhe_services import refund_balance, sync_audit_and_jilu_status
                with transaction.atomic():
                    try:
                        audit = TixianShenheJilu.objects.select_for_update().get(
                            id=withdrawal.shenhe_jilu_id
                        )
                    except TixianShenheJilu.DoesNotExist:
                        return Response({'code': 404, 'message': '审核记录不存在', 'data': None},
                                        status=status.HTTP_404_NOT_FOUND)
                    if audit.zhuangtai != 1:
                        return Response({'code': 400, 'message': '该审核申请已被处理', 'data': None},
                                        status=status.HTTP_400_BAD_REQUEST)
                    user_main = UserMain.objects.get(yonghuid=withdrawal.yonghuid)
                    if result == 2:
                        # 审核通过 → 待收款(6)，等用户在前端点击「收款」
                        sync_audit_and_jilu_status(
                            audit, 6,
                            shenhe_ren_id=request.user.yonghuid,
                        )
                        withdrawal.shenheid = request.user.yonghuid
                        withdrawal.save(update_fields=['shenheid', 'update_time'])
                    elif result == 3:
                        sync_audit_and_jilu_status(
                            audit, 5,
                            bhliyou=reason,
                            bo_hui_ren_id=request.user.yonghuid,
                        )
                        refund_balance(user_main, audit.leixing, audit.shijidaozhang)
                        withdrawal.shenheid = request.user.yonghuid
                        withdrawal.bhliyou = reason
                        withdrawal.save(update_fields=['shenheid', 'bhliyou', 'update_time'])
                return Response({
                    'code': 0,
                    'message': '处理成功',
                    'data': {
                        'id': withdrawal.id,
                        'zhuangtai': 6 if result == 2 else 5,
                        'shenhe_danhao': audit.shenhe_danhao,
                    },
                }, status=status.HTTP_200_OK)

            # 使用事务确保数据一致性（手动提现旧流程）
            with transaction.atomic():
                # 更新提现记录
                withdrawal.zhuangtai = result
                withdrawal.shenheid = request.user.yonghuid

                if result == 3:  # 拒绝
                    from .tixian_shenhe_services import refund_balance
                    user_main = UserMain.objects.get(yonghuid=withdrawal.yonghuid)
                    # 手动提现记录 jine=到账金额(已扣手续费)，按类型退回对应账户
                    refund_balance(user_main, withdrawal.leixing, withdrawal.jine)
                    withdrawal.bhliyou = reason

                withdrawal.update_time = timezone.now()
                withdrawal.save()

                # 🟢 新增：如果同意提现（result=2），更新收支记录表
                if result == 2:
                    try:
                        # 查询收支记录表，id=1的记录
                        szjilu_record = Szjilu.objects.get(id=1)

                        # 获取提现金额
                        tixian_jine = withdrawal.jine  # 假设提现记录模型中有jine字段

                        from dingdan.utils import update_daily_payout
                        update_daily_payout(tixian_jine)

                        # 更新收支记录
                        szjilu_record.zongsy -= tixian_jine  # 总收益减去提现金额
                        szjilu_record.zongzc += tixian_jine  # 总支出加上提现金额
                        szjilu_record.jrzc += tixian_jine  # 今日支出加上提现金额
                        szjilu_record.update_time = timezone.now()
                        szjilu_record.save()

                    except Szjilu.DoesNotExist:
                        # 如果收支记录表不存在id=1的记录，创建一个
                        szjilu_record = Szjilu.objects.create(
                            id=1,
                            zongsy=-tixian_jine if result == 2 else 0,
                            zongzc=tixian_jine if result == 2 else 0,
                            jrzc=tixian_jine if result == 2 else 0
                        )
                    except Exception as e:
                        # 如果更新收支记录失败，抛出异常，事务会回滚
                        raise Exception(f"更新收支记录失败: {str(e)}")

            return Response({
                'code': 0,
                'message': '处理成功',
                'data': {
                    'id': withdrawal.id,
                    'zhuangtai': withdrawal.zhuangtai,
                    'shenheid': withdrawal.shenheid,
                    'update_time': withdrawal.update_time
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            return Response({
                'code': 500,
                'message': f'处理提现失败: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

'''class AdtixianqkView(APIView):
    """
    处理提现申请接口（保持不变）
    """
    permission_classes = [IsAuthenticated]

    @admin_required
    def post(self, request):
        try:
            zhanghao = request.data.get('zhanghao')
            tixian_id = request.data.get('tixian_id')
            result = int(request.data.get('result', 0))
            reason = request.data.get('reason', '')

            if not tixian_id:
                return Response({
                    'code': 400,
                    'message': '提现记录ID不能为空',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            if result not in [2, 3]:
                return Response({
                    'code': 400,
                    'message': '操作结果无效',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 如果是拒绝，需要理由
            if result == 3 and not reason:
                return Response({
                    'code': 400,
                    'message': '拒绝提现需要提供理由',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 获取提现记录
            try:
                withdrawal = Tixianjilu.objects.get(id=tixian_id)
            except Tixianjilu.DoesNotExist:
                return Response({
                    'code': 404,
                    'message': '提现记录不存在',
                    'data': None
                }, status=status.HTTP_404_NOT_FOUND)

            # 检查状态，只有待审核的可以处理
            if withdrawal.zhuangtai != 1:
                return Response({
                    'code': 400,
                    'message': '该提现申请已被处理',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 更新提现记录
            withdrawal.zhuangtai = result
            withdrawal.shenheid = request.user.yonghuid

            if result == 3:  # 拒绝
                withdrawal.bhliyou = reason

            withdrawal.update_time = timezone.now()
            withdrawal.save()

            return Response({
                'code': 0,
                'message': '处理成功',
                'data': {
                    'id': withdrawal.id,
                    'zhuangtai': withdrawal.zhuangtai,
                    'shenheid': withdrawal.shenheid,
                    'update_time': withdrawal.update_time
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            return Response({
                'code': 500,
                'message': f'处理提现失败: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)'''

# views.py (yonghu应用)
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
from .models import UserMain, UserDashou
import logging

logger = logging.getLogger(__name__)


class DashouZiliaoHuoquView(APIView):
    """
    打手资料获取接口
    URL: /yonghu/dszjxxhq
    方法: POST
    认证: JWT Token
    返回: 打手扩展表信息
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 使用select_related高效查询，避免N+1问题
            dashou = UserDashou.objects.select_related('user').get(user=request.user)

            # 构建返回数据
            data = {
                'nicheng': dashou.nicheng if dashou.nicheng else '',
                'jieshao': dashou.jieshao if dashou.jieshao else '',
                'dianhua': dashou.dianhua if dashou.dianhua else '',
                'wechat': dashou.wechat if dashou.wechat else '',
                'uid': request.user.yonghuid,  # 从主表获取UID
                'avatar': request.user.avatar if request.user.avatar else '',  # 头像相对URL
            }

            return Response({
                'code': 200,
                'msg': 'success',
                'data': data
            }, status=status.HTTP_200_OK)

        except UserDashou.DoesNotExist:
            logger.warning(f'打手扩展表不存在: user_id={request.user.id}')
            return Response({
                'code': 404,
                'msg': '打手信息不存在'
            }, status=status.HTTP_404_NOT_FOUND)

        except Exception as e:
            logger.error(f'获取打手资料异常: {str(e)}', exc_info=True)
            return Response({
                'code': 500,
                'msg': '服务器内部错误'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


# views.py (yonghu应用)
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
from .models import UserDashou
import re
import logging

logger = logging.getLogger(__name__)


class DashouGengxinView(APIView):
    """
    打手信息更新接口
    URL: /yonghu/dsgxxx
    方法: POST
    认证: JWT Token
    参数: nicheng(昵称), dianhua(电话), wechat(微信), jieshao(介绍)
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 获取请求数据
            nicheng = request.data.get('nicheng', '').strip()
            dianhua = request.data.get('dianhua', '').strip()
            wechat = request.data.get('wechat', '').strip()
            jieshao = request.data.get('jieshao', '').strip()

            # 数据验证
            validation_errors = self.validate_data(nicheng, dianhua, wechat, jieshao)
            if validation_errors:
                return Response({
                    'code': 400,
                    'msg': validation_errors
                }, status=status.HTTP_400_BAD_REQUEST)

            # 获取打手扩展表
            try:
                dashou = UserDashou.objects.get(user=request.user)
            except UserDashou.DoesNotExist:
                return Response({
                    'code': 404,
                    'msg': '打手信息不存在'
                }, status=status.HTTP_404_NOT_FOUND)

            # 更新数据
            update_fields = []

            if nicheng is not None:
                dashou.nicheng = nicheng if nicheng != '' else None
                update_fields.append('nicheng')

            if dianhua is not None:
                dashou.dianhua = dianhua if dianhua != '' else None
                update_fields.append('dianhua')

            if wechat is not None:
                dashou.wechat = wechat if wechat != '' else None
                update_fields.append('wechat')

            if jieshao is not None:
                dashou.jieshao = jieshao if jieshao != '' else None
                update_fields.append('jieshao')

            # 保存更新（只更新修改的字段）
            if update_fields:
                dashou.save(update_fields=update_fields)

            return Response({
                'code': 200,
                'msg': '更新成功',
                'data': {
                    'nicheng': dashou.nicheng or '',
                    'dianhua': dashou.dianhua or '',
                    'wechat': dashou.wechat or '',
                    'jieshao': dashou.jieshao or ''
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f'更新打手信息异常: {str(e)}', exc_info=True)
            return Response({
                'code': 500,
                'msg': '服务器内部错误'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def validate_data(self, nicheng, dianhua, wechat, jieshao):
        """数据验证方法"""
        errors = []

        # 1. 昵称验证（必填）
        if not nicheng:
            errors.append('昵称不能为空')
        elif len(nicheng) > 20:
            errors.append('昵称不能超过20个字符')

        # 2. 手机号验证（非必填，但填写时必须正确）
        if dianhua:
            # 手机号正则：1开头，11位数字
            phone_pattern = r'^1[3-9]\d{9}$'
            if not re.match(phone_pattern, dianhua):
                errors.append('手机号格式不正确')

        # 3. 微信号验证（非必填）
        if wechat and len(wechat) > 30:
            errors.append('微信号不能超过30个字符')

        # 4. 个人介绍验证
        if jieshao and len(jieshao) > 200:
            errors.append('个人介绍不能超过200个字符')

        return '; '.join(errors) if errors else None


class ShangjiaZhuceView(APIView):
    """
    商家注册接口 (通过管理员邀请码)
    访问路径: /api/yonghu/shangjiahuce/
    请求方法: POST
    权限要求: JWT Token认证通过的用户
    请求体: { "inviteCode": "管理员邀请码" }

    返回字段说明：
    - code: 状态码（200成功，其他失败）
    - message: 提示信息
    - data: 商家信息数据，包含以下字段（与前端商家页面完全一致）：
        - nicheng: 商家昵称
        - sjyue: 商家余额（字符串，保留两位小数）
        - fabu: 发布订单总数
        - chengjiao: 成交订单总数
        - tuikuan: 退款订单总数
        - jinridingdan: 今日订单
        - jinriliushui: 今日流水（字符串）
        - jinyuedingdan: 今月订单
        - jinyueliushui: 今月流水（字符串）
        - zhuangtai: 商家状态（1正常）
        - dianhua: 商家电话
        - wechat: 商家微信
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 1. 获取并验证邀请码参数
        yaoqingma = request.data.get('inviteCode')
        if not yaoqingma:
            return Response({
                'code': 400,
                'message': '邀请码不能为空',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        yaoqingma = yaoqingma.strip()
        if len(yaoqingma) > 100:
            return Response({
                'code': 400,
                'message': '邀请码长度超过限制',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        current_user = request.user

        # 2. 检查用户是否已是商家
        try:
            shangjia_profile = current_user.shop_profile
            # 用户已是商家，直接返回现有信息
            return self.fanhuiXianyouShangjiaXinxi(shangjia_profile, current_user)
        except UserShangjia.DoesNotExist:
            # 用户不是商家，继续注册流程
            pass

        # 3. 根据邀请码查找对应的管理员
        try:
            # 从管理员表查找邀请码
            admin_profile = AdminProfile.objects.select_related('user').get(yaoqingma=yaoqingma)
        except AdminProfile.DoesNotExist:
            return Response({
                'code': 404,
                'message': '管理员邀请码无效或不存在',
                'data': None
            }, status=status.HTTP_404_NOT_FOUND)

        # 4. 核心：在数据库事务中创建商家身份
        try:
            with transaction.atomic():
                # 4.1 查询老板扩展表获取老板昵称
                boss_nickname = '普通商家'
                try:
                    boss_profile = current_user.boss_profile
                    if boss_profile.nickname and boss_profile.nickname.strip():
                        boss_nickname = boss_profile.nickname.strip()
                except UserBoss.DoesNotExist:
                    # 老板扩展表不存在，使用默认值
                    pass

                # 4.2 创建商家扩展表
                # 使用老板昵称作为商家昵称的基础
                shangjia_nicheng = boss_nickname

                # 检查昵称是否已存在（安全考虑）
                if UserShangjia.objects.filter(nicheng=shangjia_nicheng).exists():
                    # 如果存在，添加随机数确保唯一
                    import random
                    shangjia_nicheng = f"{boss_nickname}{random.randint(1000, 9999)}"

                # 4.3 创建商家记录
                shop_profile = UserShangjia.objects.create(
                    user=current_user,
                    nicheng=shangjia_nicheng,
                    zhuangtai=1,  # 正常状态
                    yue=0.00,  # 商家余额
                    fabu=0,  # 发布订单总数
                    tuikuan=0,  # 退款订单总数
                    chengjiao=0,  # 成交订单总数
                    jinridingdan=0,  # 今日订单
                    jinriliushui=0.00,  # 今日流水
                    jinyuedingdan=0,  # 今月订单
                    jinyueliushui=0.00,  # 今月流水
                    dianhua='',  # 电话
                    wechat='',  # 微信
                )

        except Exception as e:
            # 事务会自动回滚
            import traceback
            error_detail = traceback.format_exc()
            #print(f"商家注册错误详情: {error_detail}")

            return Response({
                'code': 500,
                'message': f'商家注册过程中发生系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # 5. 注册成功，返回商家信息
        fanhui_data = self.zhuangbeiFanhuiShuju(shop_profile, current_user)
        return Response({
            'code': 200,
            'message': '商家注册成功！',
            'data': fanhui_data
        })

    def fanhuiXianyouShangjiaXinxi(self, shangjia_profile, current_user):
        """处理已是商家的用户，返回其现有信息"""
        fanhui_data = self.zhuangbeiFanhuiShuju(shangjia_profile, current_user)
        return Response({
            'code': 200,
            'message': '您已是商家，返回当前信息。',
            'data': fanhui_data
        })

    def zhuangbeiFanhuiShuju(self, shangjia_profile, current_user):
        """
        准备返回给前端的商家数据
        字段名必须与前端商家页面完全一致
        """
        data = {
            # 🟢 商家基本信息
            'nicheng': shangjia_profile.nicheng,  # 商家昵称
            'sjyue': format(shangjia_profile.yue, '.2f'),  # 商家余额，保留两位小数
            'fabu': shangjia_profile.fabu,  # 发布订单总数
            'chengjiao': shangjia_profile.chengjiao,  # 成交订单总数
            'tuikuan': shangjia_profile.tuikuan,  # 退款订单总数
            'jinridingdan': shangjia_profile.jinridingdan,  # 今日订单
            'jinriliushui': format(shangjia_profile.jinriliushui, '.2f'),  # 今日流水
            'jinyuedingdan': shangjia_profile.jinyuedingdan,  # 今月订单
            'jinyueliushui': format(shangjia_profile.jinyueliushui, '.2f'),  # 今月流水
            'zhuangtai': shangjia_profile.zhuangtai,  # 商家状态
            'dianhua': shangjia_profile.dianhua or '',  # 电话
            'wechat': shangjia_profile.wechat or '',  # 微信

            # 🟢 可能需要的主表信息
            'uid': current_user.yonghuid,  # 用户ID
        }
        return data





class WechatLoginAndDashouRegisterView(APIView):
    """
    微信登录并注册打手一体化接口
    访问路径: /api/yonghu/wdlyhdl
    请求方法: POST
    权限要求: 无需登录
    请求体: { "code": "微信登录code", "inviteCode": "邀请码" }

    功能: 用户扫码进入但未登录时，一次性完成微信登录和打手注册
    """

    throttle_classes = [AnonRateThrottle]
    permission_classes = [AllowAny]

    def post(self, request):
        """
        处理微信登录并注册打手请求
        """
        try:
            # 1. 获取并验证参数
            code = request.data.get('code', '').strip()
            yaoqingma = request.data.get('inviteCode', '').strip()

            if not code:
                return Response({
                    'code': 1,
                    'msg': '微信授权码不能为空',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            if not yaoqingma:
                return Response({
                    'code': 2,
                    'msg': '邀请码不能为空',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            if len(yaoqingma) > 100:
                return Response({
                    'code': 3,
                    'msg': '邀请码长度超过限制',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 2. 获取微信openid
            wechat_data = self.get_wechat_openid(code)
            if not wechat_data or 'openid' not in wechat_data:
                error_msg = wechat_data.get('errmsg', '微信授权失败')
                return Response({
                    'code': 4,
                    'msg': f'微信登录失败: {error_msg}',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            openid = wechat_data['openid']

            # 3. 获取客户端真实IP
            kehuduan_ip = self.huoquKehuduanIP(request)

            # 4. 开始数据库事务（确保登录和注册的原子性）
            with transaction.atomic():
                # 4.1 创建或获取用户（登录逻辑）
                user_main, created = UserMain.objects.select_for_update().get_or_create(
                    openid=openid,
                    defaults={
                        'yonghuid': self.shengchengYonghuID(),
                        'user_type': 'normal',
                    }
                )

                # 更新用户IP和最后登录时间
                cunchu_ip = kehuduan_ip
                user_main.ip = cunchu_ip
                user_main.last_login_time = timezone.now()
                user_main.save()

                if created:
                    # 新用户：创建老板扩展表
                    UserBoss.objects.create(user=user_main, nickname='微信用户')

                # 4.2 验证邀请码对应的管事（注册逻辑）
                try:
                    # 使用select_related获取管事及其关联的主表用户信息
                    guanshi_profile = UserGuanshi.objects.select_related('user').get(yaoqingma=yaoqingma)
                except UserGuanshi.DoesNotExist:
                    # 邀请码无效，但用户已登录，可以返回登录成功但注册失败
                    # 这里我们继续执行，但只返回登录信息
                    return self.fanhuiZhihouDengluXinxi(user_main, yaoqingma_wuxiao=True)

                # 验证管事状态
                if guanshi_profile.zhuangtai != 1:
                    # 管事账号已被禁用
                    return self.fanhuiZhihouDengluXinxi(user_main, guanshi_jinyong=True)

                # 4.3 检查用户是否已是打手
                dashou_exists = UserDashou.objects.filter(user=user_main).exists()
                if dashou_exists:
                    # 用户已是打手，直接返回信息
                    dashou_profile = UserDashou.objects.get(user=user_main)
                    return self.fanhuiDengluZhuceshuju(user_main, dashou_profile)

                # 4.4 核心：为用户创建所有身份（打手、商家、管事）
                guanshi_yonghuid = guanshi_profile.user.yonghuid

                # 创建打手扩展表
                dashou_profile = UserDashou.objects.create(
                    user=user_main,
                    nicheng='大手子',
                    chenghao='普通大手',
                    yaoqingren=guanshi_yonghuid,
                    # 其他字段使用模型默认值
                )

                # 创建商家扩展表
                # 商家昵称需要唯一，这里用 用户ID + "的店铺" 来确保唯一性
                '''shangjia_nicheng = f"{user_main.yonghuid}的店铺"
                UserShangjia.objects.create(
                    user=user_main,
                    nicheng=shangjia_nicheng,
                    # 其他字段使用默认值
                )'''

                # 创建管事扩展表
                '''guanshi_yaoqingma = chuangjianYaoqingma(str(user_main.yonghuid))
                new_guanshi_profile = UserGuanshi.objects.create(
                    user=user_main,
                    yaoqingma=guanshi_yaoqingma,
                    # 其他字段使用默认值
                )'''

                # 更新原管事的邀请数量
                locked_guanshi = UserGuanshi.objects.select_for_update().get(pk=guanshi_profile.pk)
                locked_guanshi.yaogingshuliang += 1
                locked_guanshi.save()

                # ========== 新增：管事每日统计（邀请打手） ==========

                try:
                    import logging

                    logger = logging.getLogger(__name__)
                    from houtai.utils import update_guanshi_daily_by_action
                    update_guanshi_daily_by_action(
                        yonghuid=guanshi_yonghuid,
                        action=1,  # 1 = 邀请打手
                        amount=Decimal('0.00')
                    )
                    logger.info(f"管事每日统计更新成功（邀请打手）：管事{guanshi_yonghuid}")
                except Exception as e:
                    logger.error(f"管事每日统计更新失败（邀请打手）：{str(e)}")

                # 5. 生成JWT token
                refresh = RefreshToken.for_user(user_main)
                token = str(refresh.access_token)

                # 6. 准备返回数据
                response_data = self.zhuangbeiFanhuiShuju(user_main, dashou_profile, token)

                return Response({
                    'code': 0,
                    'msg': '登录并注册成功！已开通打手、管事等身份。',
                    'data': response_data
                })

        except Exception as e:
            # 记录错误日志
            import logging
            logger = logging.getLogger(__name__)
            error_openid = locals().get('openid', 'N/A')
            logger.error(
                f"微信登录注册一体化接口异常 - openid: {error_openid}, "
                f"错误类型: {type(e).__name__}, 错误详情: {str(e)}",
                exc_info=True
            )

            # 返回友好错误信息
            return Response({
                'code': 99,
                'msg': '系统繁忙，请稍后重试',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def get_wechat_openid(self, code):
        """
        调用微信接口获取openid
        """
        try:
            appid = getattr(settings, 'WEIXIN_APPID', '')
            secret = getattr(settings, 'WEIXIN_SECRET', '')

            if not appid or not secret:
                raise ValueError('微信配置未设置')

            url = 'https://api.weixin.qq.com/sns/jscode2session'
            params = {
                'appid': appid,
                'secret': secret,
                'js_code': code,
                'grant_type': 'authorization_code'
            }

            response = requests.get(url, params=params, timeout=10)
            result = response.json()

            if 'openid' in result:
                return result
            else:
                errcode = result.get('errcode', 'unknown')
                errmsg = result.get('errmsg', '未知错误')
                return {'errmsg': f'[{errcode}]{errmsg}'}

        except requests.exceptions.Timeout:
            return {'errmsg': '请求微信接口超时'}
        except Exception as e:
            return {'errmsg': f'请求微信接口异常: {str(e)}'}

    def shengchengYonghuID(self):
        """
        生成7位数字用户ID
        """
        for _ in range(10):
            timestamp_part = str(int(time.time()))[-5:].zfill(5)
            random_part = str(random.randint(0, 99)).zfill(2)
            user_id = timestamp_part + random_part

            if len(user_id) == 7 and user_id.isdigit():
                if not UserMain.objects.filter(yonghuid=user_id).exists():
                    return user_id

        raise Exception('生成用户ID失败')

    def huoquKehuduanIP(self, request):
        """
        获取客户端真实IP地址
        """
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0].strip()
            if ip:
                return ip

        ip = request.META.get('REMOTE_ADDR', '')
        return ip if ip else '0.0.0.0'

    def huoquQunPeizhi(self):
        """
        获取群配置信息
        """
        try:
            qun_configs = Qunpeizhi.objects.filter(id__in=[1, 2])

            result = {
                'dashouqun': '',
                'dashouqunid': '',
                'guanshiqun': '',
                'guanshiqunid': ''
            }

            for config in qun_configs:
                if config.id == 1:
                    result['dashouqun'] = config.neirong or ''
                    result['dashouqunid'] = config.qunid or ''
                elif config.id == 2:
                    result['guanshiqun'] = config.neirong or ''
                    result['guanshiqunid'] = config.qunid or ''

            return result

        except Exception:
            return {
                'dashouqun': '',
                'dashouqunid': '',
                'guanshiqun': '',
                'guanshiqunid': ''
            }

    def fanhuiZhihouDengluXinxi(self, user_main, yaoqingma_wuxiao=False, guanshi_jinyong=False):
        """
        返回只登录成功的信息（当邀请码无效或管事禁用时）
        """
        # 获取老板昵称
        boss_nickname = '微信用户'
        try:
            boss_profile = UserBoss.objects.get(user=user_main)
            if boss_profile.nickname:
                boss_nickname = boss_profile.nickname
        except UserBoss.DoesNotExist:
            pass

        # 检查各身份状态
        dashou_status = 1 if UserDashou.objects.filter(user=user_main).exists() else 0
        shangjia_status = 1 if UserShangjia.objects.filter(user=user_main).exists() else 0
        guanshi_status = 1 if UserGuanshi.objects.filter(user=user_main).exists() else 0

        # 生成token
        refresh = RefreshToken.for_user(user_main)
        token = str(refresh.access_token)

        # 获取群配置
        group_info = self.huoquQunPeizhi()

        # 构建返回数据
        response_data = {
            'token': token,
            'nicheng': boss_nickname,
            'uid': user_main.yonghuid,
            'touxiang': user_main.avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            # 🟢 注意：这里没有返回dingdantiaoshu（订单数量），与前端需求一致
            'dashouqun': group_info.get('dashouqun', ''),
            'dashouqunid': group_info.get('dashouqunid', ''),
            'guanshiqun': group_info.get('guanshiqun', ''),
            'guanshiqunid': group_info.get('guanshiqunid', '')
        }

        # 根据情况设置返回消息
        if yaoqingma_wuxiao:
            msg = '登录成功，但邀请码无效'
        elif guanshi_jinyong:
            msg = '登录成功，但邀请码对应的管事账号已被禁用'
        else:
            msg = '登录成功'

        return Response({
            'code': 0,
            'msg': msg,
            'data': response_data
        })

    def fanhuiDengluZhuceshuju(self, user_main, dashou_profile):
        """
        返回登录并注册的数据（用户已是打手的情况）
        """
        # 获取老板昵称
        boss_nickname = '微信用户'
        try:
            boss_profile = UserBoss.objects.get(user=user_main)
            if boss_profile.nickname:
                boss_nickname = boss_profile.nickname
        except UserBoss.DoesNotExist:
            pass

        # 检查各身份状态（这里用户已是打手，所以都是1）
        dashou_status = 1
        shangjia_status = 1 if UserShangjia.objects.filter(user=user_main).exists() else 1  # 确保是1
        guanshi_status = 1 if UserGuanshi.objects.filter(user=user_main).exists() else 1  # 确保是1

        # 生成token
        refresh = RefreshToken.for_user(user_main)
        token = str(refresh.access_token)

        # 获取群配置
        group_info = self.huoquQunPeizhi()

        # 准备打手信息
        dashou_data = self.zhuangbeiDashouFanhuiShuju(dashou_profile)

        # 合并所有数据
        response_data = {
            'token': token,
            'nicheng': boss_nickname,
            'uid': user_main.yonghuid,
            'touxiang': user_main.avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            'dashouqun': group_info.get('dashouqun', ''),
            'dashouqunid': group_info.get('dashouqunid', ''),
            'guanshiqun': group_info.get('guanshiqun', ''),
            'guanshiqunid': group_info.get('guanshiqunid', ''),
            # 合并打手信息
            **dashou_data
        }

        return Response({
            'code': 0,
            'msg': '您已是打手，登录成功',
            'data': response_data
        })

    def zhuangbeiFanhuiShuju(self, user_main, dashou_profile, token):
        """
        准备完整的返回数据（登录+注册成功的情况）
        """
        # 获取老板昵称
        boss_nickname = '微信用户'
        try:
            boss_profile = UserBoss.objects.get(user=user_main)
            if boss_profile.nickname:
                boss_nickname = boss_profile.nickname
        except UserBoss.DoesNotExist:
            pass

        # 身份状态（刚注册成功，应该都是1）
        dashou_status = 1
        shangjia_status = 1
        guanshi_status = 1

        # 获取群配置
        group_info = self.huoquQunPeizhi()

        # 准备打手信息
        dashou_data = self.zhuangbeiDashouFanhuiShuju(dashou_profile)

        # 合并所有数据
        response_data = {
            'token': token,
            'nicheng': boss_nickname,
            'uid': user_main.yonghuid,
            'touxiang': user_main.avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            'dashouqun': group_info.get('dashouqun', ''),
            'dashouqunid': group_info.get('dashouqunid', ''),
            'guanshiqun': group_info.get('guanshiqun', ''),
            'guanshiqunid': group_info.get('guanshiqunid', ''),
            # 合并打手信息
            **dashou_data
        }

        return response_data

    def zhuangbeiDashouFanhuiShuju(self, dashou_profile):
        """
        准备打手返回数据（字段名严格匹配前端）
        """
        # 构建基础信息
        data = {
            'dashounicheng': dashou_profile.nicheng,
            'zhanghaostatus': dashou_profile.zhanghaozhuangtai,
            'yongjin': str(dashou_profile.yue),  # Decimal转字符串
            'zonge': str(dashou_profile.zonge),
            'yajin': str(dashou_profile.yajin),
            'chenghao': dashou_profile.chenghao,
            'jinfen': dashou_profile.jifen,
            'chengjiaoliang': dashou_profile.chengjiaozongliang,
            'zaixianzhuangtai': dashou_profile.zaixianzhuangtai,
            'dashouzhuangtai': dashou_profile.zhuangtai,
        }

        # 查询并处理会员列表 (clumber)
        # 使用当前用户的yonghuid进行查询
        huiyuan_goumai_list = []
        goumai_records = Huiyuangoumai.objects.filter(yonghu_id=dashou_profile.user.yonghuid)
        for record in goumai_records:
            # 调用方法检查是否到期，此方法内部会更新状态
            shifou_daoqi = record.jiance_shifou_daoqi()
            huiyuan_goumai_list.append({
                'huiyuan_id': record.huiyuan_id,
                'huiyuan_zhuangtai': record.huiyuan_zhuangtai,
                'daoqi_time': record.daoqi_time.isoformat() if record.daoqi_time else None,
                'shifou_daoqi': shifou_daoqi,
                'jieshao': record.jieshao
            })

        data['clumber'] = huiyuan_goumai_list
        return data

from datetime import datetime  # 🔴【关键修改】
class YonghuTixianShenheXiugaiView(APIView):
    """
    用户修改审核中提现申请接口
    访问路径: /api/yonghu/yonghutxshxg
    请求方法: POST
    权限要求: JWT Token认证通过的用户
    请求体: multipart/form-data 格式
    支持字段: tixian_id, fangshi, txdianhua, txzh, file (图片文件)

    功能: 允许用户修改审核中提现申请的收款方式、电话、账号、收款码等
    """

    permission_classes = [IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser, JSONParser)

    def post(self, request):
        """
        处理用户修改审核中提现申请的POST请求
        """
        try:
            # 1. 获取当前用户
            user_main = request.user
            current_yonghuid = user_main.yonghuid

            # 2. 验证必填字段：提现记录ID
            tixian_id = request.data.get('tixian_id')
            if not tixian_id:
                return Response({
                    'code': 1,
                    'msg': '提现记录ID不能为空',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 查询提现记录（使用select_for_update确保事务安全）
            with transaction.atomic():
                try:
                    tixian_record = Tixianjilu.objects.select_for_update().get(
                        id=tixian_id,
                        yonghuid=current_yonghuid  # 确保只能修改自己的记录
                    )
                except Tixianjilu.DoesNotExist:
                    return Response({
                        'code': 2,
                        'msg': '提现记录不存在或无权修改',
                        'data': None
                    }, status=status.HTTP_404_NOT_FOUND)

                # 4. 验证提现记录状态（必须是审核中）
                if tixian_record.zhuangtai != 1:
                    return Response({
                        'code': 3,
                        'msg': '只有审核中的提现申请可以修改',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                # 5. 获取并验证提现方式
                fangshi = request.data.get('fangshi')
                if fangshi:
                    fangshi = int(fangshi)
                    if fangshi not in [1, 2]:
                        return Response({
                            'code': 4,
                            'msg': '提现方式无效，请选择1(微信)或2(支付宝)',
                            'data': None
                        }, status=status.HTTP_400_BAD_REQUEST)

                    # 检查提现类型与方式的匹配（如果前端提供了leixing）
                    leixing = request.data.get('leixing')
                    if leixing:
                        leixing = int(leixing)
                        # 这里可以根据业务逻辑添加类型与方式的验证
                        # 例如：某些类型只能使用某些方式

                # 6. 验证手机号（必填）
                txdianhua = request.data.get('txdianhua', '').strip()
                if not txdianhua:
                    return Response({
                        'code': 5,
                        'msg': '收款人电话不能为空',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                # 验证手机号格式
                if not txdianhua.isdigit() or len(txdianhua) != 11:
                    return Response({
                        'code': 6,
                        'msg': '请输入11位有效的手机号码',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                # 7. 获取收款账号（可选）
                txzh = request.data.get('txzh', '').strip()

                # 8. 处理收款码图片上传（如果有）
                txtupian_file = request.FILES.get('file')
                new_zhifu_url = None
                old_zhifu_url = tixian_record.zhifu

                if txtupian_file:
                    # 验证图片
                    is_valid, error_msg = validate_image(txtupian_file)
                    if not is_valid:
                        return Response({
                            'code': 7,
                            'msg': f'图片验证失败: {error_msg}',
                            'data': None
                        }, status=status.HTTP_400_BAD_REQUEST)

                    # 上传收款码图片
                    new_zhifu_url = self.handle_shoukuanma_upload(
                        user_main,
                        txtupian_file,
                        old_zhifu_url,
                        tixian_record.leixing
                    )

                    if not new_zhifu_url:
                        return Response({
                            'code': 8,
                            'msg': '收款码上传失败',
                            'data': None
                        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

                # 9. 验证收款信息（账号和图片至少有一个）
                if not txzh and not (new_zhifu_url or old_zhifu_url):
                    return Response({
                        'code': 9,
                        'msg': '请填写收款账号或上传收款码',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                # 10. 更新提现记录
                update_fields = []

                # 更新提现方式（如果有）
                if fangshi:
                    tixian_record.fangshi = fangshi
                    update_fields.append('fangshi')

                # 更新手机号（必填）
                tixian_record.phone = txdianhua
                update_fields.append('phone')

                # 更新收款账号（如果有）
                if txzh is not None:  # 注意：空字符串也要更新
                    tixian_record.skzhanghao = txzh
                    update_fields.append('skzhanghao')

                # 更新收款码图片（如果有新图片）
                if new_zhifu_url:
                    tixian_record.zhifu = new_zhifu_url
                    update_fields.append('zhifu')

                # 保存更新
                if update_fields:
                    tixian_record.save(update_fields=update_fields)

                # 11. 构建返回数据
                response_data = {
                    'tixian_id': tixian_record.id,
                    'fangshi': tixian_record.fangshi,
                    'txdianhua': tixian_record.phone,
                    'txzh': tixian_record.skzhanghao or '',
                    'txtupian': tixian_record.zhifu or ''  # 返回相对URL
                }

                # 12. 返回成功响应
                return Response({
                    'code': 0,
                    'msg': '提现申请修改成功',
                    'data': response_data
                })

        except Exception as e:
            # 记录详细错误日志
            import logging
            logger = logging.getLogger(__name__)
            logger.error(
                f"修改提现申请异常 - 用户ID: {getattr(user_main, 'yonghuid', 'N/A')}, "
                f"提现ID: {tixian_id}, "
                f"错误类型: {type(e).__name__}, "
                f"错误详情: {str(e)}",
                exc_info=True
            )

            # 返回友好错误信息
            return Response({
                'code': 99,
                'msg': '系统繁忙，请稍后重试',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def handle_shoukuanma_upload(self, user_main, image_file, old_zhifu_url, leixing=None):
        """
        处理收款码图片上传到腾讯云COS
        存储路径: tixian/{yonghuid}/{timestamp_uuid}.扩展名

        参数:
        - user_main: 当前用户对象
        - image_file: 图片文件对象
        - old_zhifu_url: 旧收款码URL（用于删除）
        - leixing: 提现类型（可选，用于文件夹分类）

        返回: 新的图片相对路径
        """
        try:
            yonghuid = user_main.yonghuid
            if not yonghuid:
                return None

            # 删除旧收款码（如果存在且不是空字符串）
            if old_zhifu_url and old_zhifu_url.strip():
                delete_from_oss(old_zhifu_url)

            # 获取文件扩展名
            file_name = image_file.name
            file_extension = os.path.splitext(file_name)[1].lower()
            if not file_extension:
                file_extension = '.jpg'

            # 生成唯一文件名（使用时间戳+UUID确保不重复）
            timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
            unique_id = str(uuid.uuid4())[:8]  # 取UUID前8位
            unique_file_name = f"{timestamp}_{unique_id}{file_extension}"

            # 根据提现类型构建文件夹路径（如果提供了leixing）
            if leixing:
                # leixing=1:打手佣金, leixing=2:管事分红
                type_folder = 'dashou' if leixing == 1 else 'guanshi'
                oss_file_path = f"tixian/{type_folder}/{yonghuid}/{unique_file_name}"
            else:
                # 默认路径
                oss_file_path = f"tixian/{yonghuid}/{unique_file_name}"

            # 上传新收款码到OSS
            new_shoukuanma_url = upload_to_oss(image_file, oss_file_path)

            if new_shoukuanma_url:
                # 返回相对路径（从tixian文件夹开始）
                return oss_file_path
            else:
                return None

        except Exception as e:
            print(f"处理收款码上传失败: {e}")
            return None


# views.py
from django.db.models import Q, Prefetch
from django.db import connection
from django.core.paginator import Paginator
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from dingdan.models import Chufajilu, Chufatupian
from yonghu.models import UserDashou
import logging

logger = logging.getLogger(__name__)


class DashouPermission:
    """
    打手权限验证类
    确保用户是打手且账号状态正常
    """

    def has_permission(self, request, view):
        user = request.user

        # 检查用户是否已认证
        if not user.is_authenticated:
            return False

        try:
            # 通过反向关系获取打手扩展信息
            dashou_profile = user.dashou_profile

            # 检查账号状态是否为1（正常）
            if dashou_profile.zhanghaozhuangtai != 1:
                return False

            return True
        except UserDashou.DoesNotExist:
            return False
        except Exception as e:
            logger.error(f"打手权限验证异常: {e}")
            return False


from django.db.models import Q, Count, Case, When, IntegerField



logger = logging.getLogger(__name__)


class ChufaJiluHuoquView(APIView):
    """
    打手获取处罚记录接口
    路径: /yonghu/dshqcfjl
    方法: POST
    权限: JWT Token + 打手权限验证
    """
    permission_classes = [IsAuthenticated, DashouPermission]

    def post(self, request):
        try:
            # 获取当前用户信息
            user_main = request.user
            yonghuid = user_main.yonghuid

            # 通过反向关系获取打手扩展信息
            try:
                dashou_profile = user_main.dashou_profile
                # 再次确认账号状态
                if dashou_profile.zhanghaozhuangtai != 1:
                    return Response({
                        'code': 3,
                        'msg': '账号已被封禁，无法查看处罚记录',
                        'data': None
                    }, status=status.HTTP_403_FORBIDDEN)
            except UserDashou.DoesNotExist:
                return Response({
                    'code': 2,
                    'msg': '用户不是打手身份',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 判断请求类型：统计信息 or 记录列表
            qingqiu_tongji = request.data.get('qingqiu_tongji', False)

            if qingqiu_tongji:
                # 返回统计信息
                return self.get_tongji_info(yonghuid)
            else:
                # 返回处罚记录列表
                return self.get_chufa_list(yonghuid, request.data)

        except Exception as e:
            logger.error(f"获取处罚记录异常 - 用户ID: {yonghuid}, 错误: {str(e)}", exc_info=True)
            return Response({
                'code': 99,
                'msg': '系统繁忙，请稍后重试',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def get_tongji_info(self, yonghuid):
        """
        获取统计信息（总记录、待处理、已处理）
        """
        try:
            # 使用单个查询获取所有统计信息
            stats = Chufajilu.objects.filter(dashouid=yonghuid).aggregate(
                # 总记录数
                zongshu=Count('id'),

                # 待处理数：状态为0（待处罚）和3（申诉中）
                daichuli=Count(
                    Case(
                        When(Q(sqzhuangtai=0) | Q(sqzhuangtai=3), then=1),
                        output_field=IntegerField()
                    )
                ),

                # 已处理数：状态为1（已处罚）和2（已驳回）
                yichuli=Count(
                    Case(
                        When(Q(sqzhuangtai=1) | Q(sqzhuangtai=2), then=1),
                        output_field=IntegerField()
                    )
                )
            )

            # 如果查询结果为None，则设置为0
            tongji_data = {
                'zongshu': stats.get('zongshu', 0) or 0,
                'daichuli': stats.get('daichuli', 0) or 0,
                'yichuli': stats.get('yichuli', 0) or 0
            }

            return Response({
                'code': 0,
                'msg': '获取统计信息成功',
                'data': tongji_data
            })

        except Exception as e:
            logger.error(f"获取统计信息异常 - 用户ID: {yonghuid}, 错误: {str(e)}")
            return Response({
                'code': 1,
                'msg': '获取统计信息失败',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def get_chufa_list(self, yonghuid, request_data):
        """
        获取处罚记录列表（高性能批量查询）
        🔴 只修改图片查询逻辑，字段保持原样
        """
        try:
            # 获取分页参数
            page = int(request_data.get('page', 1))
            page_size = int(request_data.get('page_size', 10))

            # 限制最大每页数量，防止恶意请求
            if page_size > 50:
                page_size = 50
            if page_size < 1:
                page_size = 10

            # 获取状态筛选参数
            zhuangtai = request_data.get('zhuangtai', 0)

            # 🔴 构建查询条件 - 打手端根据dashouid查询
            queryset = Chufajilu.objects.filter(dashouid=yonghuid)

            if zhuangtai == 0:
                # 待处理：状态为0（待处罚）和3（申诉中）
                queryset = queryset.filter(Q(sqzhuangtai=0) | Q(sqzhuangtai=3))
            elif zhuangtai == 1:
                # 已处理：状态为1（已处罚）和2（已驳回）
                queryset = queryset.filter(Q(sqzhuangtai=1) | Q(sqzhuangtai=2))
            else:
                # 默认返回所有状态
                pass

            # 按创建时间倒序排列（最新在前）
            queryset = queryset.order_by('-create_time')

            # 使用游标分页，避免传统分页的性能问题
            paginator = Paginator(queryset, page_size)

            try:
                page_obj = paginator.page(page)
            except:
                # 页码超出范围，返回空列表
                return Response({
                    'code': 0,
                    'msg': '获取成功',
                    'data': {
                        'list': [],
                        'has_more': False,
                        'page': page,
                        'page_size': page_size,
                        'current_count': 0
                    }
                })

            # 获取当前页的记录
            chufa_records = list(page_obj)

            if not chufa_records:
                # 没有数据直接返回
                return Response({
                    'code': 0,
                    'msg': '获取成功',
                    'data': {
                        'list': [],
                        'has_more': False,
                        'page': page,
                        'page_size': page_size,
                        'current_count': 0
                    }
                })

            # 🔴【核心修复】收集所有需要查询图片的组合
            dingdan_ids = []
            shangjia_ids = []

            for record in chufa_records:
                if record.dingdan_id:
                    dingdan_ids.append(record.dingdan_id)
                if record.qingqiuid:  # 商家ID
                    shangjia_ids.append(record.qingqiuid)

            # 去重
            dingdan_ids = list(set(dingdan_ids))
            shangjia_ids = list(set(shangjia_ids))

            # 🔴【核心修复】分别查询两种图片（避免if-elif逻辑错误）
            # 1. 查询证据图片（商家上传的）
            zhengju_mapping = {}
            if dingdan_ids and shangjia_ids:
                # 构建Q对象：dingdan_id在列表中 AND yonghuid在商家ID列表中
                zhengju_q = Q(dingdan_id__in=dingdan_ids, yonghuid__in=shangjia_ids)
                zhengju_queryset = Chufatupian.objects.filter(zhengju_q).values('dingdan_id', 'yonghuid', 'tupian')

                for item in zhengju_queryset:
                    key = f"{item['dingdan_id']}_{item['yonghuid']}"
                    if key not in zhengju_mapping:
                        zhengju_mapping[key] = []
                    if item['tupian']:
                        zhengju_mapping[key].append(item['tupian'])

            # 2. 查询申诉图片（打手上传的）
            shensu_mapping = {}
            if dingdan_ids:
                # 构建Q对象：dingdan_id在列表中 AND yonghuid=当前打手ID
                shensu_q = Q(dingdan_id__in=dingdan_ids, yonghuid=yonghuid)
                shensu_queryset = Chufatupian.objects.filter(shensu_q).values('dingdan_id', 'yonghuid', 'tupian')

                for item in shensu_queryset:
                    key = f"{item['dingdan_id']}_{item['yonghuid']}"
                    if key not in shensu_mapping:
                        shensu_mapping[key] = []
                    if item['tupian']:
                        shensu_mapping[key].append(item['tupian'])

            # 🔴【核心修复】组装返回数据 - 字段保持原样！
            chufa_list = []
            for record in chufa_records:
                dingdan_id = record.dingdan_id
                shangjia_id = record.qingqiuid

                # 获取证据图片（商家上传的）
                zhengju_tupian = []
                if dingdan_id and shangjia_id:
                    key = f"{dingdan_id}_{shangjia_id}"
                    zhengju_tupian = zhengju_mapping.get(key, [])

                # 获取申诉图片（打手上传的）
                shensu_tupian = []
                if dingdan_id:
                    key = f"{dingdan_id}_{yonghuid}"
                    shensu_tupian = shensu_mapping.get(key, [])

                # 🔴【字段保持原样！】与前端完全对应！
                chufa_data = {
                    'id': record.id,
                    'dingdan_id': record.dingdan_id or '',
                    'qingqiuid': record.qingqiuid or '',  # 商家ID
                    'cfliyou': record.cfliyou or '',
                    'sqzhuangtai': record.sqzhuangtai or 0,
                    'ssliyou': record.ssliyou or '',
                    'jifen': record.jifen or 0,
                    'create_time': record.create_time.strftime('%Y-%m-%d %H:%M:%S') if record.create_time else '',
                    'update_time': record.update_time.strftime('%Y-%m-%d %H:%M:%S') if record.update_time else '',
                    'zhengju_tupian': zhengju_tupian,  # 商家上传的证据图片
                    'shensu_tupian': shensu_tupian,  # 打手上传的申诉图片
                }
                chufa_list.append(chufa_data)

            # 判断是否还有更多数据
            has_more = page_obj.has_next()

            # 构建响应数据
            response_data = {
                'list': chufa_list,
                'has_more': has_more,
                'page': page,
                'page_size': page_size,
                'current_count': len(chufa_list)
            }

            return Response({
                'code': 0,
                'msg': '获取成功',
                'data': response_data
            })

        except ValueError as e:
            logger.error(f"参数错误 - 用户ID: {yonghuid}, 错误: {str(e)}")
            return Response({
                'code': 4,
                'msg': '参数格式错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            logger.error(f"获取处罚记录列表异常 - 用户ID: {yonghuid}, 错误: {str(e)}", exc_info=True)
            return Response({
                'code': 5,
                'msg': '获取记录列表失败',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)





'''class ChufaJiluHuoquView(APIView):
    """
    打手获取处罚记录接口
    路径: /yonghu/dshqcfjl
    方法: POST
    权限: JWT Token + 打手权限验证
    """
    permission_classes = [IsAuthenticated, DashouPermission]

    def post(self, request):
        try:
            # 获取当前用户信息
            user_main = request.user
            yonghuid = user_main.yonghuid

            # 🔴🆕【关键】通过反向关系获取打手扩展信息
            try:
                dashou_profile = user_main.dashou_profile
                # 再次确认账号状态
                if dashou_profile.zhanghaozhuangtai != 1:
                    return Response({
                        'code': 3,
                        'msg': '账号已被封禁，无法查看处罚记录',
                        'data': None
                    }, status=status.HTTP_403_FORBIDDEN)
            except UserDashou.DoesNotExist:
                return Response({
                    'code': 2,
                    'msg': '用户不是打手身份',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 判断请求类型：统计信息 or 记录列表
            qingqiu_tongji = request.data.get('qingqiu_tongji', False)

            if qingqiu_tongji:
                # 🔴🆕【关键】返回统计信息（高效查询）
                return self.get_tongji_info(yonghuid)
            else:
                # 🔴🆕【关键】返回处罚记录列表（高性能游标分页）
                return self.get_chufa_list(yonghuid, request.data)

        except Exception as e:
            logger.error(f"获取处罚记录异常 - 用户ID: {yonghuid}, 错误: {str(e)}", exc_info=True)
            return Response({
                'code': 99,
                'msg': '系统繁忙，请稍后重试',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def get_tongji_info(self, yonghuid):
        """
        获取统计信息（总记录、待处理、已处理）
        使用高效的单次查询，避免多次count查询
        """
        try:
            # 🔴🆕【关键】使用单个查询获取所有统计信息，减少数据库查询次数
            # 使用条件聚合查询
            from django.db.models import Count, Case, When, IntegerField

            stats = Chufajilu.objects.filter(dashouid=yonghuid).aggregate(
                # 总记录数
                zongshu=Count('id'),

                # 待处理数：状态为0（待处罚）和3（申诉中）
                daichuli=Count(
                    Case(
                        When(Q(sqzhuangtai=0) | Q(sqzhuangtai=3), then=1),
                        output_field=IntegerField()
                    )
                ),

                # 已处理数：状态为1（已处罚）和2（已驳回）
                yichuli=Count(
                    Case(
                        When(Q(sqzhuangtai=1) | Q(sqzhuangtai=2), then=1),
                        output_field=IntegerField()
                    )
                )
            )

            # 如果查询结果为None，则设置为0
            tongji_data = {
                'zongshu': stats.get('zongshu', 0) or 0,
                'daichuli': stats.get('daichuli', 0) or 0,
                'yichuli': stats.get('yichuli', 0) or 0
            }

            return Response({
                'code': 0,
                'msg': '获取统计信息成功',
                'data': tongji_data
            })

        except Exception as e:
            logger.error(f"获取统计信息异常 - 用户ID: {yonghuid}, 错误: {str(e)}")
            return Response({
                'code': 1,
                'msg': '获取统计信息失败',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def get_chufa_list(self, yonghuid, request_data):
        """
        获取处罚记录列表（高性能游标分页）
        关键优化：使用JOIN减少查询次数，批量获取图片数据
        """
        try:
            # 🔴🆕【关键】获取分页参数
            page = int(request_data.get('page', 1))
            page_size = int(request_data.get('page_size', 10))

            # 限制最大每页数量，防止恶意请求
            if page_size > 50:
                page_size = 50
            if page_size < 1:
                page_size = 10

            # 🔴🆕【关键】获取状态筛选参数
            zhuangtai = request_data.get('zhuangtai', 0)

            # 构建查询条件
            queryset = Chufajilu.objects.filter(dashouid=yonghuid)

            if zhuangtai == 0:
                # 待处理：状态为0（待处罚）和3（申诉中）
                queryset = queryset.filter(Q(sqzhuangtai=0) | Q(sqzhuangtai=3))
            elif zhuangtai == 1:
                # 已处理：状态为1（已处罚）和2（已驳回）
                queryset = queryset.filter(Q(sqzhuangtai=1) | Q(sqzhuangtai=2))
            else:
                # 默认返回所有状态
                pass

            # 🔴🆕【关键】按创建时间倒序排列（最新在前）
            queryset = queryset.order_by('-create_time')

            # 🔴🆕【关键】使用游标分页，避免传统分页的性能问题
            paginator = Paginator(queryset, page_size)

            try:
                page_obj = paginator.page(page)
            except:
                # 页码超出范围，返回空列表
                return Response({
                    'code': 0,
                    'msg': '获取成功',
                    'data': {
                        'list': [],
                        'has_more': False,
                        'page': page,
                        'page_size': page_size,
                        'current_count': 0
                    }
                })

            # 获取当前页的记录
            chufa_records = list(page_obj)

            if not chufa_records:
                # 没有数据直接返回
                return Response({
                    'code': 0,
                    'msg': '获取成功',
                    'data': {
                        'list': [],
                        'has_more': False,
                        'page': page,
                        'page_size': page_size,
                        'current_count': 0
                    }
                })

            # 🔴🆕【关键】批量获取所有相关的图片数据（性能优化核心）
            # 提取所有dingdan_id
            dingdan_ids = [record.dingdan_id for record in chufa_records if record.dingdan_id]

            # 提取所有qingqiuid（申请人ID）
            qingqiuids = [record.qingqiuid for record in chufa_records if record.qingqiuid]

            # 🔴🆕【关键】批量查询证据图片（申请人上传的图片）
            # 使用单个查询获取所有相关图片，避免N+1查询
            zhengju_tupian_queryset = Chufatupian.objects.filter(
                dingdan_id__in=dingdan_ids,
                yonghuid__in=qingqiuids
            ).values('dingdan_id', 'yonghuid', 'tupian')

            # 将证据图片按(dingdan_id, yonghuid)分组
            zhengju_tupian_dict = {}
            for item in zhengju_tupian_queryset:
                key = f"{item['dingdan_id']}_{item['yonghuid']}"
                if key not in zhengju_tupian_dict:
                    zhengju_tupian_dict[key] = []
                if item['tupian']:
                    zhengju_tupian_dict[key].append(item['tupian'])

            # 🔴🆕【关键】批量查询申诉图片（打手上传的图片）
            shensu_tupian_queryset = Chufatupian.objects.filter(
                dingdan_id__in=dingdan_ids,
                yonghuid=yonghuid  # 打手自己上传的图片
            ).values('dingdan_id', 'yonghuid', 'tupian')

            # 将申诉图片按dingdan_id分组
            shensu_tupian_dict = {}
            for item in shensu_tupian_queryset:
                dingdan_id = item['dingdan_id']
                if dingdan_id not in shensu_tupian_dict:
                    shensu_tupian_dict[dingdan_id] = []
                if item['tupian']:
                    shensu_tupian_dict[dingdan_id].append(item['tupian'])

            # 🔴🆕【关键】组装返回数据
            chufa_list = []
            for record in chufa_records:
                # 获取证据图片
                zhengju_tupian = []
                if record.dingdan_id and record.qingqiuid:
                    key = f"{record.dingdan_id}_{record.qingqiuid}"
                    zhengju_tupian = zhengju_tupian_dict.get(key, [])

                # 获取申诉图片
                shensu_tupian = []
                if record.dingdan_id:
                    shensu_tupian = shensu_tupian_dict.get(record.dingdan_id, [])

                # 构建返回数据格式（与前端对应）
                chufa_data = {
                    'id': record.id,  # 处罚记录ID
                    'dingdan_id': record.dingdan_id or '',
                    'qingqiuid': record.qingqiuid or '',  # 申请人ID
                    'cfliyou': record.cfliyou or '',
                    'sqzhuangtai': record.sqzhuangtai or 0,
                    'ssliyou': record.ssliyou or '',  # 申诉理由
                    'jifen': record.jifen or 0,
                    'create_time': record.create_time.strftime('%Y-%m-%d %H:%M:%S') if record.create_time else '',
                    'update_time': record.update_time.strftime('%Y-%m-%d %H:%M:%S') if record.update_time else '',
                    # 图片数据
                    'zhengju_tupian': zhengju_tupian,  # 证据图片数组
                    'shensu_tupian': shensu_tupian,  # 申诉图片数组
                }
                chufa_list.append(chufa_data)

            # 判断是否还有更多数据
            has_more = page_obj.has_next()

            # 构建响应数据
            response_data = {
                'list': chufa_list,
                'has_more': has_more,
                'page': page,
                'page_size': page_size,
                'current_count': len(chufa_list)
            }

            return Response({
                'code': 0,
                'msg': '获取成功',
                'data': response_data
            })

        except ValueError as e:
            logger.error(f"参数错误 - 用户ID: {yonghuid}, 错误: {str(e)}")
            return Response({
                'code': 4,
                'msg': '参数格式错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            logger.error(f"获取处罚记录列表异常 - 用户ID: {yonghuid}, 错误: {str(e)}", exc_info=True)
            return Response({
                'code': 5,
                'msg': '获取记录列表失败',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)'''


class DashouShensuView(APIView):
    """
    打手申诉接口
    路径: /yonghu/dscfss
    方法: POST
    权限: JWT Token + 打手权限验证
    功能: 打手对处罚进行申诉
    """
    permission_classes = [IsAuthenticated, DashouPermission]

    def post(self, request):
        try:
            # 获取当前用户信息
            user_main = request.user
            yonghuid = user_main.yonghuid

            # 🔴🆕【关键】验证打手账号状态
            try:
                dashou_profile = user_main.dashou_profile
                if dashou_profile.zhanghaozhuangtai != 1:
                    return Response({
                        'code': 3,
                        'msg': '账号已被封禁，无法申诉',
                        'data': None
                    }, status=status.HTTP_403_FORBIDDEN)
            except UserDashou.DoesNotExist:
                return Response({
                    'code': 2,
                    'msg': '用户不是打手身份',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 🔴🆕【关键】获取请求参数
            chufa_id = request.data.get('chufa_id')  # 处罚记录ID
            shensu_liyou = request.data.get('shensu_liyou', '').strip()  # 申诉理由
            shensu_tupian_urls = request.data.get('shensu_tupian_urls', [])  # 申诉图片URL数组

            # 验证必填字段
            if not chufa_id:
                return Response({
                    'code': 6,
                    'msg': '处罚记录ID不能为空',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            if not shensu_liyou:
                return Response({
                    'code': 7,
                    'msg': '申诉理由不能为空',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 验证申诉理由长度
            if len(shensu_liyou) > 500:
                return Response({
                    'code': 8,
                    'msg': '申诉理由不能超过500字',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 验证图片数量
            if len(shensu_tupian_urls) > 9:
                return Response({
                    'code': 9,
                    'msg': '最多只能上传9张图片',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 🔴🆕【关键】使用事务确保数据一致性
            from django.db import transaction

            with transaction.atomic():
                # 1. 查询处罚记录
                try:
                    chufa_record = Chufajilu.objects.select_for_update().get(
                        id=chufa_id,
                        dashouid=yonghuid  # 确保只能申诉自己的处罚记录
                    )
                except Chufajilu.DoesNotExist:
                    return Response({
                        'code': 10,
                        'msg': '处罚记录不存在或无权申诉',
                        'data': None
                    }, status=status.HTTP_404_NOT_FOUND)

                # 2. 验证处罚记录状态（必须是待处理状态0）
                if chufa_record.sqzhuangtai != 0:
                    return Response({
                        'code': 11,
                        'msg': '该处罚记录已处理，无法申诉',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                # 3. 验证订单是否存在（可选，根据需求决定）
                # 这里可以根据dingdan_id去查询订单表，但根据需求描述，我们已经有了处罚记录
                # 处罚记录中包含了dingdan_id，如果dingdan_id不存在，说明订单可能被删除
                # 但根据业务逻辑，有处罚记录就应该有订单，所以这里可以跳过这个检查

                # 4. 检查是否已有申诉记录（防止重复申诉）
                if chufa_record.ssliyou or chufa_record.sqzhuangtai == 3:
                    # 检查是否已经有申诉图片
                    existing_shensu_tupian = Chufatupian.objects.filter(
                        dingdan_id=chufa_record.dingdan_id,
                        yonghuid=yonghuid
                    ).exists()

                    if existing_shensu_tupian:
                        return Response({
                            'code': 12,
                            'msg': '您已经提交过申诉，请等待处理结果',
                            'data': None
                        }, status=status.HTTP_400_BAD_REQUEST)

                # 5. 更新处罚记录
                chufa_record.ssliyou = shensu_liyou
                chufa_record.sqzhuangtai = 3  # 状态改为申诉中
                chufa_record.save()

                # 6. 保存申诉图片（如果有）
                saved_tupian_urls = []
                if shensu_tupian_urls:
                    for tupian_url in shensu_tupian_urls:
                        if tupian_url:  # 确保URL不为空
                            chufa_tupian = Chufatupian.objects.create(
                                dingdan_id=chufa_record.dingdan_id,
                                yonghuid=yonghuid,
                                tupian=tupian_url
                            )
                            saved_tupian_urls.append(tupian_url)

                # 7. 构建返回数据
                response_data = {
                    'chufa_id': chufa_record.id,
                    'dingdan_id': chufa_record.dingdan_id or '',
                    'shensu_liyou': shensu_liyou,
                    'shensu_tupian_urls': saved_tupian_urls,
                    'sqzhuangtai': chufa_record.sqzhuangtai,
                    'update_time': chufa_record.update_time.strftime(
                        '%Y-%m-%d %H:%M:%S') if chufa_record.update_time else ''
                }

                # 记录操作日志
                logger.info(f"打手申诉成功 - 用户ID: {yonghuid}, 处罚ID: {chufa_id}, 订单ID: {chufa_record.dingdan_id}")

                return Response({
                    'code': 0,
                    'msg': '申诉提交成功',
                    'data': response_data
                })

        except Exception as e:
            logger.error(f"打手申诉异常 - 用户ID: {yonghuid}, 错误: {str(e)}", exc_info=True)
            return Response({
                'code': 99,
                'msg': '系统繁忙，请稍后重试',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)






class ShangjiaChufaJiluHuoquView(APIView):
    """
    商家获取处罚记录接口
    路径: /yonghu/sjcfjlhq
    方法: POST
    权限: JWT Token + 商家权限验证
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 获取当前用户信息
            user_main = request.user
            yonghuid = user_main.yonghuid

            # 通过反向关系获取商家扩展信息
            try:
                shangjia_profile = user_main.shop_profile
                # 再次确认账号状态
                if shangjia_profile.zhuangtai != 1:
                    return Response({
                        'code': 3,
                        'msg': '商家账号状态异常，无法查看处罚记录',
                        'data': None
                    }, status=status.HTTP_403_FORBIDDEN)
            except UserShangjia.DoesNotExist:
                return Response({
                    'code': 2,
                    'msg': '用户不是商家身份',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 判断请求类型
            qingqiu_tongji = request.data.get('qingqiu_tongji', False)

            if qingqiu_tongji:
                return self.get_tongji_info(yonghuid)
            else:
                return self.get_chufa_list(yonghuid, request.data)

        except Exception as e:
            logger.error(f"商家获取处罚记录异常 - 用户ID: {yonghuid}, 错误: {str(e)}", exc_info=True)
            return Response({
                'code': 99,
                'msg': '系统繁忙，请稍后重试',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def get_tongji_info(self, yonghuid):
        """
        获取统计信息
        """
        try:
            # 🔴 查询条件：qingqiuid = 当前商家ID
            stats = Chufajilu.objects.filter(qingqiuid=yonghuid).aggregate(
                zongshu=Count('id'),
                daichuli=Count(
                    Case(
                        When(Q(sqzhuangtai=0) | Q(sqzhuangtai=3), then=1),
                        output_field=IntegerField()
                    )
                ),
                yichuli=Count(
                    Case(
                        When(Q(sqzhuangtai=1) | Q(sqzhuangtai=2), then=1),
                        output_field=IntegerField()
                    )
                )
            )

            tongji_data = {
                'zongshu': stats.get('zongshu', 0) or 0,
                'daichuli': stats.get('daichuli', 0) or 0,
                'yichuli': stats.get('yichuli', 0) or 0
            }

            return Response({
                'code': 0,
                'msg': '获取统计信息成功',
                'data': tongji_data
            })

        except Exception as e:
            logger.error(f"商家获取统计信息异常 - 用户ID: {yonghuid}, 错误: {str(e)}")
            return Response({
                'code': 1,
                'msg': '获取统计信息失败',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def get_chufa_list(self, yonghuid, request_data):
        """
        获取处罚记录列表（商家端）
        🔴 只修改图片查询逻辑，字段保持原样
        """
        try:
            # 获取分页参数
            page = int(request_data.get('page', 1))
            page_size = int(request_data.get('page_size', 10))

            if page_size > 50:
                page_size = 50
            if page_size < 1:
                page_size = 10

            # 获取状态筛选参数
            zhuangtai = request_data.get('zhuangtai', 0)

            # 🔴 查询条件：qingqiuid = 当前商家ID
            queryset = Chufajilu.objects.filter(qingqiuid=yonghuid)

            if zhuangtai == 0:
                queryset = queryset.filter(Q(sqzhuangtai=0) | Q(sqzhuangtai=3))
            elif zhuangtai == 1:
                queryset = queryset.filter(Q(sqzhuangtai=1) | Q(sqzhuangtai=2))
            else:
                pass

            # 按创建时间倒序排列
            queryset = queryset.order_by('-create_time')

            # 分页逻辑
            paginator = Paginator(queryset, page_size)

            try:
                page_obj = paginator.page(page)
            except:
                return Response({
                    'code': 0,
                    'msg': '获取成功',
                    'data': {
                        'list': [],
                        'has_more': False,
                        'page': page,
                        'page_size': page_size,
                        'current_count': 0
                    }
                })

            chufa_records = list(page_obj)

            if not chufa_records:
                return Response({
                    'code': 0,
                    'msg': '获取成功',
                    'data': {
                        'list': [],
                        'has_more': False,
                        'page': page,
                        'page_size': page_size,
                        'current_count': 0
                    }
                })

            # 🔴【核心修复】收集所有需要查询图片的组合
            dingdan_ids = []
            dashou_ids = []

            for record in chufa_records:
                if record.dingdan_id:
                    dingdan_ids.append(record.dingdan_id)
                if record.dashouid:  # 打手ID
                    dashou_ids.append(record.dashouid)

            # 去重
            dingdan_ids = list(set(dingdan_ids))
            dashou_ids = list(set(dashou_ids))

            # 🔴【核心修复】分别查询两种图片（避免if-elif逻辑错误）
            # 1. 查询证据图片（商家自己上传的）
            zhengju_mapping = {}
            if dingdan_ids:
                # 构建Q对象：dingdan_id在列表中 AND yonghuid=当前商家ID
                zhengju_q = Q(dingdan_id__in=dingdan_ids, yonghuid=yonghuid)
                zhengju_queryset = Chufatupian.objects.filter(zhengju_q).values('dingdan_id', 'yonghuid', 'tupian')

                for item in zhengju_queryset:
                    key = f"{item['dingdan_id']}_{item['yonghuid']}"
                    if key not in zhengju_mapping:
                        zhengju_mapping[key] = []
                    if item['tupian']:
                        zhengju_mapping[key].append(item['tupian'])

            # 2. 查询申诉图片（打手上传的）
            shensu_mapping = {}
            if dingdan_ids and dashou_ids:
                # 构建Q对象：dingdan_id在列表中 AND yonghuid在打手ID列表中
                shensu_q = Q(dingdan_id__in=dingdan_ids, yonghuid__in=dashou_ids)
                shensu_queryset = Chufatupian.objects.filter(shensu_q).values('dingdan_id', 'yonghuid', 'tupian')

                for item in shensu_queryset:
                    key = f"{item['dingdan_id']}_{item['yonghuid']}"
                    if key not in shensu_mapping:
                        shensu_mapping[key] = []
                    if item['tupian']:
                        shensu_mapping[key].append(item['tupian'])

            # 🔴【核心修复】组装返回数据 - 字段保持原样！
            chufa_list = []
            for record in chufa_records:
                dingdan_id = record.dingdan_id
                dashou_id = record.dashouid

                # 获取证据图片（商家自己上传的）
                zhengju_tupian = []
                if dingdan_id:
                    key = f"{dingdan_id}_{yonghuid}"
                    zhengju_tupian = zhengju_mapping.get(key, [])

                # 获取申诉图片（打手上传的）
                shensu_tupian = []
                if dingdan_id and dashou_id:
                    key = f"{dingdan_id}_{dashou_id}"
                    shensu_tupian = shensu_mapping.get(key, [])

                # 🔴【字段保持原样！】与前端完全对应！
                chufa_data = {
                    'id': record.id,
                    'dingdan_id': record.dingdan_id or '',
                    'qingqiuid': record.dashouid or '',  # 打手ID
                    'cfliyou': record.cfliyou or '',
                    'sqzhuangtai': record.sqzhuangtai or 0,
                    'ssliyou': record.ssliyou or '',
                    'jifen': record.jifen or 0,
                    'create_time': record.create_time.strftime('%Y-%m-%d %H:%M:%S') if record.create_time else '',
                    'update_time': record.update_time.strftime('%Y-%m-%d %H:%M:%S') if record.update_time else '',
                    'zhengju_tupian': zhengju_tupian,  # 商家自己上传的证据图片
                    'shensu_tupian': shensu_tupian,  # 打手上传的申诉图片
                }
                chufa_list.append(chufa_data)

            # 判断是否还有更多数据
            has_more = page_obj.has_next()

            response_data = {
                'list': chufa_list,
                'has_more': has_more,
                'page': page,
                'page_size': page_size,
                'current_count': len(chufa_list)
            }

            return Response({
                'code': 0,
                'msg': '获取成功',
                'data': response_data
            })

        except ValueError as e:
            logger.error(f"商家端参数错误 - 用户ID: {yonghuid}, 错误: {str(e)}")
            return Response({
                'code': 4,
                'msg': '参数格式错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            logger.error(f"商家获取处罚记录列表异常 - 用户ID: {yonghuid}, 错误: {str(e)}", exc_info=True)
            return Response({
                'code': 5,
                'msg': '获取记录列表失败',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)














logger = logging.getLogger(__name__)

class KefuLoginView(APIView):
    """
    客服登录接口（支持手机号重复）
    请求：POST /yonghu/kefujinru
    请求体：{"phone": "13800138000", "password": "xxx", "erjimima": "yyy"}
    返回：
        code=0 成功，data包含token,nicheng,yonghuid
        code=4 账号被封禁（提示“账号已被封禁”）
        其他错误统一 code=1 msg="登录失败"
    """
    throttle_classes = [AnonRateThrottle]          # 限制匿名请求频率
    permission_classes = [AllowAny]                # 任何人都可访问

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        password = request.data.get('password', '')
        erjimima = request.data.get('erjimima', '')

        if not phone or not password or not erjimima:
            return Response({
                'code': 1,
                'msg': '登录失败',          # 统一提示，不暴露具体原因
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        # 2. 获取客户端真实IP
        client_ip = self.get_client_ip(request)

        # 3. 查询所有手机号匹配且类型为客服的用户
        #    注意：UserMain 中需要有 user_type 字段，且值为 'kefu' 代表客服
        user_mains = UserMain.objects.filter(
            phone=phone,
            user_type='kefu'               # 只查找客服账号
        ).select_related('kefu_profile')    # 预加载客服扩展表

        if not user_mains.exists():
            logger.warning(f"登录失败，手机号不存在或非客服: {phone}, IP: {client_ip}")
            return Response({
                'code': 1,
                'msg': '登录失败',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        # 4. 遍历所有匹配的用户，验证密码和二级密码
        target_user = None
        target_kefu = None

        for user in user_mains:
            # 验证主密码（明文比较，按您的要求）
            if user.password != password:
                continue

            # 检查是否存在客服扩展表
            try:
                kefu = user.kefu_profile
            except UserKefu.DoesNotExist:
                continue

            # 验证二级密码（明文比较）
            if kefu.erjimima != erjimima:
                continue

            # 如果账号被禁用，记录但继续查找（可能还有其他正常账号？）
            if kefu.zhuangtai != 1:
                # 如果找到被禁用的，记录下来，但继续查找是否有正常账号
                if target_user is None:
                    # 暂时记录这个禁用账号，但继续遍历
                    target_user = user
                    target_kefu = kefu
                continue

            # 找到完全匹配且状态正常的账号，立即使用
            target_user = user
            target_kefu = kefu
            break
        else:
            # 循环结束未找到正常账号，但可能找到了禁用账号
            if target_user and target_kefu:
                # 只有被禁用的账号匹配，返回封禁提示
                logger.warning(f"登录失败，客服账号已禁用: {phone}, IP: {client_ip}")
                return Response({
                    'code': 4,
                    'msg': '账号已被封禁',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)
            else:
                # 没有任何账号匹配（密码/二级密码错误）
                logger.warning(f"登录失败，密码或二级密码错误: {phone}, IP: {client_ip}")
                return Response({
                    'code': 1,
                    'msg': '登录失败',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

        # 5. 更新IP和最后登录时间
        target_user.ip = client_ip
        target_user.last_login_time = timezone.now()
        target_user.save(update_fields=['ip', 'last_login_time'])

        # 6. 生成JWT token
        refresh = RefreshToken.for_user(target_user)
        token = str(refresh.access_token)

        # 7. 返回成功数据
        return Response({
            'code': 0,
            'msg': '登录成功',
            'data': {
                'token': token,
                'nicheng': target_kefu.nicheng,
                'yonghuid': target_user.yonghuid,
            }
        })

    def get_client_ip(self, request):
        """
        获取客户端真实IP
        """
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0].strip()
            if ip:
                return ip
        return request.META.get('REMOTE_ADDR', '0.0.0.0')






logger = logging.getLogger(__name__)

class KefuStatsView(APIView):
    """
    客服统计数据接口
    请求：POST /yonghu/kfjrhqzl
    请求体：{"phone": "13800138000"}
    认证：必须携带有效的 JWT token（放在 Authorization 头）
    返回：
        code=0 成功，data 包含 jinrichuli, jinyuechuli, zongchuli
        验证失败统一返回 401，不透露具体原因
    """

    permission_classes = [IsAuthenticated]        # 必须登录


    def post(self, request):
        # 1. 获取请求中的 phone
        phone = request.data.get('phone', '').strip()
        if not phone:
            # 缺少参数，但按约定返回 401（可以改为 400，但为了统一，用401）
            logger.warning(f"统计接口缺少 phone 参数，用户: {request.user.yonghuid}")
            return Response({'detail': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 获取当前登录用户（从 JWT 中解析）
        current_user = request.user

        # 3. 验证前端传来的 phone 是否与当前用户的 phone 一致
        if current_user.phone != phone:
            # 不一致，可能 token 被冒用或参数错误
            logger.warning(f"统计接口 phone 不匹配: 请求phone={phone}, 用户phone={current_user.phone}")
            return Response({'detail': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 4. 验证用户类型是否为客服
        if current_user.user_type != 'kefu':
            logger.warning(f"统计接口用户类型非客服: {current_user.yonghuid}")
            return Response({'detail': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 5. 尝试获取客服扩展表数据
        try:
            kefu_profile = current_user.kefu_profile  # OneToOneField 反向关系
        except UserKefu.DoesNotExist:
            logger.warning(f"统计接口客服扩展表不存在: {current_user.yonghuid}")
            return Response({'detail': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 6. 返回统计数据（字段名与前端约定一致）
        return Response({
            'code': 0,
            'data': {
                'jinrichuli': kefu_profile.jinrichuli,
                'jinyuechuli': kefu_profile.jinyuechuli,
                'zongchuli': kefu_profile.zongchuli,
            }
        }, status=status.HTTP_200_OK)






from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser
import logging
from shangpin.models import ShangpinLeixing  # 假设商品类型表名，请根据实际调整

logger = logging.getLogger(__name__)

class KefuGetOrderTypesView(APIView):
    """
    客服获取订单类型列表接口（平台订单用）
    请求：POST /yonghu/kfhqptddlx
    参数：{"phone": "13800138000"}
    认证：JWT
    返回：code=0 + 类型列表
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        if not phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        current_user = request.user

        # 2. 验证手机号一致性
        if getattr(current_user, 'phone', '') != phone:
            logger.warning(f"手机号不匹配: 请求phone={phone}, 用户phone={current_user.phone}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 验证用户类型及客服状态
        if current_user.user_type != 'kefu':
            logger.warning(f"用户类型非客服: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        try:
            kefu_profile = current_user.kefu_profile
        except ObjectDoesNotExist:
            logger.warning(f"客服扩展表不存在: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if kefu_profile.zhuangtai != 1:
            logger.warning(f"客服账号已被禁用: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 4. 查询订单类型（商品类型）
        try:
            # 只查询需要的字段，减少数据传输
            types_qs = ShangpinLeixing.objects.all().only('id', 'jieshao', 'tupian_url')
            type_list = [
                {
                    'id': t.id,
                    'biaoti': t.jieshao or '',          # 假设商品类型的标题字段为 jieshao
                    'tupian_url': t.tupian_url or ''
                }
                for t in types_qs
            ]
            return Response({'code': 0, 'data': type_list})
        except Exception as e:
            logger.error(f"查询商品类型表失败: {str(e)}")
            # 表不存在或查询失败，返回空列表
            return Response({'code': 0, 'data': []})







import time
import logging
from django.db.models import Q, Count
from django.core.exceptions import ObjectDoesNotExist
from rest_framework.views import APIView

from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser


logger = logging.getLogger(__name__)

'''class KefuGetOrderListView(APIView):
    """
    客服获取平台订单列表接口（发单平台=1）
    请求参数：
        phone: 客服账号
        page: 页码
        pageSize: 每页条数
        dingdan_id: 订单ID（精确搜索）
        laoban_id: 老板ID（搜索平台扩展表中的老板）
        dashou_id: 打手ID（搜索主表中的接单打手）
        leixing: 商品类型ID
        zhuangtai: 状态（多个用逗号分隔，如 "1,7"）
        date: 日期（YYYY-MM-DD），筛选订单创建时间
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        start_total = time.time()

        phone = request.data.get('phone', '').strip()
        page = int(request.data.get('page', 1))
        page_size = int(request.data.get('pageSize', 20))

        dingdan_id = request.data.get('dingdan_id', '').strip()
        laoban_id = request.data.get('laoban_id', '').strip()
        dashou_id = request.data.get('dashou_id', '').strip()
        leixing = request.data.get('leixing')
        zhuangtai = request.data.get('zhuangtai', '')
        date = request.data.get('date', '').strip()  # 日期筛选

        if not phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if current_user.user_type != 'kefu':
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if kefu.zhuangtai != 1:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # ---------- 查询条件 ----------
        base_q = Q(fadan_pingtai=1)  # 平台订单

        if dingdan_id:
            q_conditions = base_q & Q(dingdan_id=dingdan_id)
        else:
            q_conditions = base_q
            if leixing is not None:
                try:
                    leixing_int = int(leixing)
                    q_conditions &= Q(leixing_id=leixing_int)
                except (ValueError, TypeError):
                    pass
            if zhuangtai and zhuangtai != 'all':
                try:
                    status_list = [int(s.strip()) for s in zhuangtai.split(',') if s.strip()]
                    if status_list:
                        q_conditions &= Q(zhuangtai__in=status_list)
                except (ValueError, TypeError):
                    pass
            if dashou_id:
                q_conditions &= Q(jiedan_dashou_id=dashou_id)
            if laoban_id:
                q_conditions &= Q(pingtai_kuozhan__laoban_id=laoban_id)
            if date:
                q_conditions &= Q(create_time__date=date)  # 按日期筛选

        # ---------- 统计（仅按发单平台） ----------
        stats = Dingdan.objects.filter(fadan_pingtai=1).aggregate(
            total_orders=Count('id'),
            completed_orders=Count('id', filter=Q(zhuangtai=3)),
            refund_orders=Count('id', filter=Q(zhuangtai=5)),
            pending_orders=Count('id', filter=Q(zhuangtai__in=[4,8]))
        )

        # ---------- 状态计数（所有状态都返回） ----------
        status_counts = {
            'all': Dingdan.objects.filter(fadan_pingtai=1).count(),
            '1,7': Dingdan.objects.filter(fadan_pingtai=1, zhuangtai__in=[1,7]).count(),
            '2': Dingdan.objects.filter(fadan_pingtai=1, zhuangtai=2).count(),
            '8': Dingdan.objects.filter(fadan_pingtai=1, zhuangtai=8).count(),
            '3': Dingdan.objects.filter(fadan_pingtai=1, zhuangtai=3).count(),
            '4': Dingdan.objects.filter(fadan_pingtai=1, zhuangtai=4).count(),
            '5': Dingdan.objects.filter(fadan_pingtai=1, zhuangtai=5).count(),
            '6': Dingdan.objects.filter(fadan_pingtai=1, zhuangtai=6).count(),
        }

        # ---------- 分页查询 ----------
        total_count = Dingdan.objects.filter(q_conditions).count()

        orders_qs = Dingdan.objects.filter(q_conditions).select_related(
            'pingtai_kuozhan'  # 预加载平台扩展表
        ).only(
            'dingdan_id', 'jieshao', 'zhuangtai', 'leixing_id', 'fadan_pingtai',
            'jine', 'tupian', 'create_time', 'nicheng', 'jiedan_dashou_id',
            'pingtai_kuozhan__laoban_id'
        ).order_by('-create_time')[(page-1)*page_size : page*page_size]

        # ---------- 获取老板昵称 ----------
        laoban_ids = [o.pingtai_kuozhan.laoban_id for o in orders_qs if hasattr(o, 'pingtai_kuozhan') and o.pingtai_kuozhan.laoban_id]
        nickname_map = {}
        if laoban_ids:
            users = UserMain.objects.filter(yonghuid__in=laoban_ids).select_related('boss_profile').only(
                'yonghuid', 'boss_profile__nickname'
            )
            for user in users:
                nickname_map[user.yonghuid] = user.boss_profile.nickname or '' if hasattr(user, 'boss_profile') else ''

        result_list = []
        for order in orders_qs:
            ext = getattr(order, 'pingtai_kuozhan', None)
            laoban_id = ext.laoban_id if ext else ''
            youxi_nicheng = nickname_map.get(laoban_id, order.nicheng or '')
            result_list.append({
                'dingdan_id': order.dingdan_id or '',
                'jieshao': order.jieshao or '',
                'zhuangtai': order.zhuangtai,
                'leixing': order.leixing_id,
                'fadanpingtai': order.fadan_pingtai,
                'jiage': float(order.jine) if order.jine else 0.00,
                'tupian_url': order.tupian or '',
                'fadanshijian': order.create_time.strftime('%Y-%m-%d %H:%M:%S') if order.create_time else '',
                'youxi_nicheng': youxi_nicheng
            })

        response_data = {
            'stats': {
                'totalOrders': stats['total_orders'] or 0,
                'completedOrders': stats['completed_orders'] or 0,
                'refundOrders': stats['refund_orders'] or 0,
                'pendingOrders': stats['pending_orders'] or 0
            },
            'statusCounts': status_counts,
            'list': result_list,
            'total': total_count,
            'page': page,
            'pageSize': page_size
        }

        logger.info(f"平台订单接口总耗时: {time.time()-start_total:.3f}s")
        return Response({'code': 0, 'data': response_data})







logger = logging.getLogger(__name__)

class KefuGetShangjiaOrderListView(APIView):
    """
    客服获取商家订单列表接口（发单平台=2）
    请求参数：
        phone: 客服账号
        page: 页码
        pageSize: 每页条数
        dingdan_id: 订单ID（精确搜索）
        shangjia_id: 商家ID（搜索商家扩展表中的商家ID）
        dashou_id: 打手ID（搜索主表中的接单打手）
        leixing: 商品类型ID
        zhuangtai: 状态（多个用逗号分隔，如 "1,7"）
        date: 日期（YYYY-MM-DD），筛选订单创建时间
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        start_total = time.time()

        phone = request.data.get('phone', '').strip()
        page = int(request.data.get('page', 1))
        page_size = int(request.data.get('pageSize', 20))

        dingdan_id = request.data.get('dingdan_id', '').strip()
        shangjia_id = request.data.get('shangjia_id', '').strip()
        dashou_id = request.data.get('dashou_id', '').strip()
        leixing = request.data.get('leixing')
        zhuangtai = request.data.get('zhuangtai', '')
        date = request.data.get('date', '').strip()  # 格式 YYYY-MM-DD

        if not phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if current_user.user_type != 'kefu':
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if kefu.zhuangtai != 1:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # ---------- 查询条件 ----------
        base_q = Q(fadan_pingtai=2)  # 商家订单

        if dingdan_id:
            q_conditions = base_q & Q(dingdan_id=dingdan_id)
        else:
            q_conditions = base_q
            if leixing is not None:
                try:
                    leixing_int = int(leixing)
                    q_conditions &= Q(leixing_id=leixing_int)
                except (ValueError, TypeError):
                    pass
            if zhuangtai and zhuangtai != 'all':
                try:
                    status_list = [int(s.strip()) for s in zhuangtai.split(',') if s.strip()]
                    if status_list:
                        q_conditions &= Q(zhuangtai__in=status_list)
                except (ValueError, TypeError):
                    pass
            if dashou_id:
                q_conditions &= Q(jiedan_dashou_id=dashou_id)
            if shangjia_id:
                q_conditions &= Q(shangjia_kuozhan__shangjia_id=shangjia_id)  # 关联商家扩展表
            if date:
                q_conditions &= Q(create_time__date=date)  # 按日期筛选

        # ---------- 统计（仅按发单平台） ----------
        stats = Dingdan.objects.filter(fadan_pingtai=2).aggregate(
            total_orders=Count('id'),
            completed_orders=Count('id', filter=Q(zhuangtai=3)),
            refund_orders=Count('id', filter=Q(zhuangtai=5)),
            pending_orders=Count('id', filter=Q(zhuangtai__in=[4,8]))
        )

        # ---------- 状态计数（所有状态都返回） ----------
        status_counts = {
            'all': Dingdan.objects.filter(fadan_pingtai=2).count(),
            '1,7': Dingdan.objects.filter(fadan_pingtai=2, zhuangtai__in=[1,7]).count(),
            '2': Dingdan.objects.filter(fadan_pingtai=2, zhuangtai=2).count(),
            '8': Dingdan.objects.filter(fadan_pingtai=2, zhuangtai=8).count(),
            '3': Dingdan.objects.filter(fadan_pingtai=2, zhuangtai=3).count(),
            '4': Dingdan.objects.filter(fadan_pingtai=2, zhuangtai=4).count(),
            '5': Dingdan.objects.filter(fadan_pingtai=2, zhuangtai=5).count(),
            '6': Dingdan.objects.filter(fadan_pingtai=2, zhuangtai=6).count(),
        }

        # ---------- 分页查询 ----------
        total_count = Dingdan.objects.filter(q_conditions).count()

        orders_qs = Dingdan.objects.filter(q_conditions).select_related(
            'shangjia_kuozhan'  # 预加载商家扩展表
        ).only(
            'dingdan_id', 'jieshao', 'zhuangtai', 'leixing_id', 'fadan_pingtai',
            'jine', 'tupian', 'create_time', 'nicheng', 'jiedan_dashou_id',
            'shangjia_kuozhan__shangjia_id'  # 商家ID
        ).order_by('-create_time')[(page-1)*page_size : page*page_size]

        # ---------- 获取商家昵称（如果有） ----------
        # 假设商家昵称在 UserShangjia 扩展表中，通过 shangjia_id 关联 UserMain，再关联 UserShangjia
        # 此处简化，实际可根据需要查询
        shangjia_ids = [o.shangjia_kuozhan.shangjia_id for o in orders_qs if hasattr(o, 'shangjia_kuozhan') and o.shangjia_kuozhan.shangjia_id]
        nickname_map = {}
        if shangjia_ids:
            users = UserMain.objects.filter(yonghuid__in=shangjia_ids).select_related('shop_profile').only(
                'yonghuid', 'shop_profile__nicheng'
            )
            for user in users:
                nickname_map[user.yonghuid] = user.shop_profile.nicheng or '' if hasattr(user, 'shop_profile') else ''

        result_list = []
        for order in orders_qs:
            ext = getattr(order, 'shangjia_kuozhan', None)
            shangjia_id = ext.shangjia_id if ext else ''
            # 游戏昵称从订单主表的 nicheng 取，或从老板昵称取（商家订单可能没有老板昵称，保持简单）
            youxi_nicheng = order.nicheng or ''
            result_list.append({
                'dingdan_id': order.dingdan_id or '',
                'jieshao': order.jieshao or '',
                'zhuangtai': order.zhuangtai,
                'leixing': order.leixing_id,
                'fadanpingtai': order.fadan_pingtai,
                'jiage': float(order.jine) if order.jine else 0.00,
                'tupian_url': order.tupian or '',
                'fadanshijian': order.create_time.strftime('%Y-%m-%d %H:%M:%S') if order.create_time else '',
                'youxi_nicheng': youxi_nicheng
            })

        response_data = {
            'stats': {
                'totalOrders': stats['total_orders'] or 0,
                'completedOrders': stats['completed_orders'] or 0,
                'refundOrders': stats['refund_orders'] or 0,
                'pendingOrders': stats['pending_orders'] or 0
            },
            'statusCounts': status_counts,
            'list': result_list,
            'total': total_count,
            'page': page,
            'pageSize': page_size
        }

        logger.info(f"商家订单接口总耗时: {time.time()-start_total:.3f}s")
        return Response({'code': 0, 'data': response_data})'''


from rest_framework.views import APIView

from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser
from django.db.models import Q, Count
from django.core.paginator import Paginator

class KefuGetOrderListView(APIView):
    """
    客服获取平台订单列表接口（发单平台=1，非跨平台）
    需要权限：002ab（平台订单管理）
    请求参数：
        username: 客服账号（用于权限校验）
        page: 页码
        pageSize: 每页条数
        dingdan_id: 订单ID（精确搜索）
        laoban_id: 老板ID（搜索平台扩展表中的老板）
        dashou_id: 打手ID（搜索主表中的接单打手）
        leixing: 商品类型ID
        zhuangtai: 状态（多个用逗号分隔，如 "1,7"）
        date: 日期（YYYY-MM-DD），筛选订单创建时间
        nicheng: 游戏昵称（订单主表的 nicheng 字段）
        jieshao: 订单介绍（订单主表的 jieshao 字段）
        clkf: 处理客服（订单主表的 clkf 字段）
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        start_total = time.time()

        # 1. 获取前端参数
        username = request.data.get('phone', '').strip()
        if not username:
            return Response({'code': 400, 'msg': '缺少username'})

        # 2. 公共权限校验
        kefu, permissions = verify_kefu_permission(request, username)
        if kefu is None:
            return permissions

        # 3. 检查平台订单管理权限（002ab）
        if '002ab' not in permissions:
            return Response({'code': 403, 'msg': '您无权查看平台订单列表'})

        # 4. 获取分页和筛选参数
        page = int(request.data.get('page', 1))
        page_size = int(request.data.get('pageSize', 20))

        dingdan_id = request.data.get('dingdan_id', '').strip()
        laoban_id = request.data.get('laoban_id', '').strip()
        dashou_id = request.data.get('dashou_id', '').strip()
        leixing = request.data.get('leixing')
        zhuangtai = request.data.get('zhuangtai', '')
        date = request.data.get('date', '').strip()
        # 新增筛选条件
        nicheng = request.data.get('nicheng', '').strip()
        jieshao = request.data.get('jieshao', '').strip()
        clkf = request.data.get('clkf', '').strip()

        # ---------- 查询条件 ----------
        # 基础条件：平台发单 + 非跨平台
        base_q = Q(fadan_pingtai=1) & Q(is_cross=0)

        if dingdan_id:
            q_conditions = base_q & Q(dingdan_id=dingdan_id)
        else:
            q_conditions = base_q
            if leixing is not None:
                try:
                    leixing_int = int(leixing)
                    q_conditions &= Q(leixing_id=leixing_int)
                except (ValueError, TypeError):
                    pass
            if zhuangtai and zhuangtai != 'all':
                try:
                    status_list = [int(s.strip()) for s in zhuangtai.split(',') if s.strip()]
                    if status_list:
                        q_conditions &= Q(zhuangtai__in=status_list)
                except (ValueError, TypeError):
                    pass
            if dashou_id:
                q_conditions &= Q(jiedan_dashou_id=dashou_id)
            if laoban_id:
                q_conditions &= Q(pingtai_kuozhan__laoban_id=laoban_id)
            if date:
                q_conditions &= Q(create_time__date=date)
            # 新增筛选条件
            if nicheng:
                q_conditions &= Q(nicheng__icontains=nicheng)
            if jieshao:
                q_conditions &= Q(jieshao__icontains=jieshao)
            if clkf:
                q_conditions &= Q(clkf__icontains=clkf)

        # ---------- 统计（仅按发单平台，非跨平台） ----------
        stats = Dingdan.objects.filter(fadan_pingtai=1, is_cross=0).aggregate(
            total_orders=Count('id'),
            completed_orders=Count('id', filter=Q(zhuangtai=3)),
            refund_orders=Count('id', filter=Q(zhuangtai=5)),
            pending_orders=Count('id', filter=Q(zhuangtai__in=[4,8]))
        )

        # ---------- 状态计数（所有状态都返回，非跨平台） ----------
        status_counts = {
            'all': Dingdan.objects.filter(fadan_pingtai=1, is_cross=0).count(),
            '1,7': Dingdan.objects.filter(fadan_pingtai=1, is_cross=0, zhuangtai__in=[1,7]).count(),
            '2': Dingdan.objects.filter(fadan_pingtai=1, is_cross=0, zhuangtai=2).count(),
            '8': Dingdan.objects.filter(fadan_pingtai=1, is_cross=0, zhuangtai=8).count(),
            '3': Dingdan.objects.filter(fadan_pingtai=1, is_cross=0, zhuangtai=3).count(),
            '4': Dingdan.objects.filter(fadan_pingtai=1, is_cross=0, zhuangtai=4).count(),
            '5': Dingdan.objects.filter(fadan_pingtai=1, is_cross=0, zhuangtai=5).count(),
            '6': Dingdan.objects.filter(fadan_pingtai=1, is_cross=0, zhuangtai=6).count(),
        }

        # ---------- 分页查询 ----------
        total_count = Dingdan.objects.filter(q_conditions).count()

        orders_qs = Dingdan.objects.filter(q_conditions).select_related(
            'pingtai_kuozhan'
        ).only(
            'dingdan_id', 'jieshao', 'zhuangtai', 'leixing_id', 'fadan_pingtai',
            'jine', 'tupian', 'create_time', 'nicheng', 'jiedan_dashou_id',
            'pingtai_kuozhan__laoban_id'
        ).order_by('-create_time')[(page-1)*page_size : page*page_size]

        # ---------- 获取老板昵称 ----------
        laoban_ids = [o.pingtai_kuozhan.laoban_id for o in orders_qs if hasattr(o, 'pingtai_kuozhan') and o.pingtai_kuozhan.laoban_id]
        nickname_map = {}
        if laoban_ids:
            users = UserMain.objects.filter(yonghuid__in=laoban_ids).select_related('boss_profile').only(
                'yonghuid', 'boss_profile__nickname'
            )
            for user in users:
                nickname_map[user.yonghuid] = user.boss_profile.nickname or '' if hasattr(user, 'boss_profile') else ''

        result_list = []
        for order in orders_qs:
            ext = getattr(order, 'pingtai_kuozhan', None)
            laoban_id = ext.laoban_id if ext else ''
            youxi_nicheng = nickname_map.get(laoban_id, order.nicheng or '')
            result_list.append({
                'dingdan_id': order.dingdan_id or '',
                'jieshao': order.jieshao or '',
                'zhuangtai': order.zhuangtai,
                'leixing': order.leixing_id,
                'fadanpingtai': order.fadan_pingtai,
                'jiage': float(order.jine) if order.jine else 0.00,
                'tupian_url': order.tupian or '',
                'fadanshijian': order.create_time.strftime('%Y-%m-%d %H:%M:%S') if order.create_time else '',
                'youxi_nicheng': youxi_nicheng
            })

        response_data = {
            'stats': {
                'totalOrders': stats['total_orders'] or 0,
                'completedOrders': stats['completed_orders'] or 0,
                'refundOrders': stats['refund_orders'] or 0,
                'pendingOrders': stats['pending_orders'] or 0
            },
            'statusCounts': status_counts,
            'list': result_list,
            'total': total_count,
            'page': page,
            'pageSize': page_size
        }

        logger.info(f"平台订单接口总耗时: {time.time()-start_total:.3f}s")
        return Response({'code': 0, 'data': response_data})

class KefuGetShangjiaOrderListView(APIView):
    """
    客服获取商家订单列表接口（发单平台=2，非跨平台）
    需要权限：002ac（商家订单管理）—— 如不区分可使用 002ab
    请求参数：
        username: 客服账号（用于权限校验）
        page: 页码
        pageSize: 每页条数
        dingdan_id: 订单ID（精确搜索）
        shangjia_id: 商家ID（搜索商家扩展表中的商家ID）
        dashou_id: 打手ID（搜索主表中的接单打手）
        leixing: 商品类型ID
        zhuangtai: 状态（多个用逗号分隔，如 "1,7"）
        date: 日期（YYYY-MM-DD），筛选订单创建时间
        nicheng: 游戏昵称（订单主表的 nicheng 字段）
        jieshao: 订单介绍（订单主表的 jieshao 字段）
        clkf: 处理客服（订单主表的 clkf 字段）
        shangjia_nicheng: 商家昵称（商家扩展表中的昵称）
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        start_total = time.time()

        # 1. 获取前端参数
        username = request.data.get('phone', '').strip()
        if not username:
            return Response({'code': 400, 'msg': '缺少username'})

        # 2. 公共权限校验
        kefu, permissions = verify_kefu_permission(request, username)
        if kefu is None:
            return permissions

        # 3. 检查商家订单管理权限（使用 002ac，如果没有可改用 002ab）
        if '002ac' not in permissions:
            return Response({'code': 403, 'msg': '您无权查看商家订单列表'})

        # 4. 获取分页和筛选参数
        page = int(request.data.get('page', 1))
        page_size = int(request.data.get('pageSize', 20))

        dingdan_id = request.data.get('dingdan_id', '').strip()
        shangjia_id = request.data.get('shangjia_id', '').strip()
        dashou_id = request.data.get('dashou_id', '').strip()
        leixing = request.data.get('leixing')
        zhuangtai = request.data.get('zhuangtai', '')
        date = request.data.get('date', '').strip()
        # 新增筛选条件
        nicheng = request.data.get('nicheng', '').strip()
        jieshao = request.data.get('jieshao', '').strip()
        clkf = request.data.get('clkf', '').strip()
        shangjia_nicheng = request.data.get('shangjia_nicheng', '').strip()

        # ---------- 查询条件 ----------
        # 基础条件：商家发单 + 非跨平台
        base_q = Q(fadan_pingtai=2) & Q(is_cross=0)

        if dingdan_id:
            q_conditions = base_q & Q(dingdan_id=dingdan_id)
        else:
            q_conditions = base_q
            if leixing is not None:
                try:
                    leixing_int = int(leixing)
                    q_conditions &= Q(leixing_id=leixing_int)
                except (ValueError, TypeError):
                    pass
            if zhuangtai and zhuangtai != 'all':
                try:
                    status_list = [int(s.strip()) for s in zhuangtai.split(',') if s.strip()]
                    if status_list:
                        q_conditions &= Q(zhuangtai__in=status_list)
                except (ValueError, TypeError):
                    pass
            if dashou_id:
                q_conditions &= Q(jiedan_dashou_id=dashou_id)
            if shangjia_id:
                q_conditions &= Q(shangjia_kuozhan__shangjia_id=shangjia_id)
            if date:
                q_conditions &= Q(create_time__date=date)
            if nicheng:
                q_conditions &= Q(nicheng__icontains=nicheng)
            if jieshao:
                q_conditions &= Q(jieshao__icontains=jieshao)
            if clkf:
                q_conditions &= Q(clkf__icontains=clkf)
            if shangjia_nicheng:
                # 通过商家扩展表关联 UserShangjia 的昵称
                q_conditions &= Q(shangjia_kuozhan__shangjia_id__in=UserMain.objects.filter(
                    shop_profile__nicheng__icontains=shangjia_nicheng
                ).values_list('yonghuid', flat=True))

        # ---------- 统计（仅按发单平台，非跨平台） ----------
        stats = Dingdan.objects.filter(fadan_pingtai=2, is_cross=0).aggregate(
            total_orders=Count('id'),
            completed_orders=Count('id', filter=Q(zhuangtai=3)),
            refund_orders=Count('id', filter=Q(zhuangtai=5)),
            pending_orders=Count('id', filter=Q(zhuangtai__in=[4,8]))
        )

        # ---------- 状态计数（所有状态都返回，非跨平台） ----------
        status_counts = {
            'all': Dingdan.objects.filter(fadan_pingtai=2, is_cross=0).count(),
            '1,7': Dingdan.objects.filter(fadan_pingtai=2, is_cross=0, zhuangtai__in=[1,7]).count(),
            '2': Dingdan.objects.filter(fadan_pingtai=2, is_cross=0, zhuangtai=2).count(),
            '8': Dingdan.objects.filter(fadan_pingtai=2, is_cross=0, zhuangtai=8).count(),
            '3': Dingdan.objects.filter(fadan_pingtai=2, is_cross=0, zhuangtai=3).count(),
            '4': Dingdan.objects.filter(fadan_pingtai=2, is_cross=0, zhuangtai=4).count(),
            '5': Dingdan.objects.filter(fadan_pingtai=2, is_cross=0, zhuangtai=5).count(),
            '6': Dingdan.objects.filter(fadan_pingtai=2, is_cross=0, zhuangtai=6).count(),
        }

        # ---------- 分页查询 ----------
        total_count = Dingdan.objects.filter(q_conditions).count()

        orders_qs = Dingdan.objects.filter(q_conditions).select_related(
            'shangjia_kuozhan'
        ).only(
            'dingdan_id', 'jieshao', 'zhuangtai', 'leixing_id', 'fadan_pingtai',
            'jine', 'tupian', 'create_time', 'nicheng', 'jiedan_dashou_id',
            'shangjia_kuozhan__shangjia_id'
        ).order_by('-create_time')[(page-1)*page_size : page*page_size]

        # ---------- 获取商家昵称 ----------
        shangjia_ids = [o.shangjia_kuozhan.shangjia_id for o in orders_qs if hasattr(o, 'shangjia_kuozhan') and o.shangjia_kuozhan.shangjia_id]
        nickname_map = {}
        if shangjia_ids:
            users = UserMain.objects.filter(yonghuid__in=shangjia_ids).select_related('shop_profile').only(
                'yonghuid', 'shop_profile__nicheng'
            )
            for user in users:
                nickname_map[user.yonghuid] = user.shop_profile.nicheng or '' if hasattr(user, 'shop_profile') else ''

        result_list = []
        for order in orders_qs:
            ext = getattr(order, 'shangjia_kuozhan', None)
            shangjia_id = ext.shangjia_id if ext else ''
            youxi_nicheng = order.nicheng or ''  # 商家订单的玩家昵称
            result_list.append({
                'dingdan_id': order.dingdan_id or '',
                'jieshao': order.jieshao or '',
                'zhuangtai': order.zhuangtai,
                'leixing': order.leixing_id,
                'fadanpingtai': order.fadan_pingtai,
                'jiage': float(order.jine) if order.jine else 0.00,
                'tupian_url': order.tupian or '',
                'fadanshijian': order.create_time.strftime('%Y-%m-%d %H:%M:%S') if order.create_time else '',
                'youxi_nicheng': youxi_nicheng
            })

        response_data = {
            'stats': {
                'totalOrders': stats['total_orders'] or 0,
                'completedOrders': stats['completed_orders'] or 0,
                'refundOrders': stats['refund_orders'] or 0,
                'pendingOrders': stats['pending_orders'] or 0
            },
            'statusCounts': status_counts,
            'list': result_list,
            'total': total_count,
            'page': page,
            'pageSize': page_size
        }

        logger.info(f"商家订单接口总耗时: {time.time()-start_total:.3f}s")
        return Response({'code': 0, 'data': response_data})


import time
import logging

from rest_framework.views import APIView

from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser


from dingdan.models import Dingdan, DingdanPingtai, DingdanShangjia, Dashoutupian, Tuikuanjilu

logger = logging.getLogger(__name__)

class KefuGetOrderDetailView(APIView):
    """
    客服获取订单详情接口
    请求：POST /yonghu/kefuhqddxq
    参数：{"phone": "客服手机号", "dingdan_id": "订单ID"}
    认证：JWT
    返回：code=0 + 订单详情数据
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        start_time = time.time()

        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()

        if not phone or not dingdan_id:
            return Response(
                {'code': 401, 'msg': '认证失败'},
                status=status.HTTP_401_UNAUTHORIZED
            )

        # 2. 身份验证
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            logger.warning(f"手机号不匹配: {phone}")
            return Response(
                {'code': 401, 'msg': '认证失败'},
                status=status.HTTP_401_UNAUTHORIZED
            )

        if current_user.user_type != 'kefu':
            logger.warning(f"用户类型非客服: {current_user.yonghuid}")
            return Response(
                {'code': 401, 'msg': '认证失败'},
                status=status.HTTP_401_UNAUTHORIZED
            )

        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            logger.warning(f"客服扩展表不存在: {current_user.yonghuid}")
            return Response(
                {'code': 401, 'msg': '认证失败'},
                status=status.HTTP_401_UNAUTHORIZED
            )

        if kefu.zhuangtai != 1:
            logger.warning(f"客服账号已禁用: {current_user.yonghuid}")
            return Response(
                {'code': 401, 'msg': '认证失败'},
                status=status.HTTP_401_UNAUTHORIZED
            )

        # 3. 查询订单
        try:
            # 使用 select_related 预加载扩展表，避免后续 N+1 查询
            dingdan_obj = Dingdan.objects.select_related(
                'pingtai_kuozhan',
                'shangjia_kuozhan'
            ).only(
                'dingdan_id', 'zhuangtai', 'fadan_pingtai', 'jine', 'dashou_fencheng',
                'jiedan_dashou_id', 'dashou_liuyan', 'zhiding_id', 'shangpin_id',
                'leixing_id', 'tupian', 'jieshao', 'beizhu', 'tkly', 'nicheng',
                'clkf', 'create_time', 'update_time'
            ).get(dingdan_id=dingdan_id)

        except Dingdan.DoesNotExist:
            logger.warning(f"订单不存在: {dingdan_id}")
            return Response(
                {'code': 404, 'msg': '订单不存在', 'data': None},
                status=status.HTTP_404_NOT_FOUND
            )

        # 4. 构建基础响应数据（主表字段）
        response_data = {
            'dingdan_id': dingdan_obj.dingdan_id or '',
            'zhuangtai': dingdan_obj.zhuangtai or 0,
            'fadanpingtai': dingdan_obj.fadan_pingtai or 0,
            'jiage': float(dingdan_obj.jine) if dingdan_obj.jine else 0.00,
            'dashou_fencheng': float(dingdan_obj.dashou_fencheng) if dingdan_obj.dashou_fencheng else 0.00,
            'jiedan_dashou_id': dingdan_obj.jiedan_dashou_id or '',
            'dashou_liuyan': dingdan_obj.dashou_liuyan or '',
            'zhiding_id': dingdan_obj.zhiding_id or '',
            'shangpin_id': dingdan_obj.shangpin_id or '',
            'leixing': dingdan_obj.leixing_id or 0,
            'tupian_url': dingdan_obj.tupian or '',
            'jieshao': dingdan_obj.jieshao or '',
            'beizhu': dingdan_obj.beizhu or '',
            'tkly': dingdan_obj.tkly or '',
            'nicheng': dingdan_obj.nicheng or '',
            'clkf': dingdan_obj.clkf or '',
            'chuangjianshijian': dingdan_obj.create_time.strftime('%Y-%m-%d %H:%M:%S') if dingdan_obj.create_time else '',
            'genggaishijian': dingdan_obj.update_time.strftime('%Y-%m-%d %H:%M:%S') if dingdan_obj.update_time else '',
        }

        # 5. 根据发单平台添加扩展表数据
        fadan_pingtai = dingdan_obj.fadan_pingtai

        if fadan_pingtai == 1:
            # 平台订单扩展
            if hasattr(dingdan_obj, 'pingtai_kuozhan') and dingdan_obj.pingtai_kuozhan:
                pingtai = dingdan_obj.pingtai_kuozhan
                response_data['pingtai_kuozhan'] = {
                    'laoban_id': pingtai.laoban_id or '',
                    'laoban_pingjia': pingtai.laoban_pingjia or '',
                }
            else:
                response_data['pingtai_kuozhan'] = {
                    'laoban_id': '',
                    'laoban_pingjia': '',
                }

        elif fadan_pingtai == 2:
            # 商家订单扩展
            if hasattr(dingdan_obj, 'shangjia_kuozhan') and dingdan_obj.shangjia_kuozhan:
                shangjia = dingdan_obj.shangjia_kuozhan
                response_data['shangjia_kuozhan'] = {
                    'shangjia_id': shangjia.shangjia_id or '',
                    'sjnicheng': shangjia.sjnicheng or '',
                    'shangjia_pingjia': shangjia.shangjia_pingjia or '',
                    'cfliyou': shangjia.cfliyou or '',
                    'sqzhuangtai': shangjia.sqzhuangtai if shangjia.sqzhuangtai is not None else 0,
                    'bhliyou': shangjia.bhliyou or '',
                }
            else:
                response_data['shangjia_kuozhan'] = {
                    'shangjia_id': '',
                    'sjnicheng': '',
                    'shangjia_pingjia': '',
                    'cfliyou': '',
                    'sqzhuangtai': 0,
                    'bhliyou': '',
                }

        # 6. 查询打手提交的图片
        try:
            dashou_images = Dashoutupian.objects.filter(
                dingdan_id=dingdan_id
            ).values_list('tupian', flat=True)
            response_data['dashou_images'] = [img for img in dashou_images if img]
        except Exception as e:
            logger.warning(f"查询打手图片失败: {str(e)}")
            response_data['dashou_images'] = []

        # 7. 查询退款理由（从退款记录表取最新一条）
        try:
            tuikuan_record = Tuikuanjilu.objects.filter(
                dingdan_id=dingdan_id
            ).order_by('-create_time').first()
            if tuikuan_record and tuikuan_record.liyou:
                response_data['tuikuan_liyou'] = tuikuan_record.liyou
            else:
                response_data['tuikuan_liyou'] = ''
        except Exception as e:
            logger.warning(f"查询退款记录失败: {str(e)}")
            response_data['tuikuan_liyou'] = ''

        logger.info(f"订单详情接口耗时: {time.time()-start_time:.3f}s")
        return Response({'code': 0, 'data': response_data})




import logging
from django.db import transaction
from django.core.exceptions import ObjectDoesNotExist
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser


from shangpin.models import Huiyuangoumai  # 假设会员购买模型存在

logger = logging.getLogger(__name__)

class KefuChangeDashouView(APIView):
    """
    客服更换打手接口
    请求：POST /yonghu/kefughds
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID",
        "new_dashou_id": "新打手ID"
    }
    认证：JWT
    返回：code=0 成功
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()
        new_dashou_id = request.data.get('new_dashou_id', '').strip()

        if not phone or not dingdan_id or not new_dashou_id:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            logger.warning(f"手机号不匹配: {phone}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if current_user.user_type != 'kefu':
            logger.warning(f"用户类型非客服: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            logger.warning(f"客服扩展表不存在: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if kefu.zhuangtai != 1:
            logger.warning(f"客服账号已禁用: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询订单
        try:
            order = Dingdan.objects.get(dingdan_id=dingdan_id)
        except Dingdan.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)

        # 4. 验证订单状态是否允许更换打手（进行中2 或 结算中8）
        if order.zhuangtai not in [2, 8]:
            return Response({'code': 400, 'msg': '订单状态不允许更换打手'}, status=status.HTTP_400_BAD_REQUEST)

        # 5. 查询新打手
        try:
            new_dashou_user = UserMain.objects.get(yonghuid=new_dashou_id)
        except UserMain.DoesNotExist:
            return Response({'code': 404, 'msg': '打手不存在'}, status=status.HTTP_404_NOT_FOUND)

        # 6. 验证打手扩展表
        try:
            new_dashou_profile = new_dashou_user.dashou_profile
        except ObjectDoesNotExist:
            return Response({'code': 404, 'msg': '打手信息不完整'}, status=status.HTTP_404_NOT_FOUND)

        # 7. 验证打手状态（打手状态和账号状态必须为1）
        if new_dashou_profile.zhuangtai != 1 or new_dashou_profile.zhanghaozhuangtai != 1:
            return Response({'code': 400, 'msg': '打手状态不允许接单'}, status=status.HTTP_400_BAD_REQUEST)
        # 8. 验证打手积分是否足够（至少5分）
        if new_dashou_profile.jifen < 5:
            return Response({'code': 400, 'msg': '打手积分不足，无法接单'}, status=status.HTTP_400_BAD_REQUEST)

        # 8. 根据订单的抢单要求类型进行额外验证
        yaoqiuleixing = order.yaoqiuleixing

        if yaoqiuleixing == 1:  # 会员抢单
            huiyuan_id = order.huiyuan_id
            if not huiyuan_id:
                return Response({'code': 400, 'msg': '订单会员ID为空'}, status=status.HTTP_400_BAD_REQUEST)

            try:
                # 查询打手的会员购买记录
                huiyuan_goumai = Huiyuangoumai.objects.get(
                    huiyuan_id=huiyuan_id,
                    yonghu_id=new_dashou_id  # 假设 yonghu_id 字段存储用户ID
                )
            except Huiyuangoumai.DoesNotExist:
                return Response({'code': 400, 'msg': '打手未购买该订单要求的会员'}, status=status.HTTP_400_BAD_REQUEST)

            # 检查会员是否过期（调用模型方法）
            is_expired = huiyuan_goumai.jiance_shifou_daoqi()
            if is_expired or huiyuan_goumai.huiyuan_zhuangtai != 1:
                return Response({'code': 400, 'msg': '打手的会员已过期'}, status=status.HTTP_400_BAD_REQUEST)

        elif yaoqiuleixing == 2:  # 押金抢单
            order_yajin = order.yongjin  # 假设订单的 yongjin 字段存储押金要求
            if order_yajin is None:
                return Response({'code': 400, 'msg': '订单押金为空'}, status=status.HTTP_400_BAD_REQUEST)

            if new_dashou_profile.yajin < order_yajin:
                return Response({'code': 400, 'msg': '打手押金不足'}, status=status.HTTP_400_BAD_REQUEST)
        else:
            return Response({'code': 400, 'msg': '订单抢单要求类型错误'}, status=status.HTTP_400_BAD_REQUEST)

        # 9. 所有验证通过，开始更换打手（使用事务）
        with transaction.atomic():
            # 9.1 更新新打手扩展表
            new_dashou_profile.zhuangtai = 0  # 设为接单中
            new_dashou_profile.jiedanzongliang += 1
            new_dashou_profile.jinrijiedan += 1
            new_dashou_profile.jinyuejiedan += 1
            new_dashou_profile.save()

            # 9.2 处理原打手（如果存在）
            old_dashou_id = order.jiedan_dashou_id
            if old_dashou_id:
                try:
                    old_dashou_user = UserMain.objects.get(yonghuid=old_dashou_id)
                    old_dashou_profile = old_dashou_user.dashou_profile
                    old_dashou_profile.zhuangtai = 1  # 恢复空闲
                    old_dashou_profile.tuikuanliang += 1  # 原打手退款总量+1（业务逻辑）
                    old_dashou_profile.save()
                    logger.info(f"原打手 {old_dashou_id} 状态已更新")
                except (UserMain.DoesNotExist, ObjectDoesNotExist):
                    logger.warning(f"原打手 {old_dashou_id} 不存在或信息不完整，跳过更新")
                except Exception as e:
                    logger.error(f"更新原打手时异常: {str(e)}", exc_info=True)

            # 9.3 更新订单
            order.jiedan_dashou_id = new_dashou_id
            order.zhuangtai = 2  # 进行中
            order.clkf = current_user.yonghuid  # 记录处理客服ID
            order.save()

        return Response({'code': 0, 'msg': '更换打手成功'})





class KefuRecoverOrderView(APIView):
    """
    客服恢复订单接口（仅状态9可恢复）
    请求：POST /yonghu/kefuhf
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID"
    }
    认证：JWT
    返回：code=0 成功
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()

        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if current_user.user_type != 'kefu':
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if kefu.zhuangtai != 1:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询订单
        try:
            order = Dingdan.objects.get(dingdan_id=dingdan_id)
        except Dingdan.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)

        # 4. 验证订单状态是否为9（未付款）
        if order.zhuangtai != 9:
            return Response({'code': 400, 'msg': '订单状态不允许恢复'}, status=status.HTTP_400_BAD_REQUEST)

        # 5. 根据是否有指定ID决定新状态
        if order.zhiding_id:
            new_status = 7  # 指定中
        else:
            new_status = 1  # 下单中

        # 6. 更新订单
        order.zhuangtai = new_status
        order.clkf = current_user.yonghuid
        order.save()

        return Response({'code': 0, 'msg': '恢复成功', 'data': {'new_status': new_status}})







# dingdan/views.py
import logging
import random
import hashlib
import requests
import xmltodict

from rest_framework.views import APIView

from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser

from dingdan.models import Dingdan, DingdanPingtai # 注意：Tuikuanjilu 模型未在本次提供，但假设存在

logger = logging.getLogger(__name__)


'''class KefuPlatformRefundView(APIView):
    """
    客服平台订单退款接口（调用微信支付）
    请求：POST /yonghu/kefupttk
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID",
        "tuikuan_liyou": "退款理由（可选）"
    }
    认证：JWT
    返回：code=0 成功，code=其他 失败
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()
        tuikuan_liyou = request.data.get('tuikuan_liyou', '').strip()

        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            logger.warning(f"手机号不匹配: {phone}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if current_user.user_type != 'kefu':
            logger.warning(f"用户类型非客服: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            logger.warning(f"客服扩展表不存在: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if kefu.zhuangtai != 1:
            logger.warning(f"客服账号已禁用: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询订单并加锁
        try:
            with transaction.atomic():
                order = Dingdan.objects.select_related('pingtai_kuozhan').select_for_update().get(dingdan_id=dingdan_id)

                # 4. 验证平台订单
                if order.fadan_pingtai != 1:
                    return Response({'code': 400, 'msg': '该订单不是平台订单'}, status=status.HTTP_400_BAD_REQUEST)

                # 5. 验证状态允许退款（根据模型，状态值：1下单中，2进行中，3已完成，4退款审核，5已退款，6退款失败，7指定中，8结算中）
                allowed_statuses = [1, 2, 4, 7, 8]  # 允许退款的已支付或处理中状态
                if order.zhuangtai not in allowed_statuses:
                    return Response({'code': 400, 'msg': '订单状态不允许退款'}, status=status.HTTP_400_BAD_REQUEST)

                # 6. 获取微信交易号（如果存在）
                wechat_transaction_id = getattr(order, 'wechat_transaction_id', None)

                # 7. 调用微信退款接口
                refund_result = self.call_wechat_refund(
                    dingdan_id=order.dingdan_id,
                    jine=order.jine,
                    transaction_id=wechat_transaction_id
                )

                if refund_result['code'] != 0:
                    # 微信退款失败，直接返回错误，数据库不更新
                    logger.error(f"微信退款失败，订单 {dingdan_id}，原因：{refund_result['msg']}")
                    return Response({'code': 400, 'msg': refund_result['msg']}, status=status.HTTP_400_BAD_REQUEST)

                # 8. 更新订单状态为5（已退款）
                order.zhuangtai = 5
                order.clkf = current_user.phone  # 记录处理客服手机号
                if tuikuan_liyou:
                    order.tkly = tuikuan_liyou
                order.save()

                # 9. 更新打手数据
                jiedan_dashou_id = order.jiedan_dashou_id
                if jiedan_dashou_id:
                    try:
                        dashou_user = UserMain.objects.get(yonghuid=jiedan_dashou_id)
                        dashou_profile = dashou_user.dashou_profile
                        dashou_profile.tuikuanliang += 1
                        dashou_profile.zhuangtai = 1  # 打手状态设为空闲
                        dashou_profile.save()
                        logger.info(f"平台退款：打手 {jiedan_dashou_id} 退款订单+1")
                    except (UserMain.DoesNotExist, ObjectDoesNotExist):
                        logger.warning(f"平台退款：打手 {jiedan_dashou_id} 不存在或扩展表缺失，跳过更新")

                # 10. 更新退款记录表（假设存在 Tuikuanjilu 模型，字段需根据实际调整）
                try:
                    from dingdan.models import Tuikuanjilu  # 确保模型已导入
                    refund_record, created = Tuikuanjilu.objects.get_or_create(
                        dingdan_id=dingdan_id,
                        defaults={
                            'dashouid': jiedan_dashou_id or '',
                            'qingqiuid': '',
                            'chuliid': phone,
                            'liyou': tuikuan_liyou or '客服退款',
                            'sqzhuangtai': 1,  # 成功
                            'jine': order.jine,
                            'dashou_fencheng': order.dashou_fencheng or 0,
                            'jieshao': order.jieshao or '',
                            'beizhu': '客服平台退款',
                            'nicheng': order.nicheng or '',
                        }
                    )
                    if not created:
                        refund_record.sqzhuangtai = 1
                        refund_record.chuliid = phone
                        if tuikuan_liyou:
                            refund_record.liyou = tuikuan_liyou
                        refund_record.save()
                except Exception as e:
                    logger.error(f"平台退款更新退款记录异常: {str(e)}", exc_info=True)

                # ========== 新增：商品和店铺每日统计 ==========
                try:
                    # 商品每日统计（只要有商品ID就执行）
                    if order.shangpin_id:
                        # 从扩展表获取已计算好的收益值（下单时已存储）
                        pingtai_shouyi = Decimal('0.00')
                        dianpu_shouyi = Decimal('0.00')
                        if hasattr(order, 'pingtai_kuozhan'):
                            pingtai_shouyi = order.pingtai_kuozhan.pingtai_shouyi or Decimal('0.00')
                            dianpu_shouyi = order.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')

                        update_shangpin_daily_stat(
                            shangpin_id=order.shangpin_id,
                            caozuo_leixing=3,  # 3 = 退款
                            dingdan_jiage=order.jine,
                            pingtai_shouyi=pingtai_shouyi,
                            dianpu_zongshouyi=dianpu_shouyi
                        )
                        logger.info(f"商品统计更新完成，商品ID: {order.shangpin_id}")

                    # 店铺每日统计（仅当存在店铺ID时执行）
                    dianpu_id = None
                    if hasattr(order, 'pingtai_kuozhan'):
                        dianpu_id = order.pingtai_kuozhan.dianpu_id
                    if dianpu_id:
                        dianpu_shouyi = order.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')
                        update_dianpu_daily_stat(
                            dianpu_id=dianpu_id,
                            caozuo_leixing=3,  # 3 = 退款
                            dingdan_jiage=order.jine,
                            dianpu_shouyi=dianpu_shouyi
                        )
                        logger.info(f"店铺统计更新完成，店铺ID: {dianpu_id}")
                except Exception as e:
                    logger.error(f"商品/店铺统计更新失败: {e}")
                    logger.error(traceback.format_exc())
                    # 统计失败不影响主流程
                # =============================================

                # 11. 更新客服统计数据
                kefu.jinrichuli += 1
                kefu.jinyuechuli += 1
                kefu.zongchuli += 1
                kefu.save()

                #12.更新退款统计
                from dingdan.utils import update_daily_payout
                update_daily_payout(order.jine)

                # 🔥 新增：调用打手每日统计（成交）
                try:
                    update_dashou_daily_by_action(
                        yonghuid=order.jiedan_dashou_id,
                        amount=order.dashou_fencheng,
                        action=3  # 3 表示退款（退款）
                    )
                    logger.info(f"打手 {order.jiedan_dashou_id} 每日统计更新成功")
                except Exception as e:
                    logger.error(f"打手每日统计更新失败: {e}")
                    # 不影响主流程

            logger.info(f"平台退款成功，订单 {dingdan_id}，退款单号 {refund_result.get('refund_id')}")
            return Response({'code': 0, 'msg': '退款成功'})

        except Dingdan.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            logger.error(f"平台退款接口异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'msg': '服务器内部错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def call_wechat_refund(self, dingdan_id, jine, transaction_id=None):
        """
        调用微信支付退款接口
        :param dingdan_id: 商户订单号（我们的订单ID）
        :param jine: 退款金额
        :param transaction_id: 微信支付订单号（优先使用）
        :return: {'code': 0, 'msg': '成功', 'refund_id': 'xxx'} 或 {'code': 非0, 'msg': '错误信息'}
        """
        # 获取配置
        appid = getattr(settings, 'WEIXIN_APPID', '')
        mch_id = getattr(settings, 'WEIXIN_MCHID', '')
        key = getattr(settings, 'WEIXIN_SHANGHUMIYAO', '')
        cert_path = getattr(settings, 'WEIXIN_CERT_PATH', '')
        key_path = getattr(settings, 'WEIXIN_KEY_PATH', '')

        if not all([appid, mch_id, key, cert_path, key_path]):
            missing = [k for k, v in {'appid': appid, 'mch_id': mch_id, 'key': key, 'cert_path': cert_path, 'key_path': key_path}.items() if not v]
            logger.error(f"微信支付配置缺失: {missing}")
            return {'code': 500, 'msg': f'系统支付配置缺失: {missing}'}

        # 生成退款单号
        out_refund_no = self.generate_refund_no(dingdan_id)
        total_fee = int(float(jine) * 100)
        refund_fee = total_fee
        refund_desc = '客服退款'

        # 构造请求参数
        params = {
            'appid': appid,
            'mch_id': mch_id,
            'nonce_str': self.generate_nonce_str(),
            'out_refund_no': out_refund_no,
            'total_fee': total_fee,
            'refund_fee': refund_fee,
            'refund_desc': refund_desc,
        }
        if transaction_id:
            params['transaction_id'] = transaction_id
        else:
            params['out_trade_no'] = dingdan_id  # 使用订单ID作为商户订单号

        # 生成签名
        sorted_keys = sorted(params.keys())
        stringA = '&'.join([f"{k}={params[k]}" for k in sorted_keys])
        stringSignTemp = f"{stringA}&key={key}"
        sign = hashlib.md5(stringSignTemp.encode('utf-8')).hexdigest().upper()
        params['sign'] = sign

        xml_data = self.dict_to_xml(params)
        url = 'https://api.mch.weixin.qq.com/secapi/pay/refund'

        try:
            response = requests.post(
                url,
                data=xml_data,
                cert=(cert_path, key_path),
                timeout=10
            )
            result = xmltodict.parse(response.content)['xml']
            logger.info(f"微信退款响应: {result}")
        except Exception as e:
            logger.error(f"微信退款请求异常: {str(e)}", exc_info=True)
            return {'code': 500, 'msg': '微信退款请求异常'}

        if result.get('return_code') == 'SUCCESS' and result.get('result_code') == 'SUCCESS':
            return {'code': 0, 'msg': 'success', 'refund_id': out_refund_no}
        else:
            err_msg = result.get('err_code_des', result.get('return_msg', '未知错误'))
            logger.warning(f"微信退款失败: {err_msg}")
            return {'code': 400, 'msg': err_msg}

    def generate_nonce_str(self):
        import string
        return ''.join(random.choices(string.ascii_letters + string.digits, k=32))

    def generate_refund_no(self, dingdan_id):
        timestamp = str(int(time.time()))
        rand = ''.join(random.choices('0123456789', k=4))
        return f"{dingdan_id}REF{timestamp}{rand}"

    def dict_to_xml(self, data):
        xml = ['<xml>']
        for k, v in data.items():
            xml.append(f'<{k}>{v}</{k}>')
        xml.append('</xml>')
        return ''.join(xml)'''

from dingdan.utils import (
    update_daily_income,
    sync_order_to_partners,
    update_daily_payout,)




import hmac
class KefuPlatformRefundView(APIView):
    """
    虚拟支付退款接口（代币订单，使用 refund_order 接口）
    业务逻辑与原 KefuPlatformRefundView 完全一致
    微信 API：POST /xpay/refund_order
    文档：https://developers.weixin.qq.com/minigame/dev/api-backend/open-api/virtual-payment/refund_order.html
    """
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()
        tuikuan_liyou = request.data.get('tuikuan_liyou', '').strip()

        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证（与原逻辑完全一致）
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            logger.warning(f"手机号不匹配: {phone}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if current_user.user_type != 'kefu':
            logger.warning(f"用户类型非客服: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            logger.warning(f"客服扩展表不存在: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if kefu.zhuangtai != 1:
            logger.warning(f"客服账号已禁用: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询订单并加锁
        try:
            with transaction.atomic():
                order = Dingdan.objects.select_related('pingtai_kuozhan').select_for_update().get(dingdan_id=dingdan_id)

                # 4. 验证平台订单
                if order.fadan_pingtai != 1:
                    return Response({'code': 400, 'msg': '该订单不是平台订单'}, status=status.HTTP_400_BAD_REQUEST)

                # 5. 验证状态允许退款（沿用原有白名单）
                allowed_statuses = [1, 2, 4, 7, 8]
                if order.zhuangtai not in allowed_statuses:
                    return Response({'code': 400, 'msg': '订单状态不允许退款'}, status=status.HTTP_400_BAD_REQUEST)

                # 6. 获取退款所需关键信息
                jiedan_dashou_id = order.jiedan_dashou_id
                # 从订单扩展表获取老板 openid（退款API需要）
                laoban_openid = None
                laoban_id = order.pingtai_kuozhan.laoban_id if hasattr(order, 'pingtai_kuozhan') else None
                if laoban_id:
                    laoban_user = UserMain.objects.filter(yonghuid=laoban_id).first()
                    if laoban_user:
                        laoban_openid = getattr(laoban_user, 'openid', None)

                if not laoban_openid:
                    return Response({'code': 400, 'msg': '未找到用户openid，无法退款'}, status=status.HTTP_400_BAD_REQUEST)

                # 7. 调用虚拟支付退款接口（refund_order）
                refund_result = self.call_virtual_refund(
                    dingdan_id=order.dingdan_id,
                    jine=order.jine,
                    openid=laoban_openid,
                    wechat_transaction_id=getattr(order, 'wechat_transaction_id', None)
                )

                if refund_result['code'] != 0:
                    logger.error(f"虚拟支付退款失败，订单 {dingdan_id}，原因：{refund_result['msg']}")
                    return Response({'code': 400, 'msg': refund_result['msg']}, status=status.HTTP_400_BAD_REQUEST)

                # ========== 以下数据库操作与原逻辑完全一致（全部保留） ==========
                # 8. 更新订单状态为5（已退款）
                order.zhuangtai = 5
                order.clkf = current_user.phone
                if tuikuan_liyou:
                    order.tkly = tuikuan_liyou
                order.save()

                # 9. 更新打手数据
                if jiedan_dashou_id:
                    try:
                        dashou_user = UserMain.objects.get(yonghuid=jiedan_dashou_id)
                        dashou_profile = dashou_user.dashou_profile
                        dashou_profile.tuikuanliang += 1
                        dashou_profile.zhuangtai = 1
                        dashou_profile.save()
                        logger.info(f"平台退款：打手 {jiedan_dashou_id} 退款订单+1")
                    except (UserMain.DoesNotExist, ObjectDoesNotExist):
                        logger.warning(f"平台退款：打手 {jiedan_dashou_id} 不存在或扩展表缺失")

                # 10. 更新退款记录表
                try:
                    refund_record, created = Tuikuanjilu.objects.get_or_create(
                        dingdan_id=dingdan_id,
                        defaults={
                            'dashouid': jiedan_dashou_id or '',
                            'qingqiuid': '',
                            'chuliid': phone,
                            'liyou': tuikuan_liyou or '客服退款',
                            'sqzhuangtai': 1,
                            'jine': order.jine,
                            'dashou_fencheng': order.dashou_fencheng or 0,
                            'jieshao': order.jieshao or '',
                            'beizhu': '客服平台退款（虚拟支付）',
                            'nicheng': order.nicheng or '',
                        }
                    )
                    if not created:
                        refund_record.sqzhuangtai = 1
                        refund_record.chuliid = phone
                        if tuikuan_liyou:
                            refund_record.liyou = tuikuan_liyou
                        refund_record.save()
                except Exception as e:
                    logger.error(f"平台退款更新退款记录异常: {str(e)}", exc_info=True)

                # 11. 商品和店铺每日统计
                try:
                    if order.shangpin_id:
                        pingtai_shouyi = Decimal('0.00')
                        dianpu_shouyi = Decimal('0.00')
                        if hasattr(order, 'pingtai_kuozhan'):
                            pingtai_shouyi = order.pingtai_kuozhan.pingtai_shouyi or Decimal('0.00')
                            dianpu_shouyi = order.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')

                        update_shangpin_daily_stat(
                            shangpin_id=order.shangpin_id,
                            caozuo_leixing=3,
                            dingdan_jiage=order.jine,
                            pingtai_shouyi=pingtai_shouyi,
                            dianpu_zongshouyi=dianpu_shouyi
                        )
                        logger.info(f"商品统计更新完成，商品ID: {order.shangpin_id}")

                    dianpu_id = None
                    if hasattr(order, 'pingtai_kuozhan'):
                        dianpu_id = order.pingtai_kuozhan.dianpu_id
                    if dianpu_id:
                        dianpu_shouyi = order.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')
                        update_dianpu_daily_stat(
                            dianpu_id=dianpu_id,
                            caozuo_leixing=3,
                            dingdan_jiage=order.jine,
                            dianpu_shouyi=dianpu_shouyi
                        )
                        logger.info(f"店铺统计更新完成，店铺ID: {dianpu_id}")
                except Exception as e:
                    logger.error(f"商品/店铺统计更新失败: {e}")
                    logger.error(traceback.format_exc())

                # 12. 更新客服统计数据
                kefu.jinrichuli += 1
                kefu.jinyuechuli += 1
                kefu.zongchuli += 1
                kefu.save()

                # 13. 更新退款统计
                update_daily_payout(order.jine)

                # 14. 打手每日统计（退款）
                try:
                    update_dashou_daily_by_action(
                        yonghuid=order.jiedan_dashou_id,
                        amount=order.dashou_fencheng,
                        action=3
                    )
                    logger.info(f"打手 {order.jiedan_dashou_id} 每日统计更新成功")
                except Exception as e:
                    logger.error(f"打手每日统计更新失败: {e}")

            logger.info(f"虚拟支付退款成功，订单 {dingdan_id}，退款单号 {refund_result.get('refund_id')}")
            return Response({'code': 0, 'msg': '退款成功'})

        except Dingdan.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            logger.error(f"虚拟支付退款接口异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'msg': '服务器内部错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    # ==================== 核心退款方法 ====================
    def call_virtual_refund(self, dingdan_id, jine, openid, wechat_transaction_id=None):
        """
        调用虚拟支付退款接口 /xpay/refund_order
        :param dingdan_id: 商户订单号（order_id）
        :param jine: 退款金额（元）
        :param openid: 支付用户的 openid
        :param wechat_transaction_id: 微信支付交易单号（wx_order_id），若有则优先使用
        :return: {'code': 0, 'msg': '成功', 'refund_id': 'xxx'} 或 {'code': 非0, 'msg': '错误信息'}
        """
        uri = "/xpay/refund_order"
        base_url = "https://api.weixin.qq.com"
        appkey = settings.VP_APPKEY_SANDBOX if settings.VP_ENV == 1 else settings.VP_APPKEY
        offer_id = settings.VP_OFFER_ID

        # 金额：元 -> 分
        refund_fee = int(float(jine) * 100)

        # 退款单号：R + 时间戳 + 6位随机数，保证唯一且长度合适
        refund_order_id = f"R{int(time.time())}{random.randint(100000, 999999)}"

        # 用户 IP
        x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR')
        user_ip = x_forwarded_for.split(',')[0].strip() if x_forwarded_for else self.request.META.get('REMOTE_ADDR', '127.0.0.1')

        # 请求体构造（优先使用 wx_order_id，若有的话）
        body_data = {
            "openid": openid,
            "env": settings.VP_ENV,
            "order_id": dingdan_id,                    # 商户订单号
            "refund_order_id": refund_order_id,        # 本次退款单号
            "left_fee": refund_fee,                    # 订单剩余可退金额（全退时等于订单金额）
            "refund_fee": refund_fee,                  # 本次退款金额
            "biz_meta": "客服退款",                    # 业务备注
            "refund_reason": 5,                        # 退款原因：5 其他
            "req_from": 1                              # 退款来源：1 人工客服
        }
        # 如果有微信支付交易单号，优先传入（可选）
        if wechat_transaction_id:
            body_data["wx_order_id"] = wechat_transaction_id

        body = json.dumps(body_data, separators=(",", ":"))

        # 签名：pay_sig
        msg = uri + "&" + body
        pay_sig = hmac.new(appkey.encode("utf-8"), msg.encode("utf-8"), hashlib.sha256).hexdigest()

        # 获取 access_token
        access_token = self._get_access_token()

        # 构建 URL
        url = f"{base_url}{uri}?access_token={access_token}&pay_sig={pay_sig}"

        # ========== 调试日志（保留，方便排查） ==========
        logger.info("================== 退款调试信息 ==================")
        logger.info(f"[退款] 订单号 (dingdan_id): {dingdan_id}")
        logger.info(f"[退款] 微信交易号 (wx_order_id): {wechat_transaction_id}")
        logger.info(f"[退款] 退款金额 (分): {refund_fee}")
        logger.info(f"[退款] 退款单号: {refund_order_id}")
        logger.info(f"[退款] 请求 URL: {url}")
        logger.info(f"[退款] 请求 Body: {body}")
        logger.info("==================================================")

        headers = {"Content-Type": "application/json"}
        try:
            response = requests.post(url, data=body, headers=headers, timeout=10)
            result = response.json()
            logger.info(f"[退款] 微信返回结果: {result}")

            if result.get("errcode") == 0:
                return {'code': 0, 'msg': '退款成功', 'refund_id': refund_order_id}
            else:
                errcode = result.get('errcode')
                errmsg = result.get('errmsg', '未知错误')
                # 常见错误码提示
                if errcode == 268490002:
                    errmsg = "参数错误，请检查订单号是否正确、金额是否匹配、openid是否正确"
                elif errcode == 268490003:
                    errmsg = "签名错误，请检查 appkey 是否正确"
                elif errcode == 268490004:
                    errmsg = "订单不存在或已退款"
                logger.error(f"[退款] 退款失败: errcode={errcode}, errmsg={errmsg}")
                return {'code': 400, 'msg': f"退款失败: {errmsg}"}

        except requests.exceptions.RequestException as e:
            logger.error(f"[退款] 网络请求异常: {e}")
            return {'code': 500, 'msg': '微信退款请求网络异常'}

    def _get_access_token(self):
        """获取 access_token，带缓存"""
        cache_key = "virtual_payment_access_token"
        access_token = cache.get(cache_key)
        if not access_token:
            logger.info("[退款] 缓存无 access_token，重新获取")
            resp = requests.get(
                "https://api.weixin.qq.com/cgi-bin/token",
                params={
                    "grant_type": "client_credential",
                    "appid": settings.WEIXIN_APPID,
                    "secret": settings.WEIXIN_SECRET,
                },
                timeout=10,
            )
            data = resp.json()
            if "access_token" in data:
                access_token = data["access_token"]
                cache.set(cache_key, access_token, data.get("expires_in", 7200) - 300)
                logger.info(f"[退款] access_token 已更新")
            else:
                raise Exception(f"获取 access_token 失败: {data}")
        return access_token





# dingdan/views.py
import logging

from rest_framework.views import APIView

from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser

from yonghu.models import  UserShangjia
from dingdan.models import Dingdan, DingdanShangjia, Tuikuanjilu

logger = logging.getLogger(__name__)
from houtai.utils import update_dashou_daily_by_action

class KefuRejectRefundView(APIView):
    """
    客服拒绝退款接口
    请求：POST /yonghu/kefujjtk
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID",
        "jujue_liyou": "拒绝理由（可选）"
    }
    认证：JWT
    返回：code=0 成功
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()
        jujue_liyou = request.data.get('jujue_liyou', '').strip()

        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if current_user.user_type != 'kefu':
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if kefu.zhuangtai != 1:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询订单并加锁
        try:
            with transaction.atomic():
                order = Dingdan.objects.select_for_update().get(dingdan_id=dingdan_id)

                # 4. 验证订单状态为退款审核中（4）
                if order.zhuangtai != 4:
                    return Response({'code': 400, 'msg': '订单状态不是退款审核中'}, status=status.HTTP_400_BAD_REQUEST)

                # 获取必要字段
                jiedan_dashou_id = order.jiedan_dashou_id
                dashou_fencheng = order.dashou_fencheng
                fadan_pingtai = order.fadan_pingtai

                # 5. 验证打手分成金额是否存在
                if dashou_fencheng is None:
                    return Response({'code': 400, 'msg': '订单缺少打手分成金额'}, status=status.HTTP_400_BAD_REQUEST)

                # 6. 更新订单状态为退款失败（6）
                order.zhuangtai = 6
                order.clkf = current_user.phone  # 记录处理客服手机号
                if jujue_liyou:
                    order.tkly = jujue_liyou
                order.save()

                # 7. 给打手结算（返还分成）
                if jiedan_dashou_id:
                    try:
                        dashou_user = UserMain.objects.get(yonghuid=jiedan_dashou_id)
                        dashou_profile = dashou_user.dashou_profile
                        # 增加打手相关统计数据
                        dashou_profile.chengjiaozongliang += 1
                        dashou_profile.yue += dashou_fencheng
                        dashou_profile.zonge += dashou_fencheng
                        dashou_profile.jinrishouyi += dashou_fencheng
                        dashou_profile.jinyueshouyi += dashou_fencheng
                        dashou_profile.save()
                        logger.info(f"拒绝退款：打手 {jiedan_dashou_id} 获得分成 {dashou_fencheng}")
                    except (UserMain.DoesNotExist, AttributeError):
                        logger.warning(f"拒绝退款：打手 {jiedan_dashou_id} 不存在或扩展表缺失，跳过结算")

                # 8. 如果是商家发单，更新商家成交订单数量
                if fadan_pingtai == 2:
                    try:
                        # 获取商家订单扩展表
                        shangjia_kuozhan = order.shangjia_kuozhan
                        shangjia_id = shangjia_kuozhan.shangjia_id
                        if shangjia_id:
                            shangjia_user = UserMain.objects.get(yonghuid=shangjia_id)
                            shangjia_profile = shangjia_user.shop_profile
                            shangjia_profile.chengjiao += 1
                            shangjia_profile.save()
                            logger.info(f"拒绝退款：商家 {shangjia_id} 成交订单+1")
                            # ✅ 新方法（行为驱动，更安全）
                            from houtai.utils import update_shangjia_daily
                            update_shangjia_daily(
                                yonghuid=shangjia_id,
                                amount=Decimal(str(order.jine)),
                                action=2  # 2 = 结算
                            )
                    except (ObjectDoesNotExist, UserMain.DoesNotExist, AttributeError):
                        logger.warning(f"拒绝退款：商家信息不存在，跳过商家更新")

                # 9. 更新退款记录表
                try:
                    refund_record = Tuikuanjilu.objects.get(dingdan_id=dingdan_id)
                    refund_record.sqzhuangtai = 2          # 2表示拒绝
                    refund_record.chuliid = phone
                    refund_record.bhliyou = jujue_liyou    # 记录驳回理由（假设模型有此字段）
                    refund_record.save()
                    logger.info(f"拒绝退款：更新退款记录表，订单 {dingdan_id}")
                except Tuikuanjilu.DoesNotExist:
                    # 如果退款记录不存在，可以创建一条记录（可选）
                    Tuikuanjilu.objects.create(
                        dingdan_id=dingdan_id,
                        dashouid=jiedan_dashou_id or '',
                        qingqiuid='',
                        chuliid=phone,
                        liyou=jujue_liyou or '客服拒绝退款',
                        sqzhuangtai=2,
                        jine=order.jine,
                        dashou_fencheng=dashou_fencheng or 0,
                        jieshao=order.jieshao or '',
                        beizhu='客服拒绝退款',
                        nicheng=order.nicheng or '',
                        bhliyou=jujue_liyou or '',  # 假设模型有 bhliyou 字段
                    )
                except Exception as e:
                    logger.error(f"拒绝退款更新退款记录异常: {str(e)}", exc_info=True)

                # 🔥 新增：调用打手每日统计（成交）
                try:
                    update_dashou_daily_by_action(
                        yonghuid=jiedan_dashou_id,
                        amount=dashou_fencheng,
                        action=2  # 2 表示成交（结算）
                    )
                    logger.info(f"打手 {jiedan_dashou_id} 每日统计更新成功")
                except Exception as e:
                    logger.error(f"打手每日统计更新失败: {e}")
                    # 不影响主流程

                # 10. 更新客服统计数据
                kefu.jinrichuli += 1
                kefu.jinyuechuli += 1
                kefu.zongchuli += 1
                kefu.save()

            return Response({'code': 0, 'msg': '拒绝退款成功'})

        except Dingdan.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            logger.error(f"拒绝退款接口异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'msg': '服务器内部错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)






class KefuMerchantRefundView(APIView):
    """
    客服商家订单退款接口（发单平台=2）
    请求：POST /yonghu/kefusjtk
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID",
        "tuikuan_liyou": "退款理由（可选）"
    }
    认证：JWT
    返回：code=0 成功
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()
        tuikuan_liyou = request.data.get('tuikuan_liyou', '').strip()


        # 客服身份验证（同前，省略以节省篇幅，但实际必须完整）

        # ... 验证
        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if current_user.user_type != 'kefu':
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if kefu.zhuangtai != 1:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 查询订单，预加载商家扩展表
        try:
            order = Dingdan.objects.select_related('shangjia_kuozhan').get(dingdan_id=dingdan_id)
        except Dingdan.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)

        # 验证商家订单
        if order.fadan_pingtai != 2:
            return Response({'code': 400, 'msg': '该订单不是商家订单'}, status=status.HTTP_400_BAD_REQUEST)

        # 验证状态允许退款
        allowed_statuses = [1, 7, 2, 8, 4]
        if order.zhuangtai not in allowed_statuses:
            return Response({'code': 400, 'msg': '订单状态不允许退款'}, status=status.HTTP_400_BAD_REQUEST)

        # 获取必要数据
        jiedan_dashou_id = order.jiedan_dashou_id
        jine = order.jine
        if jine is None:
            return Response({'code': 400, 'msg': '订单金额缺失'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            shangjia_kuozhan = order.shangjia_kuozhan
            shangjia_id = shangjia_kuozhan.shangjia_id
        except ObjectDoesNotExist:
            return Response({'code': 400, 'msg': '订单商家信息不存在'}, status=status.HTTP_400_BAD_REQUEST)

        with transaction.atomic():
            # 更新订单
            order.zhuangtai = 5
            order.clkf = current_user.phone
            if tuikuan_liyou:
                order.tkly = tuikuan_liyou
            order.save()

            # 更新打手
            if jiedan_dashou_id:
                try:
                    dashou_user = UserMain.objects.get(yonghuid=jiedan_dashou_id)
                    dashou_profile = dashou_user.dashou_profile
                    dashou_profile.tuikuanliang += 1
                    dashou_profile.zhuangtai = 1
                    dashou_profile.save()
                except (UserMain.DoesNotExist, ObjectDoesNotExist):
                    logger.warning(f"商家退款：打手 {jiedan_dashou_id} 不存在，跳过更新")

            # 更新商家
            try:
                shangjia_user = UserMain.objects.get(yonghuid=shangjia_id)
                shangjia_profile = shangjia_user.shop_profile
                shangjia_profile.tuikuan += 1
                shangjia_profile.yue += jine
                shangjia_profile.save()
            except (UserMain.DoesNotExist, ObjectDoesNotExist):
                logger.warning(f"商家退款：商家 {shangjia_id} 不存在，跳过更新")

            # 更新退款记录表
            try:
                refund_record = Tuikuanjilu.objects.get(dingdan_id=dingdan_id)
                refund_record.sqzhuangtai = 1
                refund_record.chuliid = phone
                refund_record.save()
            except Tuikuanjilu.DoesNotExist:
                pass

            # ✅ 新方法（行为驱动，更安全）
            from houtai.utils import update_shangjia_daily
            update_shangjia_daily(
                yonghuid=shangjia_id,
                amount=Decimal(str(order.jine)),
                action=3  # 3 = 退款
            )

            # 🔥 新增：调用打手每日统计（成交）
            try:
                update_dashou_daily_by_action(
                    yonghuid=order.jiedan_dashou_id,
                    amount=order.dashou_fencheng,
                    action=3  # 3 表示退款（退款）
                )
                logger.info(f"打手 {order.jiedan_dashou_id} 每日统计更新成功")
            except Exception as e:
                logger.error(f"打手每日统计更新失败: {e}")
                # 不影响主流程

            # 更新客服统计
            kefu = current_user.kefu_profile
            kefu.jinrichuli += 1
            kefu.jinyuechuli += 1
            kefu.zongchuli += 1
            kefu.save()

        return Response({'code': 0, 'msg': '退款成功'})




logger = logging.getLogger(__name__)

class KefuRejectSettlementView(APIView):
    """
    客服拒绝结算接口（仅平台订单，状态2/8）
    请求：POST /yonghu/kefujjjs
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID",
        "tkly": "拒绝结算理由（必填）"
    }
    认证：JWT
    返回：code=0 成功，其他失败
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()
        tkly = request.data.get('tkly', '').strip()

        if not phone or not dingdan_id or not tkly:
            return Response({'code': 401, 'msg': '参数不完整'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            logger.warning(f"手机号不匹配: {phone}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if current_user.user_type != 'kefu':
            logger.warning(f"用户类型非客服: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            logger.warning(f"客服扩展表不存在: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if kefu.zhuangtai != 1:
            logger.warning(f"客服账号已禁用: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询订单，预加载平台扩展表
        try:
            order = Dingdan.objects.select_related('pingtai_kuozhan').get(dingdan_id=dingdan_id)
        except Dingdan.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)

        # 4. 校验订单条件：平台发单（1）且状态为2或8
        if order.fadan_pingtai != 1 or order.zhuangtai not in [2, 8]:
            return Response({'code': 400, 'msg': '仅平台发单且状态为进行中(2)或结算中(8)的订单可拒绝结算'}, status=status.HTTP_400_BAD_REQUEST)

        jiedan_dashou_id = order.jiedan_dashou_id
        if not jiedan_dashou_id:
            return Response({'code': 400, 'msg': '订单暂无接单打手'}, status=status.HTTP_400_BAD_REQUEST)

        # 5. 使用事务更新
        with transaction.atomic():
            # 5.1 更新订单主表
            order.zhuangtai = 5                     # 已退款
            order.tkly = tkly                        # 拒绝理由
            order.clkf = phone                        # 记录客服手机号
            order.save()

            # 5.2 更新平台订单扩展表：标记为拒绝结算（假设字段 jjjs_biaoshi）
            # 注意：需要确保 DingdanPingtai 模型中已添加 jjjs_biaoshi 字段，IntegerField，默认0
            if hasattr(order, 'pingtai_kuozhan') and order.pingtai_kuozhan:
                pingtai_ext = order.pingtai_kuozhan
                pingtai_ext.jjjs_biaoshi = 1          # 1表示拒绝结算
                pingtai_ext.save()
            else:
                # 理论上应该存在，但若不存在则记录日志
                logger.warning(f"订单 {dingdan_id} 缺少平台扩展表，无法标记拒绝结算")

            # 5.3 更新打手扩展表
            try:
                dashou_user = UserMain.objects.get(yonghuid=jiedan_dashou_id)
                dashou_profile = dashou_user.dashou_profile
                dashou_profile.zhuangtai = 1          # 打手状态设为空闲
                dashou_profile.tuikuanliang += 1      # 退款订单总量+1
                dashou_profile.save()
                logger.info(f"拒绝结算：打手 {jiedan_dashou_id} 退款订单+1，状态空闲")
            except (UserMain.DoesNotExist, ObjectDoesNotExist):
                logger.warning(f"拒绝结算：打手 {jiedan_dashou_id} 不存在或扩展表缺失，跳过更新")
            except Exception as e:
                logger.error(f"拒绝结算更新打手异常: {str(e)}", exc_info=True)

            # 🔥 新增：调用打手每日统计（成交）
            try:
                update_dashou_daily_by_action(
                    yonghuid=order.jiedan_dashou_id,
                    amount=order.dashou_fencheng,
                    action=3  # 3 表示退款（退款）
                )
                logger.info(f"打手 {order.jiedan_dashou_id} 每日统计更新成功")
            except Exception as e:
                logger.error(f"打手每日统计更新失败: {e}")
                # 不影响主流程

            # 5.4 更新客服扩展表统计数据
            kefu.jinrichuli += 1
            kefu.jinyuechuli += 1
            kefu.zongchuli += 1
            kefu.save()

        return Response({'code': 0, 'msg': '拒绝结算成功'})



class KefuTransferHallView(APIView):
    """
    客服恢复大厅（转移大厅）接口
    请求：POST /yonghu/kefuzydt
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID"
    }
    认证：JWT
    返回：code=0 成功
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()

        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '参数不完整'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证（同前，略，但必须完整实现）
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        if current_user.user_type != 'kefu':
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        try:
            kefu = current_user.kefu_profile
            if kefu.zhuangtai != 1:
                return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        except ObjectDoesNotExist:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询订单
        try:
            order = Dingdan.objects.get(dingdan_id=dingdan_id)
        except Dingdan.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)

        # 4. 校验订单状态（允许状态：2,8,4）
        if order.zhuangtai not in [2, 8, 4]:
            return Response({'code': 400, 'msg': '订单状态不允许转移大厅'}, status=status.HTTP_400_BAD_REQUEST)

        # 5. 根据是否有指定ID决定新状态

        if order.jiedan_dashou_id:
            UserDashou.objects.filter(user__yonghuid=order.jiedan_dashou_id).update(zhuangtai=1)
        else:
            pass

        if order.zhiding_id:
            new_status = 7   # 指定中
        else:
            new_status = 1   # 下单中

        # 6. 使用事务更新
        with transaction.atomic():
            # 清空接单打手ID，更新状态，记录客服
            order.jiedan_dashou_id = None
            order.zhuangtai = new_status
            order.clkf = phone
            order.save()

        return Response({'code': 0, 'msg': '转移大厅成功'})







from dingdan.utils import update_daily_dispatch_stat
from dingdan.models import PreSettlement

logger = logging.getLogger(__name__)
from shangpin.utils import update_shangpin_daily_stat
from shangdian.utils import update_dianpu_daily_stat   # 注意：您之前写的店铺统计方法名是 update_dianpu_daily_stat



class KefuForceCompleteView(APIView):
    """
    客服强制结单接口（仅本地订单）
    请求：POST /yonghu/kefuqiangzhijiedan
    参数：{"phone": "客服手机号", "dingdan_id": "订单ID"}
    认证：JWT，仅限状态正常的客服
    逻辑：
        1. 验证客服身份及状态
        2. 查询订单并加锁（事务内）
        3. 校验订单状态是否为8（结算中）
        4. 校验订单必须有接单打手且打手分成金额有效
        5. 给打手增加余额、成交统计、今日/本月收益
        6. 如果是商家发单，更新商家成交订单数量
        7. 更新订单状态为3（已完成）
        8. 更新客服处理统计
        9. 返回成功
    """
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()

        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '参数缺失'})

        # 1. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            return Response({'code': 401, 'msg': '认证失败'})

        if current_user.user_type != 'kefu':
            return Response({'code': 401, 'msg': '认证失败'})

        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            return Response({'code': 401, 'msg': '认证失败'})

        if kefu.zhuangtai != 1:
            return Response({'code': 401, 'msg': '客服状态异常'})

        # 2. 订单处理（事务内）
        try:
            with transaction.atomic():
                order = Dingdan.objects.select_for_update().get(dingdan_id=dingdan_id)

                # 3. 校验订单状态
                if order.zhuangtai != 8:
                    return Response({'code': 400, 'msg': f'订单状态不是结算中，当前状态: {order.zhuangtai}'})

                # 4. 校验必要字段
                dashou_id = order.jiedan_dashou_id
                dashou_fencheng = order.dashou_fencheng
                if not dashou_id:
                    return Response({'code': 400, 'msg': '订单无接单打手'})
                if not dashou_fencheng or dashou_fencheng <= 0:
                    return Response({'code': 400, 'msg': '打手分成金额无效'})

                # 5. 给打手结算
                try:
                    dashou_user = UserMain.objects.get(yonghuid=dashou_id)
                    dashou_profile = dashou_user.dashou_profile
                    # 原子更新（避免并发重复加）
                    dashou_profile.chengjiaozongliang = F('chengjiaozongliang') + 1
                    dashou_profile.yue = F('yue') + dashou_fencheng
                    dashou_profile.zonge = F('zonge') + dashou_fencheng
                    dashou_profile.jinrishouyi = F('jinrishouyi') + dashou_fencheng
                    dashou_profile.jinyueshouyi = F('jinyueshouyi') + dashou_fencheng
                    dashou_profile.save(update_fields=[
                        'chengjiaozongliang', 'yue', 'zonge',
                        'jinrishouyi', 'jinyueshouyi'
                    ])
                except (UserMain.DoesNotExist, AttributeError):
                    return Response({'code': 400, 'msg': '打手不存在或扩展表缺失'})

                # 6. 如果是商家发单，更新商家成交订单数量
                if order.fadan_pingtai == 2:
                    try:
                        # 通过 DingdanShangjia 获取商家ID
                        shangjia_ext = order.shangjia_kuozhan  # 假设 related_name='shangjia_kuozhan'
                        if shangjia_ext and shangjia_ext.shangjia_id:
                            shangjia_user = UserMain.objects.get(yonghuid=shangjia_ext.shangjia_id)
                            shangjia_profile = shangjia_user.shop_profile
                            shangjia_profile.chengjiao = F('chengjiao') + 1
                            shangjia_profile.save(update_fields=['chengjiao'])

                            # ✅ 新方法（行为驱动，更安全）
                            from houtai.utils import update_shangjia_daily
                            update_shangjia_daily(
                                yonghuid=shangjia_ext.shangjia_id,
                                amount=Decimal(str(order.jine)),
                                action=2  # 2 = 结算
                            )

                    except ObjectDoesNotExist:
                        # 没有商家扩展记录则忽略
                        pass

                # 7. 更新订单状态
                order.zhuangtai = 3
                order.clkf = phone
                order.save(update_fields=['zhuangtai', 'clkf'])


                if order.fadan_pingtai == 1:

                    # ========== 新增：商品和店铺每日统计 ==========
                    try:
                        # 商品每日统计（只要有商品ID就执行）
                        if order.shangpin_id:
                            # 从扩展表获取已计算好的收益值（下单时已存储）
                            pingtai_shouyi = Decimal('0.00')
                            dianpu_shouyi = Decimal('0.00')
                            if hasattr(order, 'pingtai_kuozhan'):
                                pingtai_shouyi = order.pingtai_kuozhan.pingtai_shouyi or Decimal('0.00')
                                dianpu_shouyi = order.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')

                            update_shangpin_daily_stat(
                                shangpin_id=order.shangpin_id,
                                caozuo_leixing=2,  # 2 = 结单
                                dingdan_jiage=order.jine,
                                pingtai_shouyi=pingtai_shouyi,
                                dianpu_zongshouyi=dianpu_shouyi
                            )
                            logger.info(f"商品统计更新完成，商品ID: {order.shangpin_id}")

                        # 店铺每日统计（仅当存在店铺ID时执行）
                        dianpu_id = None
                        if hasattr(order, 'pingtai_kuozhan'):
                            dianpu_id = order.pingtai_kuozhan.dianpu_id
                        if dianpu_id:
                            dianpu_shouyi = order.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')
                            update_dianpu_daily_stat(
                                dianpu_id=dianpu_id,
                                caozuo_leixing=2,  # 2 = 结单
                                dingdan_jiage=order.jine,
                                dianpu_shouyi=dianpu_shouyi
                            )
                            logger.info(f"店铺统计更新完成，店铺ID: {dianpu_id}")
                    except Exception as e:
                        logger.error(f"商品/店铺统计更新失败: {e}")
                        logger.error(traceback.format_exc())
                        # 统计失败不影响主流程
                    # =============================================

                # 🔥 新增：调用打手每日统计（成交）
                try:
                    update_dashou_daily_by_action(
                        yonghuid=order.jiedan_dashou_id,
                        amount=dashou_fencheng,
                        action=2  # 2 表示成交（结算）
                    )
                    logger.info(f"打手 {order.jiedan_dashou_id} 每日统计更新成功")
                except Exception as e:
                    logger.error(f"打手每日统计更新失败: {e}")
                    # 不影响主流程

                # 商家订单管事分红
                if order.fadan_pingtai == 2:
                    from dingdan.utils import settle_shangjia_order_guanshi_fenhong
                    settle_shangjia_order_guanshi_fenhong(order, dashou_id)

                # 8. 更新客服统计
                kefu.jinrichuli = F('jinrichuli') + 1
                kefu.jinyuechuli = F('jinyuechuli') + 1
                kefu.zongchuli = F('zongchuli') + 1
                kefu.save(update_fields=['jinrichuli', 'jinyuechuli', 'zongchuli'])

            return Response({'code': 0, 'msg': '强制结单成功'})

        except Dingdan.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'})
        except Exception as e:
            logger.error(f"强制结单异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'msg': '服务器内部错误'})









class KefuCancelDesignationView(APIView):
    """
    客服取消指定接口（仅状态7）
    请求：POST /yonghu/kefuqxzd
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID"
    }
    认证：JWT
    返回：code=0 成功
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()

        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '参数不完整'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证（同前，略，但必须完整实现）
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        if current_user.user_type != 'kefu':
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        try:
            kefu = current_user.kefu_profile
            if kefu.zhuangtai != 1:
                return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        except ObjectDoesNotExist:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询订单
        try:
            order = Dingdan.objects.get(dingdan_id=dingdan_id)
        except Dingdan.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)

        # 4. 校验订单状态为7（指定中）
        if order.zhuangtai != 7:
            return Response({'code': 400, 'msg': '仅状态为指定中(7)的订单可取消指定'}, status=status.HTTP_400_BAD_REQUEST)

        # 5. 使用事务更新
        with transaction.atomic():
            # 状态改为1（下单中），清空指定ID，记录客服
            order.zhuangtai = 1
            order.zhiding_id = None
            order.clkf = phone
            order.save()

        return Response({'code': 0, 'msg': '取消指定成功'})






import logging
from django.db.models import Q
from django.core.exceptions import ObjectDoesNotExist
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser

from yonghu.models import UserMain, UserKefu, UserDashou

logger = logging.getLogger(__name__)

class KefuGetDashouListView(APIView):
    """
    客服获取打手列表接口（仅打手类型）
    请求：POST /yonghu/kefuhqdslb
    参数：{
        "phone": "客服手机号",
        "keyword": "搜索关键词（可选，搜索用户ID或昵称）",
        "page": "页码（从1开始）",
        "page_size": "每页数量"
    }
    认证：JWT
    返回：{
        "code": 0,
        "data": {
            "list": [打手对象],
            "has_more": true/false
        }
    }
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('zhanghao', '').strip()
        keyword = request.data.get('keyword', '').strip()
        try:
            page = int(request.data.get('page', 1))
            page_size = int(request.data.get('page_size', 20))
        except ValueError:
            return Response({'code': 400, 'msg': '分页参数错误'}, status=status.HTTP_400_BAD_REQUEST)

        if not phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            logger.warning(f"手机号不匹配: {phone}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if current_user.user_type != 'kefu':
            logger.warning(f"用户类型非客服: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            logger.warning(f"客服扩展表不存在: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if kefu.zhuangtai != 1:
            logger.warning(f"客服账号已禁用: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 构建查询条件（只查询打手）
        # 通过 UserDashou 扩展表关联 UserMain
        queryset = UserDashou.objects.select_related('user').all()

        if keyword:
            # 搜索用户ID或打手昵称
            queryset = queryset.filter(
                Q(user__yonghuid__icontains=keyword) |
                Q(nicheng__icontains=keyword)
            )

        # 4. 计算总数并分页
        total = queryset.count()
        offset = (page - 1) * page_size
        dashou_list = queryset.order_by('-create_time')[offset:offset + page_size]

        # 5. 构建返回数据（只取需要的字段）
        result = []
        for dashou in dashou_list:
            user = dashou.user
            result.append({
                'yonghuid': user.yonghuid,
                'avatar': user.avatar or '',
                'zaixianzhuangtai': dashou.zaixianzhuangtai,
                'zhanghaozhuangtai': dashou.zhanghaozhuangtai,
                'nicheng': dashou.nicheng or '',
                'zhuangtai': dashou.zhuangtai,
            })

        # 6. 判断是否有更多数据
        has_more = (offset + len(dashou_list)) < total

        return Response({
            'code': 0,
            'data': {
                'list': result,
                'has_more': has_more
            }
        })







class KefuGetDashouDetailView(APIView):
    """
    客服获取打手详情接口
    请求：POST /yonghu/kefuhqdsxq
    参数：{
        "phone": "客服手机号",
        "uid": "打手ID (yonghuid)"
    }
    认证：JWT
    返回：code=0 + 打手信息 + 会员列表
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        uid = request.data.get('uid', '').strip()

        if not phone or not uid:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            logger.warning(f"手机号不匹配: {phone}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if current_user.user_type != 'kefu':
            logger.warning(f"用户类型非客服: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            logger.warning(f"客服扩展表不存在: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if kefu.zhuangtai != 1:
            logger.warning(f"客服账号已禁用: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询打手主表和扩展表
        try:
            # 使用 select_related 预加载 dashou_profile，减少数据库查询
            user_main = UserMain.objects.select_related('dashou_profile').get(
                yonghuid=uid
            )
        except UserMain.DoesNotExist:
            return Response({'code': 404, 'msg': '打手不存在'}, status=status.HTTP_404_NOT_FOUND)

        # 验证用户类型是否为打手（可选，但建议验证）
        # 如果该用户没有打手扩展表，则返回空信息（但前端会显示未注册）
        try:
            dashou = user_main.dashou_profile
        except ObjectDoesNotExist:
            # 用户存在但未注册打手身份，返回基本信息
            user_info = {
                'yonghuid': user_main.yonghuid,
                'avatar': user_main.avatar or '',
                'zaixianzhuangtai': 0,
                'zhanghaozhuangtai': 0,
                'zhuangtai': 0,
                'nicheng': '',
                'chenghao': '',
                'dianhua': '',
                'wechat': '',
                'phone': user_main.phone or '',
                'create_time': user_main.create_time,
                'ip': user_main.ip or '',
                'jiedanzongliang': 0,
                'chengjiaozongliang': 0,
                'tuikuanliang': 0,
                'jinrijiedan': 0,
                'yue': 0.00,
                'zonge': 0.00,
                'jifen': 0,
                'yajin': 0.00,
                'jinrishouyi': 0.00,
                'jinyueshouyi': 0.00,
                'yaoqingren': '',
                'jieshao': '',
            }
            member_list = []
            return Response({
                'code': 0,
                'data': {
                    'user_info': user_info,
                    'member_list': member_list
                }
            })

        # 4. 构建打手信息
        user_info = {
            'yonghuid': user_main.yonghuid,
            'avatar': user_main.avatar or '',
            'zaixianzhuangtai': dashou.zaixianzhuangtai,
            'zhanghaozhuangtai': dashou.zhanghaozhuangtai,
            'zhuangtai': dashou.zhuangtai,
            'nicheng': dashou.nicheng or '',
            '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 '',
            'jiedanzongliang': dashou.jiedanzongliang,
            'chengjiaozongliang': dashou.chengjiaozongliang,
            'tuikuanliang': dashou.tuikuanliang,
            'jinrijiedan': dashou.jinrijiedan,
            'yue': float(dashou.yue) if dashou.yue else 0.00,
            'zonge': float(dashou.zonge) if dashou.zonge else 0.00,
            'jifen': dashou.jifen,
            'yajin': float(dashou.yajin) if dashou.yajin else 0.00,
            'jinrishouyi': float(dashou.jinrishouyi) if dashou.jinrishouyi else 0.00,
            'jinyueshouyi': float(dashou.jinyueshouyi) if dashou.jinyueshouyi else 0.00,
            'yaoqingren': dashou.yaoqingren or '',
            'jieshao': dashou.jieshao or '',
        }

        # 5. 查询打手会员信息（仅未过期）
        member_records = Huiyuangoumai.objects.filter(
            yonghu_id=uid
        ).order_by('-create_time')

        member_list = []
        for record in member_records:
            # 调用模型方法检查是否过期
            if hasattr(record, 'jiance_shifou_daoqi'):
                is_expired = record.jiance_shifou_daoqi()
            else:
                # 如果方法不存在，简单判断
                is_expired = record.daoqi_time < timezone.now() if record.daoqi_time else True

            if not is_expired:
                # 获取会员详情
                try:
                    huiyuan = Huiyuan.objects.get(huiyuan_id=record.huiyuan_id)
                    huiyuan_name = huiyuan.jieshao
                except Huiyuan.DoesNotExist:
                    huiyuan_name = '未知会员'

                member_list.append({
                    'id': record.id,
                    'huiyuan_name': huiyuan_name,
                    'daoqi_time': record.daoqi_time,
                    'is_active': record.huiyuan_zhuangtai == 1,
                })

        return Response({
            'code': 0,
            'data': {
                'user_info': user_info,
                'member_list': member_list
            }
        })



from yonghu.models import Xiugaijilu  # 确保已导入




from houtai.utils import verify_kefu_permission

logger = logging.getLogger(__name__)

class KefuUpdateDashouView(APIView):
    """
    客服修改打手信息接口
    支持操作：
    - jian_yue / jia_yue           : 减/加打手余额 (权限001aa/001bb)
    - jian_yajin / jia_yajin       : 减/加打手押金 (权限001aa/001bb)
    - jian_jifen / jia_jifen       : 减/加打手积分 (权限001cc/001dd)
    - gai_zhanghaozhuangtai        : 修改打手账号状态（封禁/解封） (权限001ee)
    - gai_zaixianzhuangtai         : 修改打手在线状态 (权限001ee)
    - gai_zhuangtai                : 修改打手接单状态（空闲/忙碌） (权限001ee)
    - jia_huiyuan / jian_huiyuan   : 加/减会员 (权限001ff/001gg)
    """
    def post(self, request):
        # 1. 获取前端参数
        username = request.data.get('username', '').strip()
        dashou_id = request.data.get('dashou_id', '').strip()
        caozuo = request.data.get('caozuo', '').strip()
        value = request.data.get('value')          # 金额、积分、天数等
        huiyuan_id = request.data.get('huiyuan_id', '').strip()   # 会员ID（加/减会员时使用）

        if not username or not dashou_id or not caozuo:
            return Response({'code': 400, 'msg': '参数不完整'})

        # 2. 权限校验（统一方法）
        kefu, permissions = verify_kefu_permission(request, username)
        if kefu is None:
            return permissions  # 直接返回错误响应

        # 3. 查询打手是否存在
        try:
            dashou_user = UserMain.objects.get(yonghuid=dashou_id, user_type='dashou')
            dashou_profile = dashou_user.dashou_profile
        except UserMain.DoesNotExist:
            return Response({'code': 404, 'msg': '打手不存在'})
        except UserDashou.DoesNotExist:
            return Response({'code': 404, 'msg': '打手扩展信息缺失'})

        # 4. 根据操作类型执行（事务内）
        with transaction.atomic():
            try:
                # 记录修改前的值（用于日志）
                before = {
                    'yue': dashou_profile.yue,
                    'yajin': dashou_profile.yajin,
                    'jifen': dashou_profile.jifen,
                    'zhanghaozhuangtai': dashou_profile.zhanghaozhuangtai,
                    'zaixianzhuangtai': dashou_profile.zaixianzhuangtai,
                    'zhuangtai': dashou_profile.zhuangtai,
                }

                # ---------- 余额操作 ----------
                if caozuo == 'jian_yue':
                    if '001aa' not in permissions:
                        return Response({'code': 403, 'msg': '无权限减打手余额'})
                    amount = Decimal(str(value))
                    if dashou_profile.yue < amount:
                        return Response({'code': 400, 'msg': '余额不足'})
                    dashou_profile.yue -= amount
                    dashou_profile.save()
                    after_yue = dashou_profile.yue
                    # 记录日志
                    Xiugaijilu.objects.create(
                        yonghuid=dashou_id,
                        xiugaiid=kefu.user.phone,
                        leixing=2,  # 2=打手
                        xiugaitijiao=after_yue,
                        xiugaitijiaoq=before['yue'],
                    )
                    return Response({'code': 0, 'msg': '减余额成功', 'data': {'new_yue': str(after_yue)}})

                elif caozuo == 'jia_yue':
                    if '001bb' not in permissions:
                        return Response({'code': 403, 'msg': '无权限加打手余额'})
                    amount = Decimal(str(value))
                    dashou_profile.yue += amount
                    dashou_profile.save()
                    after_yue = dashou_profile.yue
                    Xiugaijilu.objects.create(
                        yonghuid=dashou_id,
                        xiugaiid=kefu.user.phone,
                        leixing=2,
                        xiugaitijiao=after_yue,
                        xiugaitijiaoq=before['yue'],
                    )
                    return Response({'code': 0, 'msg': '加余额成功', 'data': {'new_yue': str(after_yue)}})

                # ---------- 押金操作 ----------
                elif caozuo == 'jian_yajin':
                    if '001aa' not in permissions:
                        return Response({'code': 403, 'msg': '无权限减打手押金'})
                    amount = Decimal(str(value))
                    if dashou_profile.yajin < amount:
                        return Response({'code': 400, 'msg': '押金不足'})
                    dashou_profile.yajin -= amount
                    dashou_profile.save()
                    after_yajin = dashou_profile.yajin
                    Xiugaijilu.objects.create(
                        yonghuid=dashou_id,
                        xiugaiid=kefu.user.phone,
                        leixing=2,
                        yajin=after_yajin,
                        yyajin=before['yajin'],
                    )
                    return Response({'code': 0, 'msg': '减押金成功', 'data': {'new_yajin': str(after_yajin)}})

                elif caozuo == 'jia_yajin':
                    if '001bb' not in permissions:
                        return Response({'code': 403, 'msg': '无权限加打手押金'})
                    amount = Decimal(str(value))
                    dashou_profile.yajin += amount
                    dashou_profile.save()
                    after_yajin = dashou_profile.yajin
                    Xiugaijilu.objects.create(
                        yonghuid=dashou_id,
                        xiugaiid=kefu.user.phone,
                        leixing=2,
                        yajin=after_yajin,
                        yyajin=before['yajin'],
                    )
                    return Response({'code': 0, 'msg': '加押金成功', 'data': {'new_yajin': str(after_yajin)}})

                # ---------- 积分操作 ----------
                elif caozuo == 'jian_jifen':
                    if '001cc' not in permissions:
                        return Response({'code': 403, 'msg': '无权限减打手积分'})
                    jifen = int(value)
                    if dashou_profile.jifen < jifen:
                        return Response({'code': 400, 'msg': '积分不足'})
                    dashou_profile.jifen -= jifen
                    dashou_profile.save()
                    after_jifen = dashou_profile.jifen
                    Xiugaijilu.objects.create(
                        yonghuid=dashou_id,
                        xiugaiid=kefu.user.phone,
                        leixing=2,
                        jifen=after_jifen,
                        yjifen=before['jifen'],
                    )
                    return Response({'code': 0, 'msg': '减积分成功', 'data': {'new_jifen': after_jifen}})

                elif caozuo == 'jia_jifen':
                    if '001dd' not in permissions:
                        return Response({'code': 403, 'msg': '无权限加打手积分'})
                    jifen = int(value)
                    dashou_profile.jifen += jifen
                    dashou_profile.save()
                    after_jifen = dashou_profile.jifen
                    Xiugaijilu.objects.create(
                        yonghuid=dashou_id,
                        xiugaiid=kefu.user.phone,
                        leixing=2,
                        jifen=after_jifen,
                        yjifen=before['jifen'],
                    )
                    return Response({'code': 0, 'msg': '加积分成功', 'data': {'new_jifen': after_jifen}})

                # ---------- 状态修改 ----------
                elif caozuo == 'gai_zhanghaozhuangtai':
                    if '001ee' not in permissions:
                        return Response({'code': 403, 'msg': '无权限修改打手账号状态'})
                    new_status = int(value)
                    if new_status not in [0, 1]:
                        return Response({'code': 400, 'msg': '状态值无效（0=封禁,1=正常）'})
                    dashou_profile.zhanghaozhuangtai = new_status
                    dashou_profile.save()
                    Xiugaijilu.objects.create(
                        yonghuid=dashou_id,
                        xiugaiid=kefu.user.phone,
                        leixing=2,
                        qitashuoming=f'修改账号状态为{new_status}',
                    )
                    return Response({'code': 0, 'msg': '修改账号状态成功', 'data': {'new_zhanghaozhuangtai': new_status}})

                elif caozuo == 'gai_zaixianzhuangtai':
                    if '001ee' not in permissions:
                        return Response({'code': 403, 'msg': '无权限修改打手在线状态'})
                    new_status = int(value)
                    if new_status not in [0, 1]:
                        return Response({'code': 400, 'msg': '状态值无效（0=离线,1=在线）'})
                    dashou_profile.zaixianzhuangtai = new_status
                    dashou_profile.save()
                    Xiugaijilu.objects.create(
                        yonghuid=dashou_id,
                        xiugaiid=kefu.user.phone,
                        leixing=2,
                        qitashuoming=f'修改在线状态为{new_status}',
                    )
                    return Response({'code': 0, 'msg': '修改在线状态成功', 'data': {'new_zaixianzhuangtai': new_status}})

                elif caozuo == 'gai_zhuangtai':
                    if '001ee' not in permissions:
                        return Response({'code': 403, 'msg': '无权限修改打手接单状态'})
                    new_status = int(value)
                    if new_status not in [0, 1]:
                        return Response({'code': 400, 'msg': '状态值无效（0=忙碌,1=空闲）'})
                    dashou_profile.zhuangtai = new_status
                    dashou_profile.save()
                    Xiugaijilu.objects.create(
                        yonghuid=dashou_id,
                        xiugaiid=kefu.user.phone,
                        leixing=2,
                        qitashuoming=f'修改接单状态为{new_status}',
                    )
                    return Response({'code': 0, 'msg': '修改接单状态成功', 'data': {'new_zhuangtai': new_status}})

                # ---------- 会员操作 ----------
                elif caozuo == 'jia_huiyuan':
                    if '001ff' not in permissions:
                        return Response({'code': 403, 'msg': '无权限给打手加会员'})
                    if not huiyuan_id:
                        return Response({'code': 400, 'msg': '缺少会员ID'})
                    days = int(value) if value else 30  # 默认加30天
                    try:
                        huiyuan = Huiyuan.objects.get(huiyuan_id=huiyuan_id)
                    except Huiyuan.DoesNotExist:
                        return Response({'code': 404, 'msg': '会员类型不存在'})
                    # 获取或创建购买记录
                    record, created = Huiyuangoumai.objects.select_for_update().get_or_create(
                        yonghu_id=dashou_id,
                        huiyuan_id=huiyuan_id,
                        defaults={
                            'huiyuan_zhuangtai': 1,
                            'jieshao': huiyuan.jieshao,
                            'daoqi_time': timezone.now() + timedelta(days=days),
                        }
                    )
                    if not created:
                        # 延长有效期
                        new_daoqi = record.daoqi_time + timedelta(days=days)
                        record.daoqi_time = new_daoqi
                        record.huiyuan_zhuangtai = 1
                        record.save()
                    # 记录修改日志
                    Xiugaijilu.objects.create(
                        yonghuid=dashou_id,
                        xiugaiid=kefu.user.phone,
                        leixing=2,
                        huiyuants=days,
                        huiyuan_id=huiyuan_id,
                        qitashuoming=f'加会员 {huiyuan_id}，增加{days}天',
                    )
                    return Response({'code': 0, 'msg': '加会员成功', 'data': {'new_daoqi': record.daoqi_time.strftime('%Y-%m-%d %H:%M:%S')}})

                elif caozuo == 'jian_huiyuan':
                    if '001gg' not in permissions:
                        return Response({'code': 403, 'msg': '无权限给打手减会员'})
                    if not huiyuan_id:
                        return Response({'code': 400, 'msg': '缺少会员ID'})
                    try:
                        record = Huiyuangoumai.objects.get(yonghu_id=dashou_id, huiyuan_id=huiyuan_id)
                    except Huiyuangoumai.DoesNotExist:
                        return Response({'code': 404, 'msg': '该打手未购买此会员'})
                    # 删除会员记录（或设置为过期，根据业务要求）
                    record.delete()
                    Xiugaijilu.objects.create(
                        yonghuid=dashou_id,
                        xiugaiid=kefu.user.phone,
                        leixing=2,
                        huiyuan_id=huiyuan_id,
                        qitashuoming=f'移除会员 {huiyuan_id}',
                    )
                    return Response({'code': 0, 'msg': '减会员成功'})

                else:
                    return Response({'code': 400, 'msg': '未知操作类型'})

            except Exception as e:
                logger.error(f"修改打手信息异常: {str(e)}", exc_info=True)
                return Response({'code': 500, 'msg': '服务器内部错误'})

'''class KefuUpdateDashouView(APIView):
    """
    客服修改打手信息接口
    请求：POST /yonghu/kefuxgds
    参数：{
        "phone": "客服手机号",
        "uid": "打手ID",
        // 以下字段可选，只传需要修改的字段
        "yue": 100.00,
        "jifen": 200,
        "yajin": 50.00,
        "zaixianzhuangtai": 0/1,
        "zhanghaozhuangtai": 0/1,
        "zhuangtai": 1/2
    }
    认证：JWT
    返回：code=0 成功
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        uid = request.data.get('uid', '').strip()

        if not phone or not uid:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            logger.warning(f"手机号不匹配: {phone}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if current_user.user_type != 'kefu':
            logger.warning(f"用户类型非客服: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            logger.warning(f"客服扩展表不存在: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if kefu.zhuangtai != 1:
            logger.warning(f"客服账号已禁用: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询打手主表和扩展表
        try:
            user_main = UserMain.objects.select_related('dashou_profile').get(
                yonghuid=uid
            )
        except UserMain.DoesNotExist:
            return Response({'code': 404, 'msg': '打手不存在'}, status=status.HTTP_404_NOT_FOUND)

        try:
            dashou = user_main.dashou_profile
        except ObjectDoesNotExist:
            return Response({'code': 400, 'msg': '该用户未注册打手身份'}, status=status.HTTP_400_BAD_REQUEST)

        # 4. 收集要修改的字段
        update_fields = {}
        editable_fields = [
            'yue', 'jifen', 'yajin',
            'zaixianzhuangtai', 'zhanghaozhuangtai', 'zhuangtai'
        ]

        for field in editable_fields:
            if field in request.data:
                value = request.data.get(field)
                # 类型转换
                if field in ['yue', 'yajin']:
                    try:
                        value = Decimal(str(value))
                    except:
                        return Response({'code': 400, 'msg': f'{field} 格式错误'}, status=status.HTTP_400_BAD_REQUEST)
                elif field in ['jifen']:
                    try:
                        value = int(value)
                    except:
                        return Response({'code': 400, 'msg': f'{field} 必须为整数'}, status=status.HTTP_400_BAD_REQUEST)
                elif field in ['zaixianzhuangtai', 'zhanghaozhuangtai', 'zhuangtai']:
                    try:
                        value = int(value)
                        if field == 'zhuangtai' and value not in [1, 2]:
                            return Response({'code': 400, 'msg': f'{field} 值无效'}, status=status.HTTP_400_BAD_REQUEST)
                        if field != 'zhuangtai' and value not in [0, 1]:
                            return Response({'code': 400, 'msg': f'{field} 值无效'}, status=status.HTTP_400_BAD_REQUEST)
                    except:
                        return Response({'code': 400, 'msg': f'{field} 必须为数字'}, status=status.HTTP_400_BAD_REQUEST)
                update_fields[field] = value

        if not update_fields:
            return Response({'code': 400, 'msg': '没有要修改的字段'}, status=status.HTTP_400_BAD_REQUEST)

        # 5. 使用事务更新并记录修改日志
        with transaction.atomic():
            # 保存旧值用于记录（可选）
            old_values = {field: getattr(dashou, field) for field in update_fields}

            for field, value in update_fields.items():
                setattr(dashou, field, value)
            dashou.save()

            # 记录修改日志
            try:
                # 构建修改描述
                desc_parts = []
                for field in update_fields:
                    old = old_values.get(field)
                    new = update_fields[field]
                    desc_parts.append(f"{field}: {old} -> {new}")
                desc = "; ".join(desc_parts)

                Xiugaijilu.objects.create(
                    yonghuid=uid,
                    xiugaiid=phone,  # 客服手机号
                    leixing=2,  # 打手类型
                    qitashuoming=desc,
                    create_time=timezone.now()
                )
            except Exception as e:
                logger.error(f"记录修改日志失败: {e}")
                # 不影响主流程，但记录错误

        return Response({'code': 0, 'msg': '修改成功'})'''





class KefuPunishmentListView(APIView):
    """
    客服获取处罚记录列表接口
    请求：POST /yonghu/kefu_cfgl
    参数：{
        "phone": "客服手机号",
        "status": [0,3] 或 [1,2],  # 状态数组
        "dingdan_id": "订单ID（可选）",
        "dashouid": "打手ID（可选）",
        "page": 1,
        "page_size": 20
    }
    认证：JWT
    返回：{
        "code": 0,
        "data": {
            "list": [处罚记录],
            "total": 总数,
            "stats": {
                "zongshu": 总记录数,
                "daichuli": 待处理数,
                "yichuli": 已处理数
            }
        }
    }
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        status_list = request.data.get('status')
        dingdan_id = request.data.get('dingdan_id', '').strip()
        dashouid = request.data.get('dashouid', '').strip()
        try:
            page = int(request.data.get('page', 1))
            page_size = int(request.data.get('page_size', 20))
        except ValueError:
            return Response({'code': 400, 'msg': '分页参数错误'}, status=status.HTTP_400_BAD_REQUEST)

        if not phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            logger.warning(f"手机号不匹配: {phone}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if current_user.user_type != 'kefu':
            logger.warning(f"用户类型非客服: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            logger.warning(f"客服扩展表不存在: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if kefu.zhuangtai != 1:
            logger.warning(f"客服账号已禁用: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 获取统计信息（不分页）
        stats = {
            'zongshu': Chufajilu.objects.count(),
            'daichuli': Chufajilu.objects.filter(sqzhuangtai__in=[0, 3]).count(),
            'yichuli': Chufajilu.objects.filter(sqzhuangtai__in=[1, 2]).count(),
        }

        # 4. 构建查询条件
        queryset = Chufajilu.objects.all()

        if status_list and isinstance(status_list, list):
            queryset = queryset.filter(sqzhuangtai__in=status_list)

        if dingdan_id:
            queryset = queryset.filter(dingdan_id=dingdan_id)

        if dashouid:
            queryset = queryset.filter(dashouid=dashouid)

        # 5. 分页
        total = queryset.count()
        offset = (page - 1) * page_size
        records = queryset.order_by('-create_time')[offset:offset + page_size]

        # 6. 构建返回列表
        list_data = []
        for item in records:
            list_data.append({
                'dingdan_id': item.dingdan_id,
                'dashouid': item.dashouid,
                'qingqiuid': item.qingqiuid,
                'cfliyou': item.cfliyou,
                'sqzhuangtai': item.sqzhuangtai,
                'create_time': item.create_time,
                'update_time': item.update_time,
                # 其他字段按需添加
            })

        return Response({
            'code': 0,
            'data': {
                'list': list_data,
                'total': total,
                'stats': stats
            }
        })





class KefuPunishmentDetailView(APIView):
    """
    客服获取处罚详情接口
    请求：POST /yonghu/kefu_cf_detail
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID"
    }
    认证：JWT
    返回：code=0 + 处罚记录详情（含图片）
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()

        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 客服身份验证
        current_user = request.user
        # 1. 获取前端参数
        username = request.data.get('phone', '').strip()
        if not username:
            return Response({'code': 400, 'msg': '缺少username'})

        # 2. 公共权限校验
        kefu, permissions = verify_kefu_permission(request, username)
        if kefu is None:
            return permissions

        # 3. 检查平台订单管理权限（002ab）
        if '005aa' not in permissions:
            return Response({'code': 403, 'msg': '您无权查看平台订单列表'})

        # 查询处罚记录（按创建时间倒序取最新一条）
        try:
            record = Chufajilu.objects.filter(dingdan_id=dingdan_id).order_by('-create_time').first()
            if not record:
                return Response({'code': 404, 'msg': '处罚记录不存在'}, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            logger.error(f"查询处罚记录失败: {e}")
            return Response({'code': 500, 'msg': '服务器内部错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # 查询商家证据图片
        zhengju_images = []
        shensu_images = []
        try:
            # 商家证据图片：上传者为请求人 (qingqiuid)
            zhengju_qs = Chufatupian.objects.filter(dingdan_id=dingdan_id, yonghuid=record.qingqiuid)
            zhengju_images = [item.tupian for item in zhengju_qs if item.tupian]

            # 打手申诉图片：上传者为打手 (dashouid)
            shensu_qs = Chufatupian.objects.filter(dingdan_id=dingdan_id, yonghuid=record.dashouid)
            shensu_images = [item.tupian for item in shensu_qs if item.tupian]
        except Exception as e:
            logger.error(f"查询图片失败: {e}")

        # 构建返回数据
        data = {
            'dingdan_id': record.dingdan_id,
            'dashouid': record.dashouid,
            'qingqiuid': record.qingqiuid,
            'chuliid': record.chuliid,
            'cfliyou': record.cfliyou,
            'sqzhuangtai': record.sqzhuangtai,
            'bhliyou': record.bhliyou,
            'jifen': record.jifen,
            'ssliyou': record.ssliyou or '',
            'zhengju_tupian': zhengju_images,
            'shensu_tupian': shensu_images,
            'create_time': record.create_time,
            'update_time': record.update_time,
        }

        return Response({'code': 0, 'data': data})



from django.db import transaction
from decimal import Decimal

class KefuPunishmentActionView(APIView):
    """
    客服同意/驳回处罚接口
    请求：POST /yonghu/kefu_cf_action
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID",
        "action": 1(同意) / 2(驳回),
        "reject_reason": "驳回理由（驳回时必填）"
    }
    认证：JWT
    返回：code=0 成功
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()
        action = request.data.get('action')
        reject_reason = request.data.get('reject_reason', '').strip()

        if not phone or not dingdan_id or action not in [1, 2]:
            return Response({'code': 401, 'msg': '参数错误'}, status=status.HTTP_400_BAD_REQUEST)

        if action == 2 and not reject_reason:
            return Response({'code': 400, 'msg': '驳回理由不能为空'}, status=status.HTTP_400_BAD_REQUEST)

        # 客服身份验证（完整验证，此处略）
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        if current_user.user_type != 'kefu':
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        try:
            kefu = current_user.kefu_profile
            if kefu.zhuangtai != 1:
                return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        except ObjectDoesNotExist:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 查询待处理的处罚记录（状态0或3）
        try:
            record = Chufajilu.objects.filter(
                dingdan_id=dingdan_id,
                sqzhuangtai__in=[0, 3]
            ).order_by('-create_time').first()
            if not record:
                exists = Chufajilu.objects.filter(dingdan_id=dingdan_id).exists()
                if exists:
                    return Response({'code': 400, 'msg': '该处罚记录已处理'}, status=status.HTTP_400_BAD_REQUEST)
                else:
                    return Response({'code': 404, 'msg': '处罚记录不存在'}, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            logger.error(f"查询处罚记录失败: {e}")
            return Response({'code': 500, 'msg': '服务器内部错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        with transaction.atomic():
            # 处理重复记录：同一订单的其他待处理/申诉中记录标记为驳回
            duplicate_records = Chufajilu.objects.filter(
                dingdan_id=dingdan_id,
                sqzhuangtai__in=[0, 3]
            ).exclude(id=record.id)
            for dup in duplicate_records:
                dup.sqzhuangtai = 2
                dup.chuliid = phone
                dup.bhliyou = "系统自动驳回：存在重复处罚记录"
                dup.save()
                logger.info(f"自动驳回重复处罚记录 ID={dup.id}")

            if action == 1:  # 同意
                # 可选验证打手存在
                if record.dashouid:
                    try:
                        dashou = UserDashou.objects.get(user__yonghuid=record.dashouid)
                    except UserDashou.DoesNotExist:
                        return Response({'code': 400, 'msg': '被处罚打手不存在'}, status=status.HTTP_400_BAD_REQUEST)

                record.sqzhuangtai = 1
                record.chuliid = phone
                record.save()

                # 更新商家订单扩展表
                try:
                    dingdan = Dingdan.objects.get(dingdan_id=dingdan_id)
                    if hasattr(dingdan, 'shangjia_kuozhan'):
                        dingdan.shangjia_kuozhan.sqzhuangtai = 1
                        dingdan.shangjia_kuozhan.save()
                except Exception as e:
                    logger.warning(f"更新商家扩展表失败: {e}")

            elif action == 2:  # 驳回
                # 返还积分
                if record.jifen > 0 and record.dashouid:
                    try:
                        dashou = UserDashou.objects.get(user__yonghuid=record.dashouid)
                        if dashou.jifen <= 1000:  # 安全限制
                            dashou.jifen += record.jifen
                            dashou.save()
                            logger.info(f"驳回处罚，打手{record.dashouid}返还积分{record.jifen}")
                        else:
                            logger.warning(f"打手积分异常({dashou.jifen})，不再返还")
                    except UserDashou.DoesNotExist:
                        logger.warning(f"打手{record.dashouid}不存在，无法返还积分")

                record.sqzhuangtai = 2
                record.chuliid = phone
                record.bhliyou = reject_reason
                record.save()

                try:
                    dingdan = Dingdan.objects.get(dingdan_id=dingdan_id)
                    if hasattr(dingdan, 'shangjia_kuozhan'):
                        dingdan.shangjia_kuozhan.sqzhuangtai = 2
                        dingdan.shangjia_kuozhan.bhliyou = reject_reason
                        dingdan.shangjia_kuozhan.save()
                except Exception as e:
                    logger.warning(f"更新商家扩展表失败: {e}")

        return Response({'code': 0, 'msg': '处理成功'})



'''class KefuWithdrawListView(APIView):
    """
    客服获取提现审核列表接口
    请求：POST /yonghu/kefu_txsh_list
    参数：{
        "phone": "客服手机号",
        "page": 1,
        "page_size": 20,
        "status": 1(待审核)/2(已处理),
        "type": 1(打手)/2(管事) 可选,
        "payment": 1(微信)/2(支付宝) 可选,
        "search_uid": "用户ID搜索" 可选,
        "date": "YYYY-MM-DD" 可选 按创建日期筛选
    }
    认证：JWT
    返回：{
        "code": 0,
        "data": {
            "list": [提现记录],
            "total": 总数,
            "stats": {
                "total": 总记录,
                "awaiting": 待审核数,
                "processed": 已处理数
            }
        }
    }
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        phone = request.data.get('phone', '').strip()
        try:
            page = int(request.data.get('page', 1))
            page_size = int(request.data.get('page_size', 20))
        except ValueError:
            return Response({'code': 400, 'msg': '分页参数错误'}, status=status.HTTP_400_BAD_REQUEST)

        status_filter = request.data.get('status')  # 1待审核 2已处理
        type_filter = request.data.get('type')
        payment_filter = request.data.get('payment')
        search_uid = request.data.get('search_uid', '').strip()
        date_filter = request.data.get('date', '').strip()

        if not phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 客服身份验证
        current_user = request.user
        # 1. 获取前端参数
        username = request.data.get('phone', '').strip()
        if not username:
            return Response({'code': 400, 'msg': '缺少username'})

        # 2. 公共权限校验
        kefu, permissions = verify_kefu_permission(request, username)
        if kefu is None:
            return permissions

        # 3. 检查平台订单管理权限（002ab）
        if '005bb' not in permissions:
            return Response({'code': 403, 'msg': '您无权查看平台订单列表'})

        # 构建查询条件
        q = Q()

        if status_filter == 1:
            q &= Q(zhuangtai=1)
        elif status_filter == 2:
            q &= Q(zhuangtai__in=[2, 3])

        if type_filter:
            try:
                q &= Q(leixing=int(type_filter))
            except ValueError:
                pass

        if payment_filter:
            try:
                q &= Q(fangshi=int(payment_filter))
            except ValueError:
                pass

        if search_uid:
            q &= Q(yonghuid=search_uid)

        if date_filter:
            q &= Q(create_time__date=date_filter)

        # 统计信息（整体，不考虑分页）
        stats = {
            'total': Tixianjilu.objects.filter(q).count(),
            'awaiting': Tixianjilu.objects.filter(q & Q(zhuangtai=1)).count(),
            'processed': Tixianjilu.objects.filter(q & Q(zhuangtai__in=[2, 3])).count(),
        }

        # 分页查询
        total = Tixianjilu.objects.filter(q).count()
        queryset = Tixianjilu.objects.filter(q).order_by('create_time')  # 按申请时间升序
        records = queryset[(page-1)*page_size : page*page_size]

        # 构建返回列表
        list_data = []
        for item in records:
            list_data.append({
                'id': item.id,
                'yonghuid': item.yonghuid,
                'avatar': item.avatar or '',
                'phone': item.phone or '',
                'nicheng': item.nicheng or '',
                'leixing': item.leixing,
                'zhifu': item.zhifu or '',
                'skzhanghao': item.skzhanghao or '',
                'jine': str(item.jine) if item.jine else '0.00',
                'zhuangtai': item.zhuangtai,
                'fangshi': item.fangshi,
                'shenheid': item.shenheid or '',
                'bhliyou': item.bhliyou or '',
                'create_time': item.create_time,
                'update_time': item.update_time,
            })

        return Response({
            'code': 0,
            'data': {
                'list': list_data,
                'total': total,
                'stats': stats
            }
        })'''


# yonghu/views.py
import logging
import sys
from django.db import DatabaseError
from django.db.models import Q, Sum
from yonghu.models import Tixianjilu, TixianShenheJilu

kefu_txsh_list_logger = logging.getLogger('yonghu.kefu_txsh_list')
if not kefu_txsh_list_logger.handlers:
    _console_handler = logging.StreamHandler(sys.stderr)
    _console_handler.setFormatter(logging.Formatter(
        '[%(asctime)s] %(levelname)s %(name)s: %(message)s'
    ))
    kefu_txsh_list_logger.addHandler(_console_handler)
    kefu_txsh_list_logger.setLevel(logging.DEBUG)
    kefu_txsh_list_logger.propagate = False

_TIXIAN_LIST_BASE_FIELDS = (
    'id', 'yonghuid', 'avatar', 'phone', 'nicheng', 'leixing',
    'zhifu', 'skzhanghao', 'jine', 'zhuangtai', 'fangshi',
    'shenheid', 'bhliyou', 'create_time', 'update_time',
)
_TIXIAN_LIST_AUDIT_FIELDS = ('shenhe_jilu_id', 'shenhe_danhao')


class KefuWithdrawListView(APIView):
    """
    客服获取提现审核列表接口
    请求：POST /yonghu/kefu_txsh_list
    参数：{
        "phone": "客服手机号",
        "page": 1,
        "page_size": 20,
        "status": 1(待审核)/2(已处理),
        "type": 1(打手佣金)/2(管事分红)/3(组长分红)/4(审核官分佣)/5(打手押金)/6(商家余额),  可选
        "payment": 1(微信)/2(支付宝) 可选,
        "search_uid": "用户ID搜索" 可选,
        "date": "YYYY-MM-DD" 可选,
        "min_amount": 0,       # 最小提现金额（元）可选
        "max_amount": 999999,  # 最大提现金额（元）可选
        "dakuan_mode": 1       # 打款方式：1手动打款 2自动打款，可选
    }
    认证：JWT
    返回：{
        "code": 0,
        "data": {
            "list": [提现记录],
            "total": 总数,
            "stats": {
                "total": 总记录数,
                "awaiting": 待审核数,
                "processed": 已处理数,
                "total_amount": "总金额（元）"
            }
        }
    }
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def _safe_request_params(self, request):
        try:
            return dict(request.data)
        except Exception:
            return {'raw': str(request.data)}

    def _shenhe_jilu_field_available(self):
        """探测 shenhe_jilu_id 字段是否已在数据库中就绪"""
        try:
            Tixianjilu.objects.values_list('shenhe_jilu_id', flat=True).first()
            return True
        except DatabaseError as e:
            kefu_txsh_list_logger.error(
                'kefu_txsh_list: shenhe_jilu_id 字段不可用，将按旧表结构查询: %s', e,
                exc_info=True,
            )
            return False

    def _list_queryset(self, q, shenhe_field_ok):
        """字段未迁移时 only 旧字段，避免 SELECT 不存在的列导致 500"""
        fields = _TIXIAN_LIST_BASE_FIELDS + (
            _TIXIAN_LIST_AUDIT_FIELDS if shenhe_field_ok else ()
        )
        return Tixianjilu.objects.filter(q).only(*fields)

    def _resolve_row_dakuan_mode(self, item, audit_mode_map, shenhe_field_ok):
        """无关联审核或审核表未标记自动 → 默认手动(1)"""
        if not shenhe_field_ok:
            return 1
        sid = getattr(item, 'shenhe_jilu_id', None)
        if not sid:
            return 1
        if audit_mode_map.get(sid) == 2:
            return 2
        return 1

    def post(self, request):
        dakuan_mode_filter = request.data.get('dakuan_mode')
        req_params = self._safe_request_params(request)
        kefu_txsh_list_logger.info('kefu_txsh_list 请求开始 params=%s', req_params)

        try:
            try:
                page = int(request.data.get('page', 1))
                page_size = int(request.data.get('page_size', 20))
            except (TypeError, ValueError):
                return Response({'code': 400, 'msg': '分页参数错误'}, status=status.HTTP_400_BAD_REQUEST)

            if page < 1:
                page = 1
            if page_size < 1 or page_size > 100:
                page_size = min(max(page_size, 1), 100)

            status_filter = request.data.get('status')
            type_filter = request.data.get('type')
            payment_filter = request.data.get('payment')
            search_uid = (request.data.get('search_uid') or '').strip()
            date_filter = (request.data.get('date') or '').strip()
            min_amount = request.data.get('min_amount')
            max_amount = request.data.get('max_amount')

            phone = (request.data.get('phone') or '').strip()
            if not phone:
                return Response({'code': 401, 'msg': '缺少客服手机号'}, status=status.HTTP_401_UNAUTHORIZED)

            kefu, permissions = verify_kefu_permission(request, phone)
            if kefu is None:
                return permissions
            if '005bb' not in permissions:
                return Response({'code': 403, 'msg': '您无权查看平台订单列表'})

            q = Q()

            try:
                status_val = int(status_filter) if status_filter is not None and str(status_filter).strip() != '' else None
            except (TypeError, ValueError):
                status_val = None

            try:
                dakuan_mode_val = int(dakuan_mode_filter) if dakuan_mode_filter is not None and str(dakuan_mode_filter).strip() != '' else None
            except (TypeError, ValueError):
                dakuan_mode_val = None

            # 未传打款方式参数 → 默认手动打款(1)
            effective_dakuan = dakuan_mode_val if dakuan_mode_val in (1, 2) else 1

            if status_val == 1:
                q &= Q(zhuangtai=1)
            elif status_val == 2:
                if effective_dakuan == 2:
                    q &= Q(zhuangtai__in=[2, 3, 4, 5, 6])
                else:
                    q &= Q(zhuangtai__in=[2, 3])

            if type_filter is not None and str(type_filter).strip() != '':
                try:
                    type_val = int(type_filter)
                    if type_val in [1, 2, 3, 4, 5, 6]:
                        q &= Q(leixing=type_val)
                except (TypeError, ValueError):
                    pass

            if payment_filter is not None and str(payment_filter).strip() != '':
                try:
                    payment_val = int(payment_filter)
                    if payment_val in [1, 2]:
                        q &= Q(fangshi=payment_val)
                except (TypeError, ValueError):
                    pass

            if search_uid:
                q &= Q(yonghuid=search_uid)

            if date_filter:
                q &= Q(update_time__date=date_filter)

            if min_amount is not None and str(min_amount).strip() != '':
                try:
                    q &= Q(jine__gte=float(min_amount))
                except (TypeError, ValueError):
                    pass
            if max_amount is not None and str(max_amount).strip() != '':
                try:
                    q &= Q(jine__lte=float(max_amount))
                except (TypeError, ValueError):
                    pass

            shenhe_field_ok = self._shenhe_jilu_field_available()
            if shenhe_field_ok:
                if effective_dakuan == 2:
                    q &= Q(shenhe_jilu_id__isnull=False)
                else:
                    q &= Q(shenhe_jilu_id__isnull=True)
            elif effective_dakuan == 2:
                kefu_txsh_list_logger.warning('kefu_txsh_list: 自动打款筛选不可用，返回空列表')
                return Response({
                    'code': 0,
                    'data': {
                        'list': [],
                        'total': 0,
                        'stats': {'total': 0, 'awaiting': 0, 'processed': 0, 'total_amount': '0.00'},
                    },
                })

            processed_statuses = [2, 3, 4, 5, 6] if effective_dakuan == 2 else [2, 3]

            base_qs = self._list_queryset(q, shenhe_field_ok)
            total_count = base_qs.count()
            awaiting_count = self._list_queryset(q & Q(zhuangtai=1), shenhe_field_ok).count()
            processed_count = self._list_queryset(
                q & Q(zhuangtai__in=processed_statuses), shenhe_field_ok,
            ).count()
            agg = base_qs.aggregate(total=Sum('jine'))
            total_amount = agg.get('total') or 0

            stats = {
                'total': total_count,
                'awaiting': awaiting_count,
                'processed': processed_count,
                'total_amount': str(round(float(total_amount), 2)),
            }

            queryset = base_qs.order_by('create_time')
            total = queryset.count()
            records = list(queryset[(page - 1) * page_size: page * page_size])

            audit_ids = [
                getattr(item, 'shenhe_jilu_id', None)
                for item in records if getattr(item, 'shenhe_jilu_id', None)
            ]
            audit_meta_map = {}
            if audit_ids:
                try:
                    from .tixian_shenhe_services import load_audit_meta_map
                    audit_meta_map = load_audit_meta_map(audit_ids)
                except Exception as e:
                    kefu_txsh_list_logger.error(
                        'kefu_txsh_list: 查询审核表信息失败: %s', e,
                        exc_info=True,
                    )

            audit_mode_map = {
                aid: meta.get('dakuan_mode', 2) for aid, meta in audit_meta_map.items()
            }
            list_data = []
            for item in records:
                shenhe_jilu_id = getattr(item, 'shenhe_jilu_id', None) if shenhe_field_ok else None
                shenhe_danhao = (getattr(item, 'shenhe_danhao', None) or '') if shenhe_field_ok else ''
                if shenhe_jilu_id and not shenhe_danhao:
                    shenhe_danhao = audit_meta_map.get(shenhe_jilu_id, {}).get('shenhe_danhao', '')
                list_data.append({
                    'id': item.id,
                    'shenhe_jilu_id': shenhe_jilu_id,
                    'shenhe_danhao': shenhe_danhao,
                    'yonghuid': item.yonghuid,
                    'avatar': item.avatar or '',
                    'phone': item.phone or '',
                    'nicheng': item.nicheng or '',
                    'leixing': item.leixing,
                    'zhifu': item.zhifu or '',
                    'skzhanghao': item.skzhanghao or '',
                    'jine': str(item.jine) if item.jine is not None else '0.00',
                    'zhuangtai': item.zhuangtai,
                    'fangshi': item.fangshi,
                    'dakuan_mode': self._resolve_row_dakuan_mode(item, audit_mode_map, shenhe_field_ok),
                    'shenheid': item.shenheid or '',
                    'bhliyou': item.bhliyou or '',
                    'create_time': item.create_time.strftime('%Y-%m-%d %H:%M:%S') if item.create_time else '',
                    'update_time': item.update_time.strftime('%Y-%m-%d %H:%M:%S') if item.update_time else '',
                })

            return Response({
                'code': 0,
                'data': {
                    'list': list_data,
                    'total': total,
                    'stats': stats,
                },
            })

        except DatabaseError as e:
            kefu_txsh_list_logger.error(
                'kefu_txsh_list 数据库错误 dakuan_mode=%s params=%s err=%s',
                dakuan_mode_filter, req_params, e,
                exc_info=True,
            )
            return Response({
                'code': 500,
                'msg': '数据库查询失败，请确认已执行 python manage.py migrate yonghu',
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        except Exception as e:
            kefu_txsh_list_logger.error(
                'kefu_txsh_list 接口异常 dakuan_mode=%s params=%s err=%s',
                dakuan_mode_filter, req_params, e,
                exc_info=True,
            )
            return Response({
                'code': 500,
                'msg': '获取提现列表失败',
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)



import logging
from decimal import Decimal
from django.core.exceptions import ObjectDoesNotExist
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser

from yonghu.models import UserMain, UserKefu, Tixianjilu, UserDashou, UserGuanshi

logger = logging.getLogger(__name__)

class KefuWithdrawDetailView(APIView):
    """
    客服获取提现详情接口
    请求：POST /yonghu/kefu_txsh_detail
    参数：{
        "phone": "客服手机号",
        "tixian_id": "提现记录ID"
    }
    认证：JWT
    返回：code=0 + 提现记录详情 + 用户扩展信息
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        phone = request.data.get('phone', '').strip()
        tixian_id = request.data.get('tixian_id')

        if not phone or not tixian_id:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 客服身份验证
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            logger.warning(f"手机号不匹配: {phone}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if current_user.user_type != 'kefu':
            logger.warning(f"用户类型非客服: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            logger.warning(f"客服扩展表不存在: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if kefu.zhuangtai != 1:
            logger.warning(f"客服账号已禁用: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 查询提现记录
        try:
            record = Tixianjilu.objects.get(id=tixian_id)
        except Tixianjilu.DoesNotExist:
            return Response({'code': 404, 'msg': '提现记录不存在'}, status=status.HTTP_404_NOT_FOUND)

        # 查询用户主表
        try:
            user = UserMain.objects.get(yonghuid=record.yonghuid)
        except UserMain.DoesNotExist:
            user = None

        # 构建基础返回数据（字段必须与前端一致）
        data = {
            'id': record.id,
            'yonghuid': record.yonghuid,
            'avatar': record.avatar or '',
            'phone': record.phone or '',
            'nicheng': record.nicheng or '',
            'leixing': record.leixing,          # 1打手 2管事
            'zhifu': record.zhifu or '',
            'skzhanghao': record.skzhanghao or '',
            'jine': str(record.jine) if record.jine else '0.00',
            'zhuangtai': record.zhuangtai,
            'fangshi': record.fangshi,
            'shenheid': record.shenheid or '',
            'bhliyou': record.bhliyou or '',
            'create_time': record.create_time,
            'update_time': record.update_time,
        }

        # 根据提现类型添加扩展信息
        if user:
            if record.leixing == 1:  # 打手
                try:
                    dashou = UserDashou.objects.get(user=user)
                    # 计算成交率和退款率
                    total = dashou.jiedanzongliang or 0
                    completed = dashou.chengjiaozongliang or 0
                    refund = dashou.tuikuanliang or 0
                    completion_rate = round((completed / total * 100) if total > 0 else 0)
                    refund_rate = round((refund / completed * 100) if completed > 0 else 0)

                    data['dashouInfo'] = {
                        'zhuangtai': dashou.zhuangtai,                     # 工作状态
                        'zaixianzhuangtai': dashou.zaixianzhuangtai,       # 在线状态
                        'zhanghaozhuangtai': dashou.zhanghaozhuangtai,     # 账号状态
                        'yue': float(dashou.yue) if dashou.yue else 0.00,  # 可提现余额
                        'zonge': float(dashou.zonge) if dashou.zonge else 0.00,  # 接单总额
                        'jifen': dashou.jifen,                             # 积分
                        'jiedanzongliang': dashou.jiedanzongliang,         # 接单总量
                        'chengjiaozongliang': dashou.chengjiaozongliang,   # 成交总量
                        'tuikuanliang': dashou.tuikuanliang,               # 退款总量
                        'completionRate': completion_rate,
                        'refundRate': refund_rate,
                    }
                except ObjectDoesNotExist:
                    data['dashouInfo'] = None
            elif record.leixing == 2:  # 管事
                try:
                    guanshi = UserGuanshi.objects.get(user=user)
                    data['guanshiInfo'] = {
                        'zhuangtai': guanshi.zhuangtai,                    # 账号状态
                        'yue': float(guanshi.yue) if guanshi.yue else 0.00,
                        'yaogingshuliang': guanshi.yaogingshuliang,        # 邀请打手总数
                        'jinrichongzhi': guanshi.jinrichongzhi,            # 今日充值
                        'jinyuechongzhi': guanshi.jinyuechongzhi,          # 今月充值
                        'chongzhifenrun': float(guanshi.chongzhifenrun) if guanshi.chongzhifenrun else 0.00,
                    }
                except ObjectDoesNotExist:
                    data['guanshiInfo'] = None

        return Response({'code': 0, 'data': data})

import logging
import json
from decimal import Decimal
from django.db import transaction
from django.utils import timezone
from django.core.exceptions import ObjectDoesNotExist
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser

from yonghu.models import UserMain, UserKefu, Tixianjilu, UserDashou, UserGuanshi

logger = logging.getLogger(__name__)

class KefuWithdrawActionView(APIView):
    """
    客服处理提现接口（同意/拒绝）—— 仅此接口处理后台审核打款
    POST /yonghu/kefu_txsh_action

    单条：{ phone, action, tixian_id, yonghuid, leixing, reason? }
    批量：{ phone, action, batch_list: [{tixian_id, yonghuid, leixing}, ...], reason? }

    自动打款(dakuan_mode=2)：同意→6待收款；拒绝→5+驳回原因+退还可到账金额(shijidaozhang)，手续费不退，不更新平台收支/每日统计
    手动打款(dakuan_mode=1)：原逻辑不变
    状态要求：Tixianjilu.zhuangtai=1 且 TixianShenheJilu.zhuangtai=1（审核中），其他状态一律拒绝
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def _verify_kefu(self, request, phone):
        if not phone:
            return None, Response({'code': 401, 'msg': '手机号不能为空'}, status=status.HTTP_400_BAD_REQUEST)
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            return None, Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        if current_user.user_type != 'kefu':
            return None, Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            return None, Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        if kefu.zhuangtai != 1:
            return None, Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        return current_user, None

    def _parse_items(self, request):
        """解析单条或 batch_list，返回 [{tixian_id, yonghuid, leixing}]"""
        batch_list = request.data.get('batch_list')
        if batch_list is not None:
            if not isinstance(batch_list, list) or len(batch_list) == 0:
                return None, Response({'code': 400, 'msg': 'batch_list 不能为空'}, status=status.HTTP_400_BAD_REQUEST)
            items = []
            for idx, row in enumerate(batch_list):
                if not isinstance(row, dict):
                    return None, Response({'code': 400, 'msg': f'batch_list[{idx}] 格式错误'}, status=status.HTTP_400_BAD_REQUEST)
                tid = row.get('tixian_id')
                yid = (row.get('yonghuid') or '').strip()
                lx = row.get('leixing')
                if not tid or not yid or lx is None:
                    return None, Response(
                        {'code': 400, 'msg': f'batch_list[{idx}] 缺少 tixian_id / yonghuid / leixing'},
                        status=status.HTTP_400_BAD_REQUEST,
                    )
                try:
                    items.append({
                        'tixian_id': int(tid),
                        'yonghuid': yid,
                        'leixing': int(lx),
                    })
                except (TypeError, ValueError):
                    return None, Response({'code': 400, 'msg': f'batch_list[{idx}] 参数格式错误'}, status=status.HTTP_400_BAD_REQUEST)
            return items, None

        tixian_id = request.data.get('tixian_id')
        if not tixian_id:
            return None, Response({'code': 400, 'msg': '提现记录ID不能为空'}, status=status.HTTP_400_BAD_REQUEST)
        yonghuid = (request.data.get('yonghuid') or '').strip()
        leixing = request.data.get('leixing')
        try:
            item = {'tixian_id': int(tixian_id), 'yonghuid': yonghuid, 'leixing': int(leixing) if leixing is not None else None}
        except (TypeError, ValueError):
            return None, Response({'code': 400, 'msg': '参数格式错误'}, status=status.HTTP_400_BAD_REQUEST)
        return [item], None

    def _process_auto_item(self, item, action, reason, kefu_user):
        """自动打款单条处理（须在 transaction.atomic 内调用）"""
        from .models import TixianShenheJilu
        from .tixian_shenhe_services import refund_balance, sync_audit_and_jilu_status

        tixian_id = item['tixian_id']
        req_yonghuid = item['yonghuid']
        req_leixing = item['leixing']

        if req_leixing not in [1, 2, 3, 4, 5, 6]:
            raise ValueError(f'提现记录{tixian_id}：提现类型无效')

        try:
            tixian = Tixianjilu.objects.select_for_update().get(id=tixian_id)
        except Tixianjilu.DoesNotExist:
            raise ValueError(f'提现记录{tixian_id}不存在')

        if tixian.yonghuid != req_yonghuid:
            raise ValueError(f'提现记录{tixian_id}：用户ID不匹配')
        if tixian.leixing != req_leixing:
            raise ValueError(f'提现记录{tixian_id}：提现类型不匹配')
        if tixian.zhuangtai != 1:
            raise ValueError(f'提现记录{tixian_id}：非审核中状态，无法处理')
        if not tixian.shenhe_jilu_id:
            raise ValueError(f'提现记录{tixian_id}：非自动打款审核记录')

        try:
            audit = TixianShenheJilu.objects.select_for_update().get(id=tixian.shenhe_jilu_id)
        except TixianShenheJilu.DoesNotExist:
            raise ValueError(f'提现记录{tixian_id}：审核记录不存在')

        if audit.yonghuid != req_yonghuid:
            raise ValueError(f'提现记录{tixian_id}：审核记录用户ID不匹配')
        if audit.leixing != req_leixing:
            raise ValueError(f'提现记录{tixian_id}：审核记录提现类型不匹配')
        if audit.zhuangtai != 1:
            raise ValueError(f'提现记录{tixian_id}：审核记录非审核中状态')

        try:
            user = UserMain.objects.select_for_update().get(yonghuid=req_yonghuid)
        except UserMain.DoesNotExist:
            raise ValueError(f'用户{req_yonghuid}不存在')

        if action == 1:
            sync_audit_and_jilu_status(audit, 6, shenhe_ren_id=kefu_user.yonghuid)
            tixian.shenheid = kefu_user.yonghuid
            tixian.save(update_fields=['shenheid', 'update_time'])
        else:
            sync_audit_and_jilu_status(
                audit, 5,
                bhliyou=reason,
                bo_hui_ren_id=kefu_user.yonghuid,
            )
            # 退还可到账金额，申请时扣的 shenqing_jine 中的手续费(shouxufei)不退
            refund_balance(user, audit.leixing, audit.shijidaozhang)
            tixian.shenheid = kefu_user.yonghuid
            tixian.bhliyou = reason
            tixian.save(update_fields=['shenheid', 'bhliyou', 'update_time'])

    def _process_manual_item(self, item, action, reason, phone):
        """手动打款单条处理（原逻辑，须在 transaction.atomic 内调用）"""
        tixian_id = item['tixian_id']
        try:
            tixian = Tixianjilu.objects.select_for_update().get(id=tixian_id)
        except Tixianjilu.DoesNotExist:
            raise ValueError(f'提现记录{tixian_id}不存在')

        req_yonghuid = item.get('yonghuid')
        req_leixing = item.get('leixing')
        if req_yonghuid and tixian.yonghuid != req_yonghuid:
            raise ValueError(f'提现记录{tixian_id}：用户ID不匹配')
        if req_leixing is not None and tixian.leixing != req_leixing:
            raise ValueError(f'提现记录{tixian_id}：提现类型不匹配')
        if tixian.zhuangtai != 1:
            raise ValueError(f'提现记录{tixian_id}：非审核中状态，无法处理')

        if getattr(tixian, 'shenhe_jilu_id', None):
            raise ValueError(f'提现记录{tixian_id}：自动打款请走自动流程')

        try:
            user = UserMain.objects.get(yonghuid=tixian.yonghuid)
        except UserMain.DoesNotExist:
            raise ValueError(f'用户{tixian.yonghuid}不存在')

        if action == 1:
            tixian.zhuangtai = 2
            try:
                from dingdan.utils import update_daily_payout
                update_daily_payout(tixian.jine)
                from peizhi.models import Szjilu
                szjilu, _ = Szjilu.objects.get_or_create(id=1)
                szjilu.zongsy -= tixian.jine
                szjilu.zongzc += tixian.jine
                szjilu.jrzc += tixian.jine
                szjilu.update_time = timezone.now()
                szjilu.save()
            except Exception as e:
                logger.error(f'更新收支记录失败: {e}')
        else:
            from .tixian_shenhe_services import refund_balance
            try:
                refund_balance(user, tixian.leixing, tixian.jine)
            except ValueError as e:
                raise ValueError(str(e))
            tixian.zhuangtai = 3
            tixian.bhliyou = reason

        tixian.shenheid = phone
        tixian.update_time = timezone.now()
        tixian.save()

    def post(self, request):
        logger.info(f'接收到提现处理请求，数据: {request.data}')

        phone = request.data.get('phone', '').strip()
        action_raw = request.data.get('action')
        reason = request.data.get('reason', '').strip()

        try:
            action = int(action_raw)
        except (TypeError, ValueError):
            return Response({'code': 400, 'msg': 'action 参数必须为数字'}, status=status.HTTP_400_BAD_REQUEST)
        if action not in [1, 2]:
            return Response({'code': 400, 'msg': 'action 必须为1(同意)或2(拒绝)'}, status=status.HTTP_400_BAD_REQUEST)
        if action == 2 and not reason:
            return Response({'code': 400, 'msg': '拒绝提现时理由不能为空'}, status=status.HTTP_400_BAD_REQUEST)

        kefu_user, err_resp = self._verify_kefu(request, phone)
        if err_resp:
            return err_resp

        items, err_resp = self._parse_items(request)
        if err_resp:
            return err_resp

        is_batch = isinstance(request.data.get('batch_list'), list) and len(request.data.get('batch_list')) > 0

        try:
            with transaction.atomic():
                for item in items:
                    tixian_id = item['tixian_id']
                    try:
                        tixian_probe = Tixianjilu.objects.select_for_update().get(id=tixian_id)
                    except Tixianjilu.DoesNotExist:
                        raise ValueError(f'提现记录{tixian_id}不存在')

                    # 有关联审核记录(shenhe_jilu_id)即为 zddksh 自动打款，不依赖 dakuan_mode 字段
                    is_auto = bool(getattr(tixian_probe, 'shenhe_jilu_id', None))

                    if is_auto:
                        self._process_auto_item(item, action, reason, kefu_user)
                    else:
                        if is_batch:
                            raise ValueError(f'提现记录{tixian_id}：批量操作仅支持自动打款记录')
                        self._process_manual_item(item, action, reason, phone)

        except ValueError as e:
            return Response({'code': 400, 'msg': str(e)}, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            logger.error(f'处理提现事务失败: {e}', exc_info=True)
            return Response({'code': 500, 'msg': f'处理失败: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        msg = '批量处理成功' if is_batch and len(items) > 1 else '处理成功'
        return Response({'code': 0, 'msg': msg, 'data': {'count': len(items)}})





class KefuPunishView(APIView):
    """
    客服处罚打手接口
    请求：POST /yonghu/kefuchufa
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID",
        "reason": "处罚原因（可选）"
    }
    认证：JWT
    返回：code=0 成功
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()
        reason = request.data.get('reason', '').strip()

        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '参数不完整'}, status=status.HTTP_400_BAD_REQUEST)

        # 2. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'phone', '') != phone:
            logger.warning(f"手机号不匹配: {phone}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if current_user.user_type != 'kefu':
            logger.warning(f"用户类型非客服: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        try:
            kefu = current_user.kefu_profile
        except ObjectDoesNotExist:
            logger.warning(f"客服扩展表不存在: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if kefu.zhuangtai != 1:
            logger.warning(f"客服账号已禁用: {current_user.yonghuid}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询订单
        try:
            order = Dingdan.objects.get(dingdan_id=dingdan_id)
        except Dingdan.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)

        # 4. 获取打手ID
        dashou_id = order.jiedan_dashou_id
        if not dashou_id:
            return Response({'code': 400, 'msg': '订单未接单，无法处罚打手'}, status=status.HTTP_400_BAD_REQUEST)

        # 5. 查询打手
        try:
            dashou_user = UserMain.objects.get(yonghuid=dashou_id)
            dashou = dashou_user.dashou_profile
        except UserMain.DoesNotExist:
            return Response({'code': 404, 'msg': '打手用户不存在'}, status=status.HTTP_404_NOT_FOUND)
        except ObjectDoesNotExist:
            return Response({'code': 400, 'msg': '该用户不是打手'}, status=status.HTTP_400_BAD_REQUEST)
        # 🔴 新增：检查该订单是否已经存在处罚记录
        if Chufajilu.objects.filter(dingdan_id=dingdan_id).exists():
            logger.warning(f"订单 {dingdan_id} 已有处罚记录，禁止再次处罚")
            return Response({'code': 400, 'msg': '该订单已被处罚过，不能重复处罚'},
                            status=status.HTTP_400_BAD_REQUEST)

        # 6. 使用事务
        with transaction.atomic():
            # 创建处罚记录（积分扣除5分）
            jifen = 5
            chufa = Chufajilu.objects.create(
                dashouid=dashou_id,
                qingqiuid=phone,           # 客服手机号作为请求人
                cfliyou=reason or '',
                sqzhuangtai=0,              # 待处理
                jifen=jifen,
                dingdan_id=dingdan_id,
            )

            # 扣除打手积分
            if dashou.jifen >= jifen:
                dashou.jifen -= jifen
            else:
                dashou.jifen = 0
            dashou.save()

            # 可选：更新订单的 clkf 字段记录处理客服
            order.clkf = phone
            order.save()

        return Response({'code': 0, 'msg': '处罚成功'})


from django.db import transaction
from django.contrib.auth.hashers import make_password

class AdKftjView(APIView):
    """
    添加客服接口
    权限：管理员JWT
    请求：POST /yonghu/adkftj
    参数：{
        "zhanghao": "管理员账号",
        "phone": "客服手机号（必填）",
        "password": "密码（必填）",
        "erjimima": "二级密码（必填）",
        "nicheng": "昵称（可选）"
    }
    返回：code=0
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 参数
        zhanghao = request.data.get('zhanghao', '').strip()
        phone = request.data.get('phone', '').strip()
        password = request.data.get('password', '').strip()
        erjimima = request.data.get('erjimima', '').strip()
        nicheng = request.data.get('nicheng', '').strip()

        if not all([zhanghao, phone, password, erjimima]):
            return Response({'code': 400, 'message': '手机号、密码、二级密码不能为空'})

        # 2. 管理员验证（同前）
        current_user = request.user
        if current_user.phone != zhanghao or current_user.user_type != 'admin':
            return Response({'code': 401, 'message': '身份验证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        try:
            admin_profile = current_user.admin_profile
        except:
            return Response({'code': 401, 'message': '身份验证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 检查手机号是否已被使用
        #if UserMain.objects.filter(phone=phone).exists():
            #return Response({'code': 400, 'message': '该手机号已被注册'})

        # 4. 生成唯一 yonghuid
        def generate_yonghuid():
            import random, time
            for _ in range(10):
                timestamp = str(int(time.time()))[-5:]
                rand = str(random.randint(0, 99)).zfill(2)
                uid = timestamp + rand
                if len(uid) == 7 and not UserMain.objects.filter(yonghuid=uid).exists():
                    return uid
            raise Exception('无法生成唯一用户ID')

        with transaction.atomic():
            # 创建主表用户
            user = UserMain.objects.create(
                yonghuid=generate_yonghuid(),
                phone=phone,
                password=password,
                user_type='kefu',
                openid=f'kefu_{phone}'  # 临时openid
            )
            # 创建客服扩展表
            kefu = UserKefu.objects.create(
                user=user,
                nicheng=nicheng or f'客服{user.yonghuid}',
                erjimima=erjimima,  # 建议实际项目中加密存储
                zhuangtai=1,
                jinrichuli=0,
                jinyuechuli=0,
                zongchuli=0
            )

        return Response({'code': 0, 'message': '添加成功'})



from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser
from django.db.models import Q
import logging

from yonghu.models import UserMain, UserKefu, AdminProfile

logger = logging.getLogger(__name__)

class AdKfglView(APIView):
    """
    客服管理列表接口
    权限：管理员JWT
    请求：POST /yonghu/adkfgl
    参数：{
        "zhanghao": "管理员账号",
        "keyword": "搜索关键词（可选，匹配客服ID或昵称）"
    }
    返回：{
        "code": 0,
        "data": {
            "list": [客服对象...]
        }
    }
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 参数获取
        zhanghao = request.data.get('zhanghao', '').strip()
        keyword = request.data.get('keyword', '').strip()

        if not zhanghao:
            return Response({'code': 400, 'message': '参数不完整'}, status=status.HTTP_400_BAD_REQUEST)

        # 2. 管理员身份验证
        current_user = request.user
        if not hasattr(current_user, 'phone') or str(current_user.phone) != zhanghao:
            return Response({'code': 401, 'message': '身份验证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if current_user.user_type != 'admin':
            return Response({'code': 401, 'message': '身份验证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        try:
            admin_profile = current_user.admin_profile
        except AttributeError:
            return Response({'code': 401, 'message': '身份验证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询所有客服（通过扩展表关联主表）
        queryset = UserKefu.objects.select_related('user').all()

        if keyword:
            queryset = queryset.filter(
                #Q(user__yonghuid__icontains=keyword) |
                Q(nicheng__icontains=keyword) |
                Q(user__phone__icontains=keyword)
            )

        # 4. 构建返回数据
        kefu_list = []
        for kefu in queryset:
            user = kefu.user
            kefu_list.append({
                'yonghuid': user.phone,
                'phone': user.phone or '',
                'nicheng': kefu.nicheng or '',
                'zhuangtai': kefu.zhuangtai,
                'jinrichuli': kefu.jinrichuli,
                'jinyuechuli': kefu.jinyuechuli,
                'zongchuli': kefu.zongchuli,
            })

        return Response({
            'code': 0,
            'data': {'list': kefu_list}
        })





class AdKfxgView(APIView):
    """
    修改客服信息接口
    权限：管理员JWT
    请求：POST /yonghu/adkfxg
    参数：{
        "zhanghao": "管理员账号",
        "uid": "客服ID (yonghuid)",
        "nicheng": "新昵称（可选）",
        "phone": "新手机号（可选）",
        "password": "新密码（可选）",
        "erjimima": "新二级密码（可选）",
        "zhuangtai": 0/1（可选）
    }
    返回：code=0
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        zhanghao = request.data.get('zhanghao', '').strip()
        uid = request.data.get('uid', '').strip()

        if not zhanghao or not uid:
            return Response({'code': 400, 'message': '参数不完整'})

        # 管理员验证
        current_user = request.user
        if current_user.phone != zhanghao or current_user.user_type != 'admin':
            return Response({'code': 401, 'message': '身份验证失败'})
        try:
            admin_profile = current_user.admin_profile
        except:
            return Response({'code': 401, 'message': '身份验证失败'})

        # 查询客服
        try:
            user = UserMain.objects.get(phone=uid, user_type='kefu')
            kefu = user.kefu_profile
        except (UserMain.DoesNotExist, UserKefu.DoesNotExist):
            return Response({'code': 404, 'message': '客服不存在'})

        # 更新数据
        with transaction.atomic():
            # 更新主表字段
            if 'phone' in request.data:
                new_phone = request.data.get('phone').strip()
                if new_phone and UserMain.objects.filter(phone=new_phone).exclude(phone=uid).exists():
                    return Response({'code': 400, 'message': '手机号已被使用'})
                user.phone = new_phone
            if 'password' in request.data:
                user.password = request.data['password']
            user.save()

            # 更新扩展表
            if 'nicheng' in request.data:
                kefu.nicheng = request.data['nicheng']
            if 'erjimima' in request.data:
                kefu.erjimima = request.data['erjimima']
            if 'zhuangtai' in request.data:
                kefu.zhuangtai = int(request.data['zhuangtai'])
            kefu.save()

        return Response({'code': 0, 'message': '修改成功'})




















# views_tixian_v3.py

import decimal
import json
import random
import string
import time
from datetime import date
import logging

import requests
from django.db import transaction
from django.conf import settings
from django.core.cache import cache
from django.utils import timezone
from rest_framework.views import APIView
from rest_framework import permissions, status
from rest_framework.response import Response


from houtai.utils import TixianRiTongji

from houtai.utils import update_tixian_daily_stat,decrease_tixian_daily_stat  # 引入公共方法

logger = logging.getLogger(__name__)

def generate_tixian_id():
    """生成唯一提现订单号：TX + 时间戳(13位) + 4位随机数"""
    timestamp = str(int(time.time() * 1000))
    rand = ''.join(random.choices(string.digits, k=4))
    return f'TX{timestamp}{rand}'


class TixianShenqingV3View(APIView):
    """
    自动提现收款接口（新流程第二步）
    POST /yonghu/tixiansq
    必须传 shenhe_danhao；审核状态须为 6=待收款；申请时已扣款，本接口不再扣款
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        shenhe_danhao = (request.data.get('shenhe_danhao') or '').strip()
        tixianjilu_id = request.data.get('tixianjilu_id') or request.data.get('id')
        if shenhe_danhao or tixianjilu_id:
            from .tixian_shenhe_views import process_audit_collect
            return process_audit_collect(request)
        return Response({
            'code': 7,
            'msg': '缺少提现记录或审核单号，请先提交申请并等待审核通过后再收款',
        })

    '''【已废弃留存】旧版 tixiansq：申请+扣款+打款一步完成；新流程 post() 只走 process_audit_collect，绝不调用本方法
    def _legacy_direct_withdraw(self, request):
        """【已废弃】旧版直接扣款+打款，仅作代码留存"""
        user_main = request.user
        yonghuid = user_main.yonghuid

        from utils.redis_lock import acquire_lock, release_lock

        lock_key = f"tixian_lock:{yonghuid}"
        if not acquire_lock(lock_key, timeout=10):
            return Response({'code': 429, 'msg': '操作频繁，请稍后重试'})

        try:
            leixing = request.data.get('leixing')
            jine_str = request.data.get('jine')
            if leixing is None or jine_str is None:
                return Response({'code': 1, 'msg': '缺少参数: leixing 或 jine'})

            try:
                leixing = int(leixing)
                jine = decimal.Decimal(jine_str)
            except (ValueError, decimal.InvalidOperation):
                return Response({'code': 2, 'msg': '参数格式错误'})

            if leixing not in [1, 2, 3, 4]:
                return Response({'code': 3, 'msg': '提现类型无效'})
            if jine <= 0.1:
                return Response({'code': 4, 'msg': '提现金额必须大于0.1'})

            # ========== 3. 获取费率 ==========
            try:
                if leixing == 1:
                    lilu_obj = Lilubiao.objects.get(fadanpingtai='5')
                elif leixing == 2:
                    lilu_obj = Lilubiao.objects.get(fadanpingtai='6')
                elif leixing == 3:
                    lilu_obj = Lilubiao.objects.get(fadanpingtai='8')
                elif leixing == 4:  # 🆕 考核官费率（fadanpingtai='9'）
                    lilu_obj = Lilubiao.objects.get(fadanpingtai='9')
                else:
                    return Response({'code': 5, 'msg': '未知提现类型'})
                feilv = decimal.Decimal(str(lilu_obj.lilu))
            except Lilubiao.DoesNotExist:
                return Response({'code': 5, 'msg': '费率未配置'})

            shouxufei = (jine * feilv).quantize(decimal.Decimal('0.01'))
            shijidaozhang = (jine - shouxufei).quantize(decimal.Decimal('0.01'))
            if shijidaozhang <= 0:
                return Response({'code': 6, 'msg': '提现金额过低，扣除手续费后无实际到账'})

            # ========== 4. 幂等性检查：同一用户不能有处理中的提现（状态0） ==========
            # if TixianAutoRecord.objects.filter(yonghuid=yonghuid, zhuangtai=0).exists():
            #     return Response({'code': 18, 'msg': '您有正在处理中的提现，请勿重复提交'}, status=status.HTTP_400_BAD_REQUEST)

            # ========== 5. 平台每日总额校验 ==========
            today = date.today()
            try:
                daily_total_obj = TixianRiTongji.objects.get(riqi=today, leixing=leixing)
                daily_total = daily_total_obj.total_amount
            except TixianRiTongji.DoesNotExist:
                daily_total = decimal.Decimal('0')
            try:
                total_limit_obj = TixianQuotaDefault.objects.get(leixing=leixing + 3)  # 打手->4, 管事->5, 组长->6, 考核官->7
                total_limit = total_limit_obj.default_quota
            except TixianQuotaDefault.DoesNotExist:
                total_limit = decimal.Decimal('100')
            if daily_total + shijidaozhang > total_limit:
                return Response({
                    'code': 33,
                    'msg': f'今日该角色提现总额已达上限，请明日再来'
                })

            # ========== 6. 数据库事务：扣款 + 更新个人当日提现 + 创建记录 ==========
            try:
                with transaction.atomic():
                    if leixing == 1:  # 打手
                        dashou = UserDashou.objects.select_for_update().get(user=user_main)
                        if dashou.zhanghaozhuangtai != 1:
                            return Response({'code': 8, 'msg': '打手账号被封禁'})
                        if dashou.zhuangtai != 1:
                            return Response({'code': 9, 'msg': '有订单进行中，请完成后提现'})
                        if dashou.jifen != 10:
                            return Response({'code': 10, 'msg': '积分不是10分'})
                        if dashou.yue < jine:
                            return Response({'code': 11, 'msg': f'余额不足，当前余额: {dashou.yue}'})

                        # 个人每日限额
                        if dashou.last_tixian_date != today:
                            dashou.jinritixian_jine = decimal.Decimal('0.00')
                            dashou.last_tixian_date = today
                        quota = dashou.ewai_xiane if (dashou.kaioi_ewai_xiane and dashou.ewai_xiane > 0) \
                            else TixianQuotaDefault.objects.get(leixing=1).default_quota
                        if dashou.jinritixian_jine + jine > quota:
                            return Response({
                                'code': 12,
                                'msg': f'今日提现已达个人限额，今日已提{dashou.jinritixian_jine}元，限额{quota}元'
                            })

                        # 扣款 & 累加个人当日提现
                        dashou.yue -= jine
                        dashou.jinritixian_jine += jine
                        dashou.save()
                        nicheng = dashou.nicheng or ''

                    elif leixing == 2:  # 管事
                        guanshi = UserGuanshi.objects.select_for_update().get(user=user_main)
                        if guanshi.zhuangtai != 1:
                            return Response({'code': 14, 'msg': '管事账号被封禁'})
                        if guanshi.yue < jine:
                            return Response({'code': 15, 'msg': f'余额不足，当前余额: {guanshi.yue}'})

                        if guanshi.last_tixian_date != today:
                            guanshi.jinritixian_jine = decimal.Decimal('0.00')
                            guanshi.last_tixian_date = today
                        quota = guanshi.ewai_xiane if (guanshi.kaioi_ewai_xiane and guanshi.ewai_xiane > 0) \
                            else TixianQuotaDefault.objects.get(leixing=2).default_quota
                        if guanshi.jinritixian_jine + jine > quota:
                            return Response({
                                'code': 16,
                                'msg': f'今日提现已达个人限额，今日已提{guanshi.jinritixian_jine}元，限额{quota}元'
                            })

                        guanshi.yue -= jine
                        guanshi.jinritixian_jine += jine
                        guanshi.save()
                        nicheng = '管事用户'

                    elif leixing == 3:  # 组长
                        zuzhang = UserZuzhang.objects.select_for_update().get(user=user_main)
                        if zuzhang.zhuangtai != 1:
                            return Response({'code': 30, 'msg': '组长账号被封禁'})
                        if zuzhang.ketixian_jine < jine:
                            return Response({'code': 31, 'msg': f'组长可提现金额不足，当前余额: {zuzhang.ketixian_jine}'})

                        # 组长个人每日限额（字段不同）
                        if zuzhang.last_tixian_time and zuzhang.last_tixian_time.date() != today:
                            zuzhang.jinri_tixian = decimal.Decimal('0.00')
                        elif not zuzhang.last_tixian_time:
                            zuzhang.jinri_tixian = decimal.Decimal('0.00')
                        try:
                            default_quota = TixianQuotaDefault.objects.get(leixing=3).default_quota
                        except TixianQuotaDefault.DoesNotExist:
                            default_quota = decimal.Decimal('0.00')
                        quota = zuzhang.ewai_tixian_xiane if (zuzhang.kaioi_ewai_tixian and zuzhang.ewai_tixian_xiane > 0) else default_quota
                        if zuzhang.jinri_tixian + jine > quota:
                            return Response({
                                'code': 32,
                                'msg': f'今日提现已达个人限额，今日已提{zuzhang.jinri_tixian}元，限额{quota}元'
                            })

                        zuzhang.ketixian_jine -= jine
                        zuzhang.jinri_tixian += jine
                        zuzhang.last_tixian_time = timezone.now()
                        zuzhang.save()
                        nicheng = ''

                    elif leixing == 4:  # 🆕 考核官
                        kaoheguan = UserShenheguan.objects.select_for_update().get(user=user_main)
                        # 校验1: 账号状态（zhuangtai=1正常）
                        if kaoheguan.zhuangtai != 1:
                            return Response({'code': 40, 'msg': '考核官账号已被封禁，无法提现'})
                        # 校验2: 可提现余额是否足够
                        if kaoheguan.yue < jine:
                            return Response({'code': 41, 'msg': f'考核官可提现金额不足，当前余额: {kaoheguan.yue}'})

                        # 考核官没有个人每日限额字段，跳过个人限额检查
                        # 扣款
                        kaoheguan.yue -= jine
                        kaoheguan.save()
                        nicheng = '考核官'

                    # 生成订单号，创建记录（状态0）
                    tixian_id = generate_tixian_id()
                    auto_record = TixianAutoRecord.objects.create(
                        tixian_id=tixian_id,
                        yonghuid=yonghuid,
                        leixing=leixing,
                        jine=jine,
                        shouxufei=shouxufei,
                        shijidaozhang=shijidaozhang,
                        feilv=feilv,
                        zhuangtai=0,
                    )

                # 事务结束，余额已扣，个人当日提现已累加，记录已创建

            except TixianQuotaDefault.DoesNotExist:
                return Response({'code': 17, 'msg': '默认提现限额未配置'})
            except Exception as e:
                logger.error(f"提现申请事务异常: {str(e)}", exc_info=True)
                return Response({'code': 99, 'msg': '提现申请失败，请稍后重试'})

            # ========== 7. 调用微信接口（事务外） ==========
            try:
                url = 'https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills'
                transfer_scene_id = settings.WECHAT_PAY_V3_CONFIG['TRANSFER_SCENE_ID']

                transfer_scene_report_infos = []
                if transfer_scene_id == '1005':
                    if leixing == 1:
                        role = "打手"
                        desc = "佣金提现"
                    elif leixing == 2:
                        role = "管事"
                        desc = "分红提现"
                    elif leixing == 3:
                        role = "组长"
                        desc = "分红提现"
                    elif leixing == 4:  # 🆕 考核官
                        role = "考核官"
                        desc = "分佣提现"
                    else:
                        role = "用户"
                        desc = "提现"
                    transfer_scene_report_infos = [
                        {"info_type": "岗位类型", "info_content": role},
                        {"info_type": "报酬说明", "info_content": desc}
                    ]
                elif transfer_scene_id == '1009':
                    transfer_scene_report_infos = [
                        {"info_type": "采购商品名称", "info_content": "平台服务"}
                    ]

                body = {
                    'appid': settings.WECHAT_PAY_V3_CONFIG['APPID'],
                    'out_bill_no': tixian_id,
                    'transfer_scene_id': transfer_scene_id,
                    'openid': user_main.openid,
                    'transfer_amount': int(shijidaozhang * 100),
                    'transfer_remark': f'平台提现-{yonghuid}',
                    'transfer_scene_report_infos': transfer_scene_report_infos,
                }
                body_json = json.dumps(body, separators=(',', ':'))

                auth = build_authorization('POST', url, body_json)
                headers = {
                    'Authorization': auth,
                    'Content-Type': 'application/json',
                    'Accept': 'application/json',
                    'User-Agent': 'Mozilla/5.0',
                }

                resp = requests.post(url, data=body_json, headers=headers, timeout=10)
                wx_result = resp.json()

                if resp.status_code == 200 and wx_result.get('state') == 'WAIT_USER_CONFIRM':
                    package_info = wx_result.get('package_info')
                    auto_record.wechat_package = json.dumps(package_info)
                    auto_record.save(update_fields=['wechat_package'])

                    update_tixian_daily_stat(auto_record.leixing, auto_record.shijidaozhang)

                    return Response({
                        'code': 0,
                        'msg': '提现申请成功，请确认收款',
                        'data': {
                            'tixian_id': tixian_id,
                            'package_info': package_info,
                            'shouxufei': str(shouxufei),
                            'shijidaozhang': str(shijidaozhang),
                            'current_rate': str(feilv),
                            'mch_id': settings.WECHAT_PAY_V3_CONFIG['MCHID'],
                            'app_id': settings.WECHAT_PAY_V3_CONFIG['APPID'],
                        }
                    })
                else:
                    err_msg = wx_result.get('message', wx_result.get('code', '微信接口调用失败'))
                    raise Exception(f'微信转账接口失败: {err_msg} (HTTP {resp.status_code})')

            except Exception as e:
                # 微信调用失败，回滚操作
                logger.error(f"微信调用失败: {str(e)}", exc_info=True)
                with transaction.atomic():
                    auto_record.zhuangtai = 2
                    auto_record.fail_reason = str(e)
                    auto_record.save(update_fields=['zhuangtai', 'fail_reason'])

                    if leixing == 1:
                        dashou = UserDashou.objects.select_for_update().get(user=user_main)
                        dashou.yue += jine
                        dashou.jinritixian_jine -= jine
                        dashou.save()
                    elif leixing == 2:
                        guanshi = UserGuanshi.objects.select_for_update().get(user=user_main)
                        guanshi.yue += jine
                        guanshi.jinritixian_jine -= jine
                        guanshi.save()
                    elif leixing == 3:
                        zuzhang = UserZuzhang.objects.select_for_update().get(user=user_main)
                        zuzhang.ketixian_jine += jine
                        zuzhang.jinri_tixian -= jine
                        zuzhang.save()
                    elif leixing == 4:  # 🆕 考核官回滚
                        kaoheguan = UserShenheguan.objects.select_for_update().get(user=user_main)
                        kaoheguan.yue += jine
                        kaoheguan.save()
                return Response({
                    'code': 99,
                    'msg': '运营账户资金不足，需等管理员充值后才能提现'
                })

        finally:
            release_lock(lock_key)
    '''









from utils.wechat_v3 import verify_wechat_sign, decrypt_callback_ciphertext

class TixianCallbackV3View(APIView):
    """
    微信转账结果回调接口（最终状态通知）
    处理微信异步发送的转账成功/失败结果
    """
    permission_classes = []  # 无需认证，签名验证保证安全

    def post(self, request):
        headers = request.headers
        body = request.body.decode('utf-8')

        # 1. 验证签名
        if not verify_wechat_sign(headers, body):
            return Response({'code': 'FAIL', 'message': '签名验证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 解密数据
        try:
            data = json.loads(body)
            resource = data.get('resource')
            if not resource:
                return Response({'code': 'FAIL', 'message': 'resource不存在'}, status=status.HTTP_400_BAD_REQUEST)

            associated_data = resource.get('associated_data', '')
            nonce = resource.get('nonce')
            ciphertext = resource.get('ciphertext')
            if not nonce or not ciphertext:
                return Response({'code': 'FAIL', 'message': '解密字段缺失'}, status=status.HTTP_400_BAD_REQUEST)

            plaintext = decrypt_callback_ciphertext(associated_data, nonce, ciphertext)
            callback_data = json.loads(plaintext)
        except Exception as e:
            logger.error(f"回调解密失败: {str(e)}", exc_info=True)
            return Response({'code': 'FAIL', 'message': f'解密失败: {str(e)}'}, status=status.HTTP_400_BAD_REQUEST)

        # 3. 获取关键信息
        out_bill_no = callback_data.get('out_bill_no')          # 商户提现单号（即 tixian_id）
        transfer_status = callback_data.get('transfer_status')  # SUCCESS / FAIL
        wechat_transfer_no = callback_data.get('transfer_no')   # 微信转账单号
        fail_reason = callback_data.get('fail_reason', '')

        if not out_bill_no:
            return Response({'code': 'FAIL', 'message': 'out_bill_no缺失'}, status=status.HTTP_400_BAD_REQUEST)

        # 4. 幂等处理：只更新状态为0（处理中）的记录，已最终状态不再处理
        with transaction.atomic():
            try:
                auto_record = TixianAutoRecord.objects.select_for_update().get(tixian_id=out_bill_no)
            except TixianAutoRecord.DoesNotExist:
                # 记录不存在，视为已处理，返回成功
                return Response({'code': 'SUCCESS', 'message': 'ok'})

            # 如果已经是最新状态，直接返回成功（幂等）
            if auto_record.zhuangtai != 0:
                return Response({'code': 'SUCCESS', 'message': 'already processed'})

            if transfer_status == 'SUCCESS':
                from .tixian_shenhe_services import mark_transfer_success
                mark_transfer_success(
                    auto_record,
                    wechat_transfer_no=wechat_transfer_no,
                    with_accounting=True,
                )

            else:  # transfer_status == 'FAIL'
                auto_record.zhuangtai = 2
                auto_record.fail_reason = fail_reason or '微信转账失败'
                auto_record.save(update_fields=['zhuangtai', 'fail_reason'])

                if not auto_record.shenhe_danhao:
                    logger.error('回调失败但打款记录无审核单号 bill=%s', out_bill_no)
                else:
                    # 申请时已扣款，回调失败不退余额，恢复待收款(6)可重试
                    from .models import TixianShenheJilu
                    from .tixian_shenhe_services import (
                        release_collect_quota_for_record,
                        sync_audit_and_jilu_status,
                    )
                    try:
                        audit = TixianShenheJilu.objects.select_for_update().get(
                            shenhe_danhao=auto_record.shenhe_danhao
                        )
                        audit.tixian_auto_id = None
                        audit.fail_reason = auto_record.fail_reason
                        sync_audit_and_jilu_status(audit, 6, fail_reason=auto_record.fail_reason)
                    except TixianShenheJilu.DoesNotExist:
                        logger.warning(f'回调失败但审核记录不存在: {auto_record.shenhe_danhao}')
                    release_collect_quota_for_record(auto_record)

        return Response({'code': 'SUCCESS', 'message': 'ok'})



class TixianQueRenAutoView(APIView):
    """
    用户确认提现结果
    POST /yonghu/tixianqr
    新审核流程：打款记录带 shenhe_danhao 时，确认成功同步审核表+提现记录表为 2；取消不退款（申请已扣），恢复待收款 6 可重试
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            tixian_id = request.data.get('tixian_id')
            result = request.data.get('result')  # 1成功 0失败/取消

            if not tixian_id or result is None:
                return Response({'code': 1, 'msg': '缺少参数'}, status=status.HTTP_400_BAD_REQUEST)

            try:
                result = int(result)
            except ValueError:
                return Response({'code': 2, 'msg': '参数格式错误'}, status=status.HTTP_400_BAD_REQUEST)

            if result not in [0, 1]:
                return Response({'code': 3, 'msg': 'result值无效'}, status=status.HTTP_400_BAD_REQUEST)

            user_main = request.user

            with transaction.atomic():
                try:
                    auto_record = TixianAutoRecord.objects.select_for_update().get(
                        tixian_id=tixian_id,
                        yonghuid=user_main.yonghuid,
                    )
                except TixianAutoRecord.DoesNotExist:
                    return Response({'code': 4, 'msg': '提现记录不存在'}, status=status.HTTP_404_NOT_FOUND)

                if result == 1:
                    if auto_record.zhuangtai == 1:
                        return Response({'code': 0, 'msg': '提现成功', 'data': None})

                    if auto_record.zhuangtai != 0:
                        return Response({'code': 5, 'msg': '该提现已处理'})

                    from .tixian_shenhe_services import mark_transfer_success
                    mark_transfer_success(auto_record, with_accounting=True)

                    return Response({'code': 0, 'msg': '提现成功', 'data': None})

                # 用户取消或失败
                auto_record.zhuangtai = 2
                auto_record.fail_reason = '用户取消收款'
                auto_record.save(update_fields=['zhuangtai', 'fail_reason'])

                if not auto_record.shenhe_danhao:
                    logger.error('确认取消但打款记录无审核单号 bill=%s', tixian_id)
                    return Response({'code': 5, 'msg': '该提现已处理'})

                # 申请时已扣款，取消不退余额，审核单恢复 6 待收款，可再次点收款
                from .models import TixianShenheJilu
                from .tixian_shenhe_services import (
                    release_collect_quota_for_record,
                    sync_audit_and_jilu_status,
                )
                try:
                    audit = TixianShenheJilu.objects.select_for_update().get(
                        shenhe_danhao=auto_record.shenhe_danhao,
                    )
                    audit.tixian_auto_id = None
                    sync_audit_and_jilu_status(
                        audit, 6,
                        fail_reason='用户取消收款，可重新发起',
                    )
                except TixianShenheJilu.DoesNotExist:
                    logger.warning(f'确认取消但审核记录不存在: {auto_record.shenhe_danhao}')
                release_collect_quota_for_record(auto_record)

                return Response({'code': 0, 'msg': '提现已取消', 'data': None})

        except Exception as e:
            logger.error(f'提现确认异常: {str(e)}', exc_info=True)
            return Response({'code': 99, 'msg': '系统错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)





# views_tixian_v3.py
import decimal
import json
import random
import string
import time
from datetime import date

import requests
from django.db import transaction
from django.conf import settings
from rest_framework.views import APIView
from rest_framework import permissions, status
from rest_framework.response import Response
from peizhi.models import TixianQuotaDefault
from .models import UserMain, UserDashou, UserGuanshi, Tixianjilu, TixianAutoRecord
from utils.wechat_v3 import build_authorization


'''def generate_tixian_id():
    """生成唯一提现订单号：TX + 时间戳(13位) + 4位随机数"""
    timestamp = str(int(time.time() * 1000))
    rand = ''.join(random.choices(string.digits, k=4))
    return f'TX{timestamp}{rand}'

class TixianShenqingV3View(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        # ---------- 1. 获取用户 ----------
        user_main = request.user
        yonghuid = user_main.yonghuid

        # ---------- 2. 参数获取与校验 ----------
        leixing = request.data.get('leixing')
        jine_str = request.data.get('jine')
        if leixing is None or jine_str is None:
            return Response({'code': 1, 'msg': '缺少参数: leixing 或 jine'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            leixing = int(leixing)
            jine = decimal.Decimal(jine_str)
        except (ValueError, decimal.InvalidOperation):
            return Response({'code': 2, 'msg': '参数格式错误'}, status=status.HTTP_400_BAD_REQUEST)

        # 🔥【修改】支持组长提现类型 3
        if leixing not in [1, 2, 3]:
            return Response({'code': 3, 'msg': '提现类型无效'}, status=status.HTTP_400_BAD_REQUEST)
        if jine <= 0.1:
            return Response({'code': 4, 'msg': '提现金额必须大于0.1'}, status=status.HTTP_400_BAD_REQUEST)

        # ---------- 3. 获取费率 ----------
        try:
            if leixing == 1:
                lilu_obj = Lilubiao.objects.get(fadanpingtai='5')
            elif leixing == 2:
                lilu_obj = Lilubiao.objects.get(fadanpingtai='6')
            else:  # leixing == 3 组长提现
                lilu_obj = Lilubiao.objects.get(fadanpingtai='8')
            feilv = decimal.Decimal(str(lilu_obj.lilu))
        except Lilubiao.DoesNotExist:
            return Response({'code': 5, 'msg': '费率未配置'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        shouxufei = (jine * feilv).quantize(decimal.Decimal('0.01'))
        shijidaozhang = (jine - shouxufei).quantize(decimal.Decimal('0.01'))
        if shijidaozhang <= 0:
            return Response({'code': 6, 'msg': '提现金额过低，扣除手续费后无实际到账'}, status=status.HTTP_400_BAD_REQUEST)

        # ---------- 4. 幂等性检查：同一用户不能有处理中的提现（状态0） ----------
        if TixianAutoRecord.objects.filter(yonghuid=yonghuid, zhuangtai=0).exists():
            return Response({'code': 18, 'msg': '您有正在处理中的提现，请勿重复提交'}, status=status.HTTP_400_BAD_REQUEST)

        # ---------- 5. 数据库事务：扣款 + 创建记录 ----------
        try:
            with transaction.atomic():
                if leixing == 1:
                    dashou = UserDashou.objects.select_for_update().get(user=user_main)

                    if dashou.zhanghaozhuangtai != 1:
                        return Response({'code': 8, 'msg': '打手账号被封禁'}, status=status.HTTP_400_BAD_REQUEST)
                    if dashou.zhuangtai != 1:
                        return Response({'code': 9, 'msg': '有订单进行中，请完成后提现'}, status=status.HTTP_400_BAD_REQUEST)
                    if dashou.jifen != 10:
                        return Response({'code': 10, 'msg': '积分不足10分'}, status=status.HTTP_400_BAD_REQUEST)
                    if dashou.yue < jine:
                        return Response({'code': 11, 'msg': f'余额不足，当前余额: {dashou.yue}'}, status=status.HTTP_400_BAD_REQUEST)

                    today = date.today()
                    if dashou.last_tixian_date != today:
                        dashou.jinritixian_jine = decimal.Decimal('0.00')
                        dashou.last_tixian_date = today

                    quota = dashou.ewai_xiane if dashou.kaioi_ewai_xiane and dashou.ewai_xiane > 0 \
                        else TixianQuotaDefault.objects.get(leixing=1).default_quota

                    if dashou.jinritixian_jine + jine > quota:
                        return Response({
                            'code': 12,
                            'msg': f'今日提现已达限额，今日已提{dashou.jinritixian_jine}元，限额{quota}元'
                        }, status=status.HTTP_400_BAD_REQUEST)

                    dashou.yue -= jine
                    dashou.save()
                    nicheng = dashou.nicheng or ''

                elif leixing == 2:
                    guanshi = UserGuanshi.objects.select_for_update().get(user=user_main)

                    if guanshi.zhuangtai != 1:
                        return Response({'code': 14, 'msg': '管事账号被封禁'}, status=status.HTTP_400_BAD_REQUEST)
                    if guanshi.yue < jine:
                        return Response({'code': 15, 'msg': f'余额不足，当前余额: {guanshi.yue}'}, status=status.HTTP_400_BAD_REQUEST)

                    today = date.today()
                    if guanshi.last_tixian_date != today:
                        guanshi.jinritixian_jine = decimal.Decimal('0.00')
                        guanshi.last_tixian_date = today

                    quota = guanshi.ewai_xiane if guanshi.kaioi_ewai_xiane and guanshi.ewai_xiane > 0 \
                        else TixianQuotaDefault.objects.get(leixing=2).default_quota

                    if guanshi.jinritixian_jine + jine > quota:
                        return Response({
                            'code': 16,
                            'msg': f'今日提现已达限额，今日已提{guanshi.jinritixian_jine}元，限额{quota}元'
                        }, status=status.HTTP_400_BAD_REQUEST)

                    guanshi.yue -= jine
                    guanshi.save()
                    nicheng = '管事用户'

                # 🔥【新增】组长提现分支
                else:  # leixing == 3
                    zuzhang = UserZuzhang.objects.select_for_update().get(user=user_main)

                    if zuzhang.zhuangtai != 1:
                        return Response({'code': 30, 'msg': '组长账号被封禁'}, status=status.HTTP_400_BAD_REQUEST)
                    if zuzhang.ketixian_jine < jine:
                        return Response({'code': 31, 'msg': f'组长可提现金额不足，当前余额: {zuzhang.ketixian_jine}'},
                                        status=status.HTTP_400_BAD_REQUEST)

                    # 组长每日限额（类似打手/管事）
                    today = date.today()
                    # last_tixian_time 是 DateTimeField，需要判断日期
                    if zuzhang.last_tixian_time and zuzhang.last_tixian_time.date() != today:
                        zuzhang.jinri_tixian = decimal.Decimal('0.00')
                    elif not zuzhang.last_tixian_time:
                        zuzhang.jinri_tixian = decimal.Decimal('0.00')
                    # 获取限额配置
                    try:
                        default_quota = TixianQuotaDefault.objects.get(leixing=3).default_quota
                    except TixianQuotaDefault.DoesNotExist:
                        default_quota = decimal.Decimal('0.00')
                    quota = zuzhang.ewai_tixian_xiane if zuzhang.kaioi_ewai_tixian and zuzhang.ewai_tixian_xiane > 0 else default_quota

                    if zuzhang.jinri_tixian + jine > quota:
                        return Response({
                            'code': 32,
                            'msg': f'今日提现已达限额，今日已提{zuzhang.jinri_tixian}元，限额{quota}元'
                        }, status=status.HTTP_400_BAD_REQUEST)

                    zuzhang.ketixian_jine -= jine
                    zuzhang.jinri_tixian += jine  # 累加今日提现
                    zuzhang.last_tixian_time = timezone.now()
                    zuzhang.save()
                    nicheng = ''  # 组长暂不显示昵称

                # 生成订单号，创建提现记录（状态0）
                tixian_id = generate_tixian_id()
                auto_record = TixianAutoRecord.objects.create(
                    tixian_id=tixian_id,
                    yonghuid=yonghuid,
                    leixing=leixing,
                    jine=jine,
                    shouxufei=shouxufei,
                    shijidaozhang=shijidaozhang,
                    feilv=feilv,
                    zhuangtai=0,
                )
            # 事务结束，数据库已扣款，记录已创建，状态为0

        except TixianQuotaDefault.DoesNotExist:
            return Response({'code': 17, 'msg': '默认提现限额未配置'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        except Exception as e:
            # 数据库操作异常，直接返回错误
            return Response({'code': 99, 'msg': '提现申请失败，请稍后重试'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # ---------- 6. 调用微信接口（事务外） ----------
        try:
            url = 'https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills'
            transfer_scene_id = settings.WECHAT_PAY_V3_CONFIG['TRANSFER_SCENE_ID']

            transfer_scene_report_infos = []
            if transfer_scene_id == '1005':
                # 🔥【修改】根据提现类型设置岗位类型和报酬说明
                if leixing == 1:
                    role = "打手"
                    desc = "佣金提现"
                elif leixing == 2:
                    role = "管事"
                    desc = "分红提现"
                else:  # leixing == 3
                    role = "组长"
                    desc = "分红提现"
                transfer_scene_report_infos = [
                    {"info_type": "岗位类型", "info_content": role},
                    {"info_type": "报酬说明", "info_content": desc}
                ]
            elif transfer_scene_id == '1009':
                transfer_scene_report_infos = [
                    {"info_type": "采购商品名称", "info_content": "平台服务"}
                ]

            body = {
                'appid': settings.WECHAT_PAY_V3_CONFIG['APPID'],
                'out_bill_no': tixian_id,
                'transfer_scene_id': transfer_scene_id,
                'openid': user_main.openid,
                'transfer_amount': int(shijidaozhang * 100),
                'transfer_remark': f'平台提现-{yonghuid}',
                'transfer_scene_report_infos': transfer_scene_report_infos,
            }
            body_json = json.dumps(body, separators=(',', ':'))

            auth = build_authorization('POST', url, body_json)
            headers = {
                'Authorization': auth,
                'Content-Type': 'application/json',
                'Accept': 'application/json',
                'User-Agent': 'Mozilla/5.0',
            }

            resp = requests.post(url, data=body_json, headers=headers, timeout=10)
            wx_result = resp.json()

            if resp.status_code == 200 and wx_result.get('state') == 'WAIT_USER_CONFIRM':
                package_info = wx_result.get('package_info')
                auto_record.wechat_package = json.dumps(package_info)
                auto_record.save(update_fields=['wechat_package'])
                return Response({
                    'code': 0,
                    'msg': '提现申请成功，请确认收款',
                    'data': {
                        'tixian_id': tixian_id,
                        'package_info': package_info,
                        'shouxufei': str(shouxufei),
                        'shijidaozhang': str(shijidaozhang),
                        'current_rate': str(feilv),
                        'mch_id': settings.WECHAT_PAY_V3_CONFIG['MCHID'],
                    }
                })
            else:
                err_msg = wx_result.get('message', wx_result.get('code', '微信接口调用失败'))
                raise Exception(f'微信转账接口失败: {err_msg} (HTTP {resp.status_code})')

        except Exception as e:
            # 微信调用异常，回滚操作
            with transaction.atomic():
                auto_record.zhuangtai = 2
                auto_record.fail_reason = str(e)
                auto_record.save(update_fields=['zhuangtai', 'fail_reason'])

                if leixing == 1:
                    dashou = UserDashou.objects.select_for_update().get(user=user_main)
                    dashou.yue += jine
                    dashou.save()
                elif leixing == 2:
                    guanshi = UserGuanshi.objects.select_for_update().get(user=user_main)
                    guanshi.yue += jine
                    guanshi.save()
                else:  # leixing == 3
                    zuzhang = UserZuzhang.objects.select_for_update().get(user=user_main)
                    zuzhang.ketixian_jine += jine
                    # 注意：今日提现累加已在事务内扣减时增加，回滚时需同时恢复今日提现金额
                    zuzhang.jinri_tixian -= jine
                    zuzhang.save()

            return Response({
                'code': 99,
                'msg': '今日账户资金不足请明日再来'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)







class TixianQueRenAutoView(APIView):
    """
    用户确认提现结果通知接口
    POST /yonghu/tixianqr
    新流程须传 shenhe_danhao；成功后将审核/提现记录置为 2，禁止重复打款
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        shenhe_danhao = (request.data.get('shenhe_danhao') or '').strip()
        if shenhe_danhao:
            from .tixian_shenhe_views import process_audit_confirm
            return process_audit_confirm(request)

        try:
            tixian_id = request.data.get('tixian_id')
            result = request.data.get('result')  # 1成功 0失败/取消

            if not tixian_id or result is None:
                return Response({'code': 1, 'msg': '缺少参数'}, status=status.HTTP_400_BAD_REQUEST)

            try:
                result = int(result)
            except ValueError:
                return Response({'code': 2, 'msg': '参数格式错误'}, status=status.HTTP_400_BAD_REQUEST)

            if result not in [0, 1]:
                return Response({'code': 3, 'msg': 'result值无效'}, status=status.HTTP_400_BAD_REQUEST)

            user_main = request.user

            with transaction.atomic():
                # 获取自动提现记录，并加锁
                try:
                    auto_record = TixianAutoRecord.objects.select_for_update().get(
                        tixian_id=tixian_id,
                        yonghuid=user_main.yonghuid
                    )
                except TixianAutoRecord.DoesNotExist:
                    return Response({'code': 4, 'msg': '提现记录不存在'}, status=status.HTTP_404_NOT_FOUND)

                # 检查记录状态，只有处理中(0)才能更新
                if auto_record.zhuangtai != 0:
                    return Response({'code': 5, 'msg': '该提现已处理'}, status=status.HTTP_400_BAD_REQUEST)

                if result == 1:
                    # 用户确认成功
                    # 1. 更新自动提现记录状态为成功
                    auto_record.zhuangtai = 1
                    auto_record.save()

                    # 2. 在旧表 tixianjilu 中插入一条记录，供用户查看
                    # 获取用户信息
                    avatar = user_main.avatar or ''
                    phone = user_main.phone or ''
                    if auto_record.leixing == 1:
                        try:
                            dashou = UserDashou.objects.get(user=user_main)
                            nicheng = dashou.nicheng or ''
                        except UserDashou.DoesNotExist:
                            nicheng = ''
                    else:
                        nicheng = '管事用户'

                    # 旧表字段：注意旧表 jine 存的是实际到账金额（shijidaozhang）
                    Tixianjilu.objects.create(
                        yonghuid=user_main.yonghuid,
                        avatar=avatar,
                        phone=phone,
                        nicheng=nicheng,
                        leixing=auto_record.leixing,
                        zhifu='',  # 自动提现无收款码
                        skzhanghao='',
                        jine=auto_record.shijidaozhang,  # 实际到账金额
                        zhuangtai=2,  # 成功状态 2（根据旧表：1审核中，2成功，3失败）
                        fangshi=1,  # 默认微信？但实际自动打款，可以固定为1
                        shenheid=None,
                        bhliyou=''
                    )

                    # 3. 更新扩展表中的今日提现金额
                    today = date.today()
                    if auto_record.leixing == 1:
                        dashou = UserDashou.objects.select_for_update().get(user=user_main)
                        if dashou.last_tixian_date != today:
                            dashou.jinritixian_jine = decimal.Decimal('0.00')
                            dashou.last_tixian_date = today
                        dashou.jinritixian_jine += auto_record.jine  # 注意累加的是申请金额还是实际到账？通常累加申请金额
                        dashou.save()
                    else:
                        guanshi = UserGuanshi.objects.select_for_update().get(user=user_main)
                        if guanshi.last_tixian_date != today:
                            guanshi.jinritixian_jine = decimal.Decimal('0.00')
                            guanshi.last_tixian_date = today
                        guanshi.jinritixian_jine += auto_record.jine
                        guanshi.save()



                    try:

                        from dingdan.utils import update_daily_payout
                        update_daily_payout(auto_record.shijidaozhang)


                        szjilu = Szjilu.objects.select_for_update().get(id=1)
                        szjilu.zongsy -= auto_record.shijidaozhang
                        szjilu.zongzc += auto_record.shijidaozhang
                        szjilu.jrzc += auto_record.shijidaozhang
                        szjilu.save()
                    except Szjilu.DoesNotExist:
                        from dingdan.utils import update_daily_payout
                        update_daily_payout(auto_record.shijidaozhang)


                        Szjilu.objects.create(
                            id=1,
                            zongsy=-auto_record.shijidaozhang,
                            zongzc=auto_record.shijidaozhang,
                            jrzc=auto_record.shijidaozhang
                        )
                    except Exception as e:
                        logger.error(f"更新收支记录失败: {str(e)}")
                        raise



                    # 返回成功
                    return Response({
                        'code': 0,
                        'msg': '提现成功',
                        'data': {
                            'new_yongjin': str(dashou.yue) if auto_record.leixing == 1 else None,
                            'new_fenyong': str(guanshi.yue) if auto_record.leixing == 2 else None,
                        }
                    })

                else:
                    # 用户取消或失败
                    # 1. 将自动提现记录状态置为失败
                    auto_record.zhuangtai = 2
                    auto_record.fail_reason = '用户取消确认'
                    auto_record.save()

                    # 2. 恢复之前扣除的余额
                    if auto_record.leixing == 1:
                        dashou = UserDashou.objects.select_for_update().get(user=user_main)
                        dashou.yue += auto_record.jine
                        dashou.save()
                    else:
                        guanshi = UserGuanshi.objects.select_for_update().get(user=user_main)
                        guanshi.yue += auto_record.jine
                        guanshi.save()

                    return Response({
                        'code': 0,
                        'msg': '提现已取消',
                        'data': None
                    })

        except Exception as e:
            return Response({
                'code': 99,
                'msg': f'系统错误: {str(e)}',
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)








from utils.wechat_v3 import verify_wechat_sign, decrypt_callback_ciphertext



class TixianCallbackV3View(APIView):
    """
    微信转账结果回调接口（最终状态通知）
    处理微信异步发送的转账成功/失败结果
    """
    permission_classes = []  # 无需认证，签名验证保证安全

    def post(self, request):
        headers = request.headers
        body = request.body.decode('utf-8')

        # 1. 验证签名
        if not verify_wechat_sign(headers, body):
            return Response({'code': 'FAIL', 'message': '签名验证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 解密数据
        try:
            data = json.loads(body)
            resource = data.get('resource')
            if not resource:
                return Response({'code': 'FAIL', 'message': 'resource不存在'}, status=status.HTTP_400_BAD_REQUEST)

            associated_data = resource.get('associated_data', '')
            nonce = resource.get('nonce')
            ciphertext = resource.get('ciphertext')
            if not nonce or not ciphertext:
                return Response({'code': 'FAIL', 'message': '解密字段缺失'}, status=status.HTTP_400_BAD_REQUEST)

            plaintext = decrypt_callback_ciphertext(associated_data, nonce, ciphertext)
            callback_data = json.loads(plaintext)
        except Exception as e:
            return Response({'code': 'FAIL', 'message': f'解密失败: {str(e)}'}, status=status.HTTP_400_BAD_REQUEST)

        # 3. 获取关键信息
        out_bill_no = callback_data.get('out_bill_no')          # 商户提现单号（即 tixian_id）
        transfer_status = callback_data.get('transfer_status')  # SUCCESS / FAIL
        wechat_transfer_no = callback_data.get('transfer_no')   # 微信转账单号
        fail_reason = callback_data.get('fail_reason', '')      # 失败原因

        if not out_bill_no:
            return Response({'code': 'FAIL', 'message': 'out_bill_no缺失'}, status=status.HTTP_400_BAD_REQUEST)

        # 4. 幂等处理：只更新状态为 0（处理中）的记录，已最终状态不再处理
        with transaction.atomic():
            try:
                auto_record = TixianAutoRecord.objects.select_for_update().get(tixian_id=out_bill_no)
            except TixianAutoRecord.DoesNotExist:
                return Response({'code': 'SUCCESS', 'message': 'ok'})  # 记录不存在，视为已处理

            # 如果已经是最新状态，直接返回成功（幂等）
            if auto_record.zhuangtai in [1, 2]:
                return Response({'code': 'SUCCESS', 'message': 'already processed'})

            if transfer_status == 'SUCCESS':
                # 微信转账成功
                auto_record.zhuangtai = 1
                auto_record.wechat_transfer_no = wechat_transfer_no
                auto_record.save()

                # 更新今日已提现金额
                yonghuid = auto_record.yonghuid
                leixing = auto_record.leixing
                try:
                    user_main = UserMain.objects.get(yonghuid=yonghuid)
                except UserMain.DoesNotExist:
                    pass
                else:
                    if leixing == 1:
                        dashou = UserDashou.objects.get(user=user_main)
                        dashou.jinritixian_jine += auto_record.jine
                        dashou.save()
                    else:
                        guanshi = UserGuanshi.objects.get(user=user_main)
                        guanshi.jinritixian_jine += auto_record.jine
                        guanshi.save()

                # 向旧表插入记录（如果还未插入）
                # 由于确认接口可能已插入，这里需要检查是否已存在，避免重复
                if not Tixianjilu.objects.filter(yonghuid=yonghuid, jine=auto_record.shijidaozhang, create_time__date=date.today()).exists():
                    avatar = user_main.avatar or ''
                    phone = user_main.phone or ''
                    nicheng = '管事用户' if leixing == 2 else (UserDashou.objects.get(user=user_main).nicheng or '')
                    Tixianjilu.objects.create(
                        yonghuid=yonghuid,
                        avatar=avatar,
                        phone=phone,
                        nicheng=nicheng,
                        leixing=leixing,
                        zhifu='',
                        skzhanghao='',
                        jine=auto_record.shijidaozhang,
                        zhuangtai=2,   # 旧表成功状态为2
                        fangshi=1,
                        shenheid=None,
                        bhliyou=''
                    )

                # 更新收支记录表（id=1）

                try:

                    from dingdan.utils import update_daily_payout
                    update_daily_payout(auto_record.shijidaozhang)

                    szjilu = Szjilu.objects.select_for_update().get(id=1)
                    szjilu.zongsy -= auto_record.shijidaozhang  # 总收益减少
                    szjilu.zongzc += auto_record.shijidaozhang  # 总支出增加
                    szjilu.jrzc += auto_record.shijidaozhang  # 今日支出增加
                    szjilu.save()
                except Szjilu.DoesNotExist:
                    from dingdan.utils import update_daily_payout
                    update_daily_payout(auto_record.shijidaozhang)
                    # 如果记录不存在，创建一条
                    Szjilu.objects.create(
                        id=1,
                        zongsy=-auto_record.shijidaozhang,
                        zongzc=auto_record.shijidaozhang,
                        jrzc=auto_record.shijidaozhang
                    )
                except Exception as e:
                    logger.error(f"更新收支记录失败: {str(e)}")
                    raise  # 抛出异常让事务回滚


            else:  # transfer_status == 'FAIL'
                # 微信转账失败
                auto_record.zhuangtai = 2
                auto_record.fail_reason = fail_reason or '微信转账失败'
                auto_record.save()

                # 恢复用户余额（仅当之前已扣减）
                yonghuid = auto_record.yonghuid
                leixing = auto_record.leixing
                try:
                    user_main = UserMain.objects.get(yonghuid=yonghuid)
                except UserMain.DoesNotExist:
                    pass
                else:
                    if leixing == 1:
                        dashou = UserDashou.objects.select_for_update().get(user=user_main)
                        dashou.yue += auto_record.jine
                        dashou.save()
                    else:
                        guanshi = UserGuanshi.objects.select_for_update().get(user=user_main)
                        guanshi.yue += auto_record.jine
                        guanshi.save()

        return Response({'code': 'SUCCESS', 'message': 'ok'})'''













from .models import (
    UserMain, UserBoss, UserDashou, UserGuanshi,
    UserZuzhang
)


class WechatLoginAndGuanshiRegisterView(APIView):
    """
    未登录用户微信登录+管事注册一体化接口
    路径: /api/yonghu/zuzhangyqmzc
    方法: POST
    权限: 允许所有
    请求体: { "code": "微信登录code", "inviteCode": "组长邀请码" }
    成功返回 code: 200，数据同 GuanshiRegisterView
    """
    permission_classes = [AllowAny]

    def post(self, request):
        code = request.data.get('code', '').strip()
        yaoqingma = request.data.get('inviteCode', '').strip()

        if not code:
            return Response({'code': 400, 'msg': '微信授权码不能为空', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        if not yaoqingma:
            return Response({'code': 400, 'msg': '邀请码不能为空', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        if len(yaoqingma) > 100:
            return Response({'code': 400, 'msg': '邀请码长度超过限制', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        wechat_data = self._get_wechat_openid(code)
        if not wechat_data or 'openid' not in wechat_data:
            error_msg = wechat_data.get('errmsg', '微信授权失败')
            return Response({'code': 400, 'msg': f'微信登录失败: {error_msg}', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        openid = wechat_data['openid']
        kehuduan_ip = self._huoqu_kehuduan_ip(request)

        with transaction.atomic():
            user_main, created = UserMain.objects.select_for_update().get_or_create(
                openid=openid,
                defaults={
                    'yonghuid': self._shengcheng_yonghu_id(),
                    'user_type': 'normal',
                }
            )
            user_main.ip = kehuduan_ip
            user_main.last_login_time = timezone.now()
            user_main.save()

            if created:
                UserBoss.objects.create(user=user_main, nickname='微信用户')

            if hasattr(user_main, 'guanshi_profile'):
                return self._fanhui_xianyou_guanshi_info(user_main)

            try:
                zuzhang = UserZuzhang.objects.select_related('user').get(yaoqingma=yaoqingma)
            except UserZuzhang.DoesNotExist:
                return Response({'code': 404, 'msg': '邀请码无效或不存在', 'data': None},
                                status=status.HTTP_404_NOT_FOUND)

            if zuzhang.zhuangtai != 1:
                return Response({'code': 403, 'msg': '该邀请码对应的组长账号已被禁用', 'data': None},
                                status=status.HTTP_403_FORBIDDEN)

            zuzhang_yonghuid = zuzhang.user.yonghuid

            guanshi_yaoqingma = chuangjianYaoqingma(str(user_main.yonghuid))
            guanshi_profile = UserGuanshi.objects.create(
                user=user_main,
                yaoqingma=guanshi_yaoqingma,
                yaoqingren=zuzhang_yonghuid,
            )

            UserZuzhang.objects.filter(pk=zuzhang.pk).update(
                yaoqing_zongshu=models.F('yaoqing_zongshu') + 1
            )
            # ========== 新增：组长每日统计（邀请管事 action=1） ==========
            try:
                from houtai.utils import update_zuzhang_daily_by_action
                update_zuzhang_daily_by_action(
                    yonghuid=zuzhang_yonghuid,
                    action=1  # 1 = 邀请管事
                )
                logger.info(f"组长每日统计更新成功（邀请管事）：组长{zuzhang_yonghuid}")
            except Exception as e:
                logger.error(f"组长每日统计更新失败（邀请管事）：{str(e)}")

            if not hasattr(user_main, 'dashou_profile'):
                dashou_profile = UserDashou.objects.create(
                    user=user_main,
                    nicheng='大神',
                    chenghao='普通大神',
                    yaoqingren=zuzhang_yonghuid,
                )
            else:
                dashou_profile = user_main.dashou_profile



        refresh = RefreshToken.for_user(user_main)
        token = str(refresh.access_token)

        response_data = self._zhuangbei_fanhui_shuju(
            user_main, dashou_profile, guanshi_profile, token
        )

        return Response({'code': 200, 'msg': '登录并注册成功！', 'data': response_data})

    # ---------- 辅助方法（与接口1完全相同，完整列出以保证完整性） ----------

    def _get_wechat_openid(self, code):
        try:
            appid = getattr(settings, 'WEIXIN_APPID', '')
            secret = getattr(settings, 'WEIXIN_SECRET', '')
            if not appid or not secret:
                raise ValueError('微信配置未设置')
            url = 'https://api.weixin.qq.com/sns/jscode2session'
            params = {
                'appid': appid,
                'secret': secret,
                'js_code': code,
                'grant_type': 'authorization_code'
            }
            response = requests.get(url, params=params, timeout=10)
            result = response.json()
            if 'openid' in result:
                return result
            else:
                errcode = result.get('errcode', 'unknown')
                errmsg = result.get('errmsg', '未知错误')
                return {'errmsg': f'[{errcode}]{errmsg}'}
        except requests.exceptions.Timeout:
            logger.error('请求微信接口超时')
            return {'errmsg': '请求微信接口超时'}
        except Exception as e:
            logger.error(f'请求微信接口异常: {e}')
            return {'errmsg': f'请求微信接口异常: {str(e)}'}

    def _shengcheng_yonghu_id(self):
        for _ in range(10):
            timestamp_part = str(int(time.time()))[-5:].zfill(5)
            random_part = str(random.randint(0, 99)).zfill(2)
            user_id = timestamp_part + random_part
            if len(user_id) == 7 and user_id.isdigit():
                if not UserMain.objects.filter(yonghuid=user_id).exists():
                    return user_id
        raise Exception('生成用户ID失败')

    def _huoqu_kehuduan_ip(self, request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0].strip()
            if ip:
                return ip
        ip = request.META.get('REMOTE_ADDR', '')
        return ip if ip else '0.0.0.0'

    def _huoqu_qun_peizhi(self):
        try:
            qun_configs = Qunpeizhi.objects.filter(id__in=[1, 2])
            result = {
                'dashouqun': '',
                'dashouqunid': '',
                'guanshiqun': '',
                'guanshiqunid': ''
            }
            for config in qun_configs:
                if config.id == 1:
                    result['dashouqun'] = config.neirong or ''
                    result['dashouqunid'] = config.qunid or ''
                elif config.id == 2:
                    result['guanshiqun'] = config.neirong or ''
                    result['guanshiqunid'] = config.qunid or ''
            return result
        except Exception as e:
            logger.error(f"获取群配置失败: {e}")
            return {'dashouqun': '', 'dashouqunid': '', 'guanshiqun': '', 'guanshiqunid': ''}

    def _zhuangbei_dashou_fanhui(self, dashou_profile):
        data = {
            'dashounicheng': dashou_profile.nicheng,
            'zhanghaostatus': dashou_profile.zhanghaozhuangtai,
            'yongjin': str(dashou_profile.yue),
            'zonge': str(dashou_profile.zonge),
            'yajin': str(dashou_profile.yajin),
            'chenghao': dashou_profile.chenghao,
            'jinfen': dashou_profile.jifen,
            'chengjiaoliang': dashou_profile.chengjiaozongliang,
            'zaixianzhuangtai': dashou_profile.zaixianzhuangtai,
            'dashouzhuangtai': dashou_profile.zhuangtai,
        }
        huiyuan_list = []
        try:
            records = Huiyuangoumai.objects.filter(yonghu_id=dashou_profile.user.yonghuid)
            for record in records:
                shifou_daoqi = record.jiance_shifou_daoqi()
                huiyuan_list.append({
                    'huiyuan_id': record.huiyuan_id,
                    'huiyuan_zhuangtai': record.huiyuan_zhuangtai,
                    'daoqi_time': record.daoqi_time.isoformat() if record.daoqi_time else None,
                    'shifou_daoqi': shifou_daoqi,
                    'jieshao': record.jieshao
                })
        except Exception as e:
            logger.warning(f"获取会员列表失败: {e}")
        data['clumber'] = huiyuan_list
        return data

    def _fanhui_xianyou_guanshi_info(self, user_main):
        guanshi_profile = user_main.guanshi_profile
        dashou_profile = getattr(user_main, 'dashou_profile', None)
        group_info = self._huoqu_qun_peizhi()
        dashou_status = 1 if dashou_profile else 0
        shangjia_status = 1 if hasattr(user_main, 'shop_profile') else 0
        guanshi_status = 1
        try:
            nicheng = user_main.boss_profile.nickname or '微信用户'
        except:
            nicheng = '微信用户'
        refresh = RefreshToken.for_user(user_main)
        token = str(refresh.access_token)
        data = {
            'token': token,
            'nicheng': nicheng,
            'uid': user_main.yonghuid,
            'touxiang': user_main.avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            **group_info,
        }
        guanshi_data = {
            'gszhstatus': guanshi_profile.zhuangtai,
            'yaoqingzongshu': guanshi_profile.yaogingshuliang,
            'fenyongzonge': str(guanshi_profile.chongzhifenrun),
            'fenyongtixian': str(guanshi_profile.yue),
            'yichongzhiDashou': guanshi_profile.jinrichongzhi,
        }
        data.update(guanshi_data)
        if dashou_profile:
            dashou_data = self._zhuangbei_dashou_fanhui(dashou_profile)
            data.update(dashou_data)
        else:
            data.update({
                'dashounicheng': '',
                'zhanghaostatus': 0,
                'yongjin': '0.00',
                'zonge': '0.00',
                'yajin': '0.00',
                'chenghao': '',
                'jinfen': 0,
                'chengjiaoliang': 0,
                'zaixianzhuangtai': 0,
                'dashouzhuangtai': 0,
                'clumber': []
            })
        return Response({'code': 200, 'msg': '您已是管事', 'data': data})

    def _zhuangbei_fanhui_shuju(self, user_main, dashou_profile, guanshi_profile, token):
        try:
            nicheng = user_main.boss_profile.nickname or '微信用户'
        except:
            nicheng = '微信用户'
        dashou_status = 1
        shangjia_status = 1 if hasattr(user_main, 'shop_profile') else 0
        guanshi_status = 1
        group_info = self._huoqu_qun_peizhi()
        data = {
            'token': token,
            'nicheng': nicheng,
            'uid': user_main.yonghuid,
            'touxiang': user_main.avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            **group_info,
        }
        guanshi_data = {
            'gszhstatus': guanshi_profile.zhuangtai,
            'yaoqingzongshu': guanshi_profile.yaogingshuliang,
            'fenyongzonge': str(guanshi_profile.chongzhifenrun),
            'fenyongtixian': str(guanshi_profile.yue),
            'yichongzhiDashou': guanshi_profile.jinrichongzhi,
        }
        data.update(guanshi_data)
        dashou_data = self._zhuangbei_dashou_fanhui(dashou_profile)
        data.update(dashou_data)
        return data
'''class WechatLoginAndGuanshiRegisterView(APIView):
    """
    微信登录并注册管事一体化接口
    访问路径: /api/yonghu/zuzhangyqmzc
    请求方法: POST
    权限要求: 允许所有（内部根据是否有code区分已登录/未登录）

    请求体（未登录用户）:
        {
            "code": "微信登录code",
            "inviteCode": "组长邀请码"
        }
    请求体（已登录用户）:
        {
            "inviteCode": "组长邀请码"
        }

    功能:
        1. 未登录用户：通过code完成微信登录，自动注册管事及打手身份。
        2. 已登录用户：直接使用当前用户注册管事及打手身份。
    """
    throttle_classes = []  # 可根据需要添加限流
    permission_classes = [AllowAny]

    def post(self, request):
        try:
            # ========== 1. 获取并验证参数 ==========
            code = request.data.get('code', '').strip()
            yaoqingma = request.data.get('inviteCode', '').strip()

            if not yaoqingma:
                return Response({
                    'code': 1,
                    'msg': '邀请码不能为空',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            if len(yaoqingma) > 100:
                return Response({
                    'code': 2,
                    'msg': '邀请码长度超过限制',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # ========== 2. 区分已登录/未登录流程 ==========
            if code:
                # 2.1 未登录流程：通过code获取openid
                wechat_data = self._get_wechat_openid(code)
                if not wechat_data or 'openid' not in wechat_data:
                    error_msg = wechat_data.get('errmsg', '微信授权失败')
                    return Response({
                        'code': 3,
                        'msg': f'微信登录失败: {error_msg}',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                openid = wechat_data['openid']
                kehuduan_ip = self._huoqu_kehuduan_ip(request)

                # 2.2 在事务中创建或获取用户（确保原子性）
                with transaction.atomic():
                    user_main, created = UserMain.objects.select_for_update().get_or_create(
                        openid=openid,
                        defaults={
                            'yonghuid': self._shengcheng_yonghu_id(),
                            'user_type': 'normal',
                        }
                    )

                    # 更新IP和最后登录时间
                    user_main.ip = kehuduan_ip
                    user_main.last_login_time = timezone.now()
                    user_main.save()

                    if created:
                        # 新用户：创建老板扩展表
                        UserBoss.objects.create(
                            user=user_main,
                            nickname='微信用户'
                        )
                        # 注意：商家扩展表暂不自动创建，后续由用户主动开通
            else:
                # 2.3 已登录流程：直接使用当前认证用户
                if not request.user.is_authenticated:
                    return Response({
                        'code': 4,
                        'msg': '用户未登录，请提供code参数',
                        'data': None
                    }, status=status.HTTP_401_UNAUTHORIZED)
                user_main = request.user
                created = False  # 标记不是新用户

            # ========== 3. 检查用户是否已是管事 ==========
            if hasattr(user_main, 'guanshi_profile'):
                # 用户已是管事，直接返回现有信息
                return self._fanhui_xianyou_guanshi_info(user_main)

            # ========== 4. 验证邀请码对应的组长 ==========
            try:
                zuzhang = UserZuzhang.objects.select_related('user').get(yaoqingma=yaoqingma)
            except UserZuzhang.DoesNotExist:
                return Response({
                    'code': 5,
                    'msg': '邀请码无效或不存在',
                    'data': None
                }, status=status.HTTP_404_NOT_FOUND)

            # 验证组长账号状态
            if zuzhang.zhuangtai != 1:
                return Response({
                    'code': 6,
                    'msg': '该邀请码对应的组长账号已被禁用',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 获取组长用户ID
            zuzhang_yonghuid = zuzhang.user.yonghuid

            # ========== 5. 使用事务执行注册 ==========
            with transaction.atomic():
                # 5.1 创建管事扩展表
                # 生成管事的邀请码（使用当前用户ID）
                guanshi_yaoqingma = chuangjianYaoqingma(str(user_main.yonghuid))

                guanshi_profile = UserGuanshi.objects.create(
                    user=user_main,
                    yaoqingma=guanshi_yaoqingma,
                    yaoqingren=zuzhang_yonghuid,  # 邀请人ID
                    # 其他字段使用默认值
                )

                # 5.2 更新组长的邀请总数
                UserZuzhang.objects.filter(pk=zuzhang.pk).update(
                    yaoqing_zongshu=models.F('yaoqing_zongshu') + 1
                )

                # 5.3 检查用户是否已是打手，如果不是则创建
                if not hasattr(user_main, 'dashou_profile'):
                    dashou_profile = UserDashou.objects.create(
                        user=user_main,
                        nicheng='大手子',           # 默认昵称
                        chenghao='普通大手',         # 默认称号
                        yaoqingren=zuzhang_yonghuid, # 邀请人ID
                        # 其他字段使用默认值
                    )
                else:
                    dashou_profile = user_main.dashou_profile

                # 5.4 如果是新用户，还需要创建其他基础表？老板表已在创建用户时创建
                # 商家表暂不自动创建

            # ========== 6. 生成JWT token（新用户需要） ==========
            if created:
                refresh = RefreshToken.for_user(user_main)
                token = str(refresh.access_token)
            else:
                # 已登录用户，可能不需要返回新token，但为了统一，也可以生成新的
                refresh = RefreshToken.for_user(user_main)
                token = str(refresh.access_token)

            # ========== 7. 准备返回数据 ==========
            response_data = self._zhuangbei_fanhui_shuju(
                user_main,
                dashou_profile,
                guanshi_profile,
                token
            )

            return Response({
                'code': 0,
                'msg': '注册成功！',
                'data': response_data
            })

        except Exception as e:
            logger.error(f"管事注册接口异常: {str(e)}", exc_info=True)
            return Response({
                'code': 99,
                'msg': '系统繁忙，请稍后重试',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    # ---------- 辅助方法 ----------

    def _get_wechat_openid(self, code):
        """调用微信接口获取openid"""
        try:
            appid = getattr(settings, 'WEIXIN_APPID', '')
            secret = getattr(settings, 'WEIXIN_SECRET', '')

            if not appid or not secret:
                raise ValueError('微信配置未设置')

            url = 'https://api.weixin.qq.com/sns/jscode2session'
            params = {
                'appid': appid,
                'secret': secret,
                'js_code': code,
                'grant_type': 'authorization_code'
            }

            response = requests.get(url, params=params, timeout=10)
            result = response.json()

            if 'openid' in result:
                return result
            else:
                errcode = result.get('errcode', 'unknown')
                errmsg = result.get('errmsg', '未知错误')
                return {'errmsg': f'[{errcode}]{errmsg}'}

        except requests.exceptions.Timeout:
            return {'errmsg': '请求微信接口超时'}
        except Exception as e:
            return {'errmsg': f'请求微信接口异常: {str(e)}'}

    def _shengcheng_yonghu_id(self):
        """生成7位数字用户ID（与打手端一致）"""
        for _ in range(10):
            timestamp_part = str(int(time.time()))[-5:].zfill(5)
            random_part = str(random.randint(0, 99)).zfill(2)
            user_id = timestamp_part + random_part
            if len(user_id) == 7 and user_id.isdigit():
                if not UserMain.objects.filter(yonghuid=user_id).exists():
                    return user_id
        raise Exception('生成用户ID失败')

    def _huoqu_kehuduan_ip(self, request):
        """获取客户端真实IP地址"""
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0].strip()
            if ip:
                return ip
        ip = request.META.get('REMOTE_ADDR', '')
        return ip if ip else '0.0.0.0'

    def _huoqu_qun_peizhi(self):
        """获取群配置信息（与打手端一致）"""
        try:
            qun_configs = Qunpeizhi.objects.filter(id__in=[1, 2])
            result = {
                'dashouqun': '',
                'dashouqunid': '',
                'guanshiqun': '',
                'guanshiqunid': ''
            }
            for config in qun_configs:
                if config.id == 1:
                    result['dashouqun'] = config.neirong or ''
                    result['dashouqunid'] = config.qunid or ''
                elif config.id == 2:
                    result['guanshiqun'] = config.neirong or ''
                    result['guanshiqunid'] = config.qunid or ''
            return result
        except Exception:
            return {
                'dashouqun': '',
                'dashouqunid': '',
                'guanshiqun': '',
                'guanshiqunid': ''
            }

    def _fanhui_xianyou_guanshi_info(self, user_main):
        """
        返回已是管事的用户信息（无需注册）
        """
        guanshi_profile = user_main.guanshi_profile
        dashou_profile = getattr(user_main, 'dashou_profile', None)

        # 获取群配置
        group_info = self._huoqu_qun_peizhi()

        # 身份状态
        dashou_status = 1 if dashou_profile else 0
        shangjia_status = 1 if hasattr(user_main, 'shop_profile') else 0
        guanshi_status = 1

        # 获取老板昵称
        try:
            boss_profile = user_main.boss_profile
            nicheng = boss_profile.nickname or '微信用户'
        except:
            nicheng = '微信用户'

        # 生成token（用户已登录，但可以生成新token）
        refresh = RefreshToken.for_user(user_main)
        token = str(refresh.access_token)

        # 准备数据
        data = {
            'token': token,
            'nicheng': nicheng,
            'uid': user_main.yonghuid,
            'touxiang': user_main.avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            **group_info,
        }

        # 添加管事信息
        guanshi_data = self._zhuangbei_guanshi_fanhui(guanshi_profile)
        data.update(guanshi_data)

        # 添加打手信息（如果存在）
        if dashou_profile:
            dashou_data = self._zhuangbei_dashou_fanhui(dashou_profile)
            data.update(dashou_data)
        else:
            # 默认空打手数据（前端可能需要）
            data.update({
                'dashounicheng': '',
                'zhanghaostatus': 0,
                'yongjin': '0.00',
                'zonge': '0.00',
                'yajin': '0.00',
                'chenghao': '',
                'jinfen': 0,
                'chengjiaoliang': 0,
                'zaixianzhuangtai': 0,
                'dashouzhuangtai': 0,
                'clumber': []
            })

        return Response({
            'code': 0,
            'msg': '您已是管事',
            'data': data
        })

    def _zhuangbei_guanshi_fanhui(self, guanshi_profile):
        """准备管事信息返回数据"""
        return {
            'gszhstatus': guanshi_profile.zhuangtai or '',
            'yaoqingzongshu': guanshi_profile.yaogingshuliang,
            'fenyongzonge': str(guanshi_profile.chongzhifenrun),
            'fenyongtixian': str(guanshi_profile.yue),
            'yichongzhiDashou': guanshi_profile.jinrichongzhi,  # 注意：这里用jinrichongzhi作为示例，实际可能需要根据业务调整
            # 如果业务有更准确的字段，请替换
        }

    def _zhuangbei_dashou_fanhui(self, dashou_profile):
        """准备打手信息返回数据（与打手端一致）"""
        data = {
            'dashounicheng': dashou_profile.nicheng,
            'zhanghaostatus': dashou_profile.zhanghaozhuangtai,
            'yongjin': str(dashou_profile.yue),
            'zonge': str(dashou_profile.zonge),
            'yajin': str(dashou_profile.yajin),
            'chenghao': dashou_profile.chenghao,
            'jinfen': dashou_profile.jifen,
            'chengjiaoliang': dashou_profile.chengjiaozongliang,
            'zaixianzhuangtai': dashou_profile.zaixianzhuangtai,
            'dashouzhuangtai': dashou_profile.zhuangtai,
        }

        # 处理会员列表（clumber）
        huiyuan_list = []
        try:
            records = Huiyuangoumai.objects.filter(yonghu_id=dashou_profile.user.yonghuid)
            for record in records:
                shifou_daoqi = record.jiance_shifou_daoqi()
                huiyuan_list.append({
                    'huiyuan_id': record.huiyuan_id,
                    'huiyuan_zhuangtai': record.huiyuan_zhuangtai,
                    'daoqi_time': record.daoqi_time.isoformat() if record.daoqi_time else None,
                    'shifou_daoqi': shifou_daoqi,
                    'jieshao': record.jieshao
                })
        except Exception as e:
            # 如果表不存在或出错，返回空列表
            logger.warning(f"获取会员列表失败: {e}")
        data['clumber'] = huiyuan_list
        return data

    def _zhuangbei_fanhui_shuju(self, user_main, dashou_profile, guanshi_profile, token):
        """准备完整的返回数据（新注册）"""
        # 获取老板昵称
        try:
            boss_profile = user_main.boss_profile
            nicheng = boss_profile.nickname or '微信用户'
        except:
            nicheng = '微信用户'

        # 身份状态
        dashou_status = 1
        shangjia_status = 1 if hasattr(user_main, 'shop_profile') else 0
        guanshi_status = 1

        # 获取群配置
        group_info = self._huoqu_qun_peizhi()

        # 基础数据
        data = {
            'token': token,
            'nicheng': nicheng,
            'uid': user_main.yonghuid,
            'touxiang': user_main.avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            **group_info,
        }

        # 添加管事信息
        guanshi_data = self._zhuangbei_guanshi_fanhui(guanshi_profile)
        data.update(guanshi_data)

        # 添加打手信息
        dashou_data = self._zhuangbei_dashou_fanhui(dashou_profile)
        data.update(dashou_data)

        return data'''





















'''class GuanshiRegisterView(APIView):
    """
    已登录用户注册管事接口
    访问路径: /api/yonghu/guanshizhuce
    请求方法: POST
    权限要求: JWT认证
    请求体: { "inviteCode": "组长邀请码" }
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 1. 获取并验证邀请码
        yaoqingma = request.data.get('inviteCode', '').strip()
        if not yaoqingma:
            return Response({
                'code': 1,
                'msg': '邀请码不能为空',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        if len(yaoqingma) > 100:
            return Response({
                'code': 2,
                'msg': '邀请码长度超过限制',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        current_user = request.user

        # 2. 检查用户是否已是管事
        if hasattr(current_user, 'guanshi_profile'):
            # 用户已是管事，直接返回现有信息
            return self._fanhui_xianyou_guanshi_info(current_user)

        # 3. 验证邀请码对应的组长
        try:
            zuzhang = UserZuzhang.objects.select_related('user').get(yaoqingma=yaoqingma)
        except UserZuzhang.DoesNotExist:
            return Response({
                'code': 3,
                'msg': '邀请码无效或不存在',
                'data': None
            }, status=status.HTTP_404_NOT_FOUND)

        if zuzhang.zhuangtai != 1:
            return Response({
                'code': 4,
                'msg': '该邀请码对应的组长账号已被禁用',
                'data': None
            }, status=status.HTTP_403_FORBIDDEN)

        zuzhang_yonghuid = zuzhang.user.yonghuid

        # 4. 事务内创建管事实体和打手（如果需要）
        with transaction.atomic():
            # 创建管事扩展表
            guanshi_yaoqingma = chuangjianYaoqingma(str(current_user.yonghuid))
            guanshi_profile = UserGuanshi.objects.create(
                user=current_user,
                yaoqingma=guanshi_yaoqingma,
                yaoqingren=zuzhang_yonghuid,
                # 其他字段使用默认值
            )

            # 更新组长的邀请总数
            UserZuzhang.objects.filter(pk=zuzhang.pk).update(
                yaoqing_zongshu=models.F('yaoqing_zongshu') + 1
            )

            # 检查用户是否已是打手，如果不是则创建
            if not hasattr(current_user, 'dashou_profile'):
                dashou_profile = UserDashou.objects.create(
                    user=current_user,
                    nicheng='大手子',
                    chenghao='普通大手',
                    yaoqingren=zuzhang_yonghuid,
                )
            else:
                dashou_profile = current_user.dashou_profile

        # 5. 生成新token（可选，为了统一处理）
        refresh = RefreshToken.for_user(current_user)
        token = str(refresh.access_token)

        # 6. 准备返回数据
        response_data = self._zhuangbei_fanhui_shuju(
            current_user, dashou_profile, guanshi_profile, token
        )

        return Response({
            'code': 0,
            'msg': '注册成功！',
            'data': response_data
        })

    # ---------- 辅助方法 ----------
    def _huoqu_qun_peizhi(self):
        """获取群配置信息"""
        try:
            qun_configs = Qunpeizhi.objects.filter(id__in=[1, 2])
            result = {
                'dashouqun': '',
                'dashouqunid': '',
                'guanshiqun': '',
                'guanshiqunid': ''
            }
            for config in qun_configs:
                if config.id == 1:
                    result['dashouqun'] = config.neirong or ''
                    result['dashouqunid'] = config.qunid or ''
                elif config.id == 2:
                    result['guanshiqun'] = config.neirong or ''
                    result['guanshiqunid'] = config.qunid or ''
            return result
        except Exception:
            return {
                'dashouqun': '',
                'dashouqunid': '',
                'guanshiqun': '',
                'guanshiqunid': ''
            }

    def _fanhui_xianyou_guanshi_info(self, user_main):
        """返回已是管事的用户信息"""
        guanshi_profile = user_main.guanshi_profile
        dashou_profile = getattr(user_main, 'dashou_profile', None)

        group_info = self._huoqu_qun_peizhi()

        dashou_status = 1 if dashou_profile else 0
        shangjia_status = 1 if hasattr(user_main, 'shop_profile') else 0
        guanshi_status = 1

        try:
            nicheng = user_main.boss_profile.nickname or '微信用户'
        except:
            nicheng = '微信用户'

        refresh = RefreshToken.for_user(user_main)
        token = str(refresh.access_token)

        data = {
            'token': token,
            'nicheng': nicheng,
            'uid': user_main.yonghuid,
            'touxiang': user_main.avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            **group_info,
        }

        # 添加管事信息
        guanshi_data = self._zhuangbei_guanshi_fanhui(guanshi_profile)
        data.update(guanshi_data)

        # 添加打手信息（如果存在）
        if dashou_profile:
            dashou_data = self._zhuangbei_dashou_fanhui(dashou_profile)
            data.update(dashou_data)
        else:
            data.update({
                'dashounicheng': '',
                'zhanghaostatus': 0,
                'yongjin': '0.00',
                'zonge': '0.00',
                'yajin': '0.00',
                'chenghao': '',
                'jinfen': 0,
                'chengjiaoliang': 0,
                'zaixianzhuangtai': 0,
                'dashouzhuangtai': 0,
                'clumber': []
            })

        return Response({
            'code': 0,
            'msg': '您已是管事',
            'data': data
        })

    def _zhuangbei_guanshi_fanhui(self, guanshi_profile):
        """组装管事信息"""
        return {
            'gszhstatus': guanshi_profile.zhuangtai or '',
            'yaoqingzongshu': guanshi_profile.yaogingshuliang,
            'fenyongzonge': str(guanshi_profile.chongzhifenrun),
            'fenyongtixian': str(guanshi_profile.yue),
            'yichongzhiDashou': guanshi_profile.jinrichongzhi,  # 根据实际字段调整
        }

    def _zhuangbei_dashou_fanhui(self, dashou_profile):
        """组装打手信息"""
        data = {
            'dashounicheng': dashou_profile.nicheng,
            'zhanghaostatus': dashou_profile.zhanghaozhuangtai,
            'yongjin': str(dashou_profile.yue),
            'zonge': str(dashou_profile.zonge),
            'yajin': str(dashou_profile.yajin),
            'chenghao': dashou_profile.chenghao,
            'jinfen': dashou_profile.jifen,
            'chengjiaoliang': dashou_profile.chengjiaozongliang,
            'zaixianzhuangtai': dashou_profile.zaixianzhuangtai,
            'dashouzhuangtai': dashou_profile.zhuangtai,
        }

        # 会员列表
        huiyuan_list = []
        try:
            records = Huiyuangoumai.objects.filter(yonghu_id=dashou_profile.user.yonghuid)
            for record in records:
                shifou_daoqi = record.jiance_shifou_daoqi()
                huiyuan_list.append({
                    'huiyuan_id': record.huiyuan_id,
                    'huiyuan_zhuangtai': record.huiyuan_zhuangtai,
                    'daoqi_time': record.daoqi_time.isoformat() if record.daoqi_time else None,
                    'shifou_daoqi': shifou_daoqi,
                    'jieshao': record.jieshao
                })
        except Exception as e:
            logger.warning(f"获取会员列表失败: {e}")
        data['clumber'] = huiyuan_list
        return data

    def _zhuangbei_fanhui_shuju(self, user_main, dashou_profile, guanshi_profile, token):
        """组装完整返回数据（新注册）"""
        try:
            nicheng = user_main.boss_profile.nickname or '微信用户'
        except:
            nicheng = '微信用户'

        dashou_status = 1
        shangjia_status = 1 if hasattr(user_main, 'shop_profile') else 0
        guanshi_status = 1

        group_info = self._huoqu_qun_peizhi()

        data = {
            'token': token,
            'nicheng': nicheng,
            'uid': user_main.yonghuid,
            'touxiang': user_main.avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            **group_info,
        }

        guanshi_data = self._zhuangbei_guanshi_fanhui(guanshi_profile)
        data.update(guanshi_data)

        dashou_data = self._zhuangbei_dashou_fanhui(dashou_profile)
        data.update(dashou_data)

        return data'''













from django.db import transaction, models

class GuanshiRegisterView(APIView):
    """
    已登录用户注册管事接口
    路径: /api/yonghu/guanshizhuce
    方法: POST
    权限: JWT认证
    请求体: { "inviteCode": "组长邀请码" }
    成功返回 code: 200
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 1. 获取并验证邀请码
        yaoqingma = request.data.get('inviteCode', '').strip()
        if not yaoqingma:
            return Response({'code': 400, 'msg': '邀请码不能为空', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        if len(yaoqingma) > 100:
            return Response({'code': 400, 'msg': '邀请码长度超过限制', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        current_user = request.user

        # 2. 检查用户是否已是管事
        if hasattr(current_user, 'guanshi_profile'):
            # 用户已是管事，直接返回现有信息
            return self._fanhui_xianyou_guanshi_info(current_user)

        # 3. 验证邀请码对应的组长
        try:
            zuzhang = UserZuzhang.objects.select_related('user').get(yaoqingma=yaoqingma)
        except UserZuzhang.DoesNotExist:
            return Response({'code': 404, 'msg': '邀请码无效或不存在', 'data': None},
                            status=status.HTTP_404_NOT_FOUND)

        if zuzhang.zhuangtai != 1:
            return Response({'code': 403, 'msg': '该邀请码对应的组长账号已被禁用', 'data': None},
                            status=status.HTTP_403_FORBIDDEN)

        zuzhang_yonghuid = zuzhang.user.yonghuid

        # 4. 事务内创建管事实体和打手（如果需要）
        with transaction.atomic():
            # 创建管事扩展表
            guanshi_yaoqingma = chuangjianYaoqingma(str(current_user.yonghuid))
            guanshi_profile = UserGuanshi.objects.create(
                user=current_user,
                yaoqingma=guanshi_yaoqingma,
                yaoqingren=zuzhang_yonghuid,
            )

            # 更新组长的邀请总数
            UserZuzhang.objects.filter(pk=zuzhang.pk).update(
                yaoqing_zongshu=models.F('yaoqing_zongshu') + 1
            )
            # ========== 新增：组长每日统计（邀请管事 action=1） ==========
            try:
                from houtai.utils import update_zuzhang_daily_by_action
                update_zuzhang_daily_by_action(
                    yonghuid=zuzhang_yonghuid,
                    action=1  # 1 = 邀请管事
                )
                logger.info(f"组长每日统计更新成功（邀请管事）：组长{zuzhang_yonghuid}")
            except Exception as e:
                logger.error(f"组长每日统计更新失败（邀请管事）：{str(e)}")

            # 检查用户是否已是打手，如果不是则创建
            if not hasattr(current_user, 'dashou_profile'):
                dashou_profile = UserDashou.objects.create(
                    user=current_user,
                    nicheng='大手子',
                    chenghao='普通大手',
                    yaoqingren=zuzhang_yonghuid,
                )
            else:
                dashou_profile = current_user.dashou_profile

        # 5. 生成新token
        refresh = RefreshToken.for_user(current_user)
        token = str(refresh.access_token)

        # 6. 准备返回数据（包含所有字段）
        response_data = self._zhuangbei_fanhui_shuju(
            current_user, dashou_profile, guanshi_profile, token
        )

        return Response({'code': 200, 'msg': '注册成功！', 'data': response_data})

    # ---------- 辅助方法 ----------

    def _huoqu_qun_peizhi(self):
        """获取群配置信息"""
        try:
            qun_configs = Qunpeizhi.objects.filter(id__in=[1, 2])
            result = {
                'dashouqun': '',
                'dashouqunid': '',
                'guanshiqun': '',
                'guanshiqunid': ''
            }
            for config in qun_configs:
                if config.id == 1:
                    result['dashouqun'] = config.neirong or ''
                    result['dashouqunid'] = config.qunid or ''
                elif config.id == 2:
                    result['guanshiqun'] = config.neirong or ''
                    result['guanshiqunid'] = config.qunid or ''
            return result
        except Exception as e:
            logger.error(f"获取群配置失败: {e}")
            return {'dashouqun': '', 'dashouqunid': '', 'guanshiqun': '', 'guanshiqunid': ''}

    def _zhuangbei_dashou_fanhui(self, dashou_profile):
        """组装打手信息（字段名与前端完全匹配）"""
        data = {
            'dashounicheng': dashou_profile.nicheng,
            'zhanghaostatus': dashou_profile.zhanghaozhuangtai,
            'yongjin': str(dashou_profile.yue),
            'zonge': str(dashou_profile.zonge),
            'yajin': str(dashou_profile.yajin),
            'chenghao': dashou_profile.chenghao,
            'jinfen': dashou_profile.jifen,
            'chengjiaoliang': dashou_profile.chengjiaozongliang,
            'zaixianzhuangtai': dashou_profile.zaixianzhuangtai,
            'dashouzhuangtai': dashou_profile.zhuangtai,
        }

        # 会员列表
        huiyuan_list = []
        try:
            records = Huiyuangoumai.objects.filter(yonghu_id=dashou_profile.user.yonghuid)
            for record in records:
                shifou_daoqi = record.jiance_shifou_daoqi()
                huiyuan_list.append({
                    'huiyuan_id': record.huiyuan_id,
                    'huiyuan_zhuangtai': record.huiyuan_zhuangtai,
                    'daoqi_time': record.daoqi_time.isoformat() if record.daoqi_time else None,
                    'shifou_daoqi': shifou_daoqi,
                    'jieshao': record.jieshao
                })
        except Exception as e:
            logger.warning(f"获取会员列表失败: {e}")
        data['clumber'] = huiyuan_list
        return data

    def _fanhui_xianyou_guanshi_info(self, user_main):
        """用户已是管事时的返回"""
        guanshi_profile = user_main.guanshi_profile
        dashou_profile = getattr(user_main, 'dashou_profile', None)

        group_info = self._huoqu_qun_peizhi()

        dashou_status = 1 if dashou_profile else 0
        shangjia_status = 1 if hasattr(user_main, 'shop_profile') else 0
        guanshi_status = 1

        try:
            nicheng = user_main.boss_profile.nickname or '微信用户'
        except:
            nicheng = '微信用户'

        refresh = RefreshToken.for_user(user_main)
        token = str(refresh.access_token)

        data = {
            'token': token,
            'nicheng': nicheng,
            'uid': user_main.yonghuid,
            'touxiang': user_main.avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            **group_info,
        }

        # 管事信息
        guanshi_data = {
            'gszhstatus': guanshi_profile.zhuangtai,
            'yaoqingzongshu': guanshi_profile.yaogingshuliang,
            'fenyongzonge': str(guanshi_profile.chongzhifenrun),
            'fenyongtixian': str(guanshi_profile.yue),
            'yichongzhiDashou': guanshi_profile.jinrichongzhi,
        }
        data.update(guanshi_data)

        if dashou_profile:
            dashou_data = self._zhuangbei_dashou_fanhui(dashou_profile)
            data.update(dashou_data)
        else:
            data.update({
                'dashounicheng': '',
                'zhanghaostatus': 0,
                'yongjin': '0.00',
                'zonge': '0.00',
                'yajin': '0.00',
                'chenghao': '',
                'jinfen': 0,
                'chengjiaoliang': 0,
                'zaixianzhuangtai': 0,
                'dashouzhuangtai': 0,
                'clumber': []
            })

        return Response({'code': 200, 'msg': '您已是管事', 'data': data})

    def _zhuangbei_fanhui_shuju(self, user_main, dashou_profile, guanshi_profile, token):
        """组装完整返回数据（新注册）"""
        try:
            nicheng = user_main.boss_profile.nickname or '微信用户'
        except:
            nicheng = '微信用户'

        dashou_status = 1
        shangjia_status = 1 if hasattr(user_main, 'shop_profile') else 0
        guanshi_status = 1

        group_info = self._huoqu_qun_peizhi()

        data = {
            'token': token,
            'nicheng': nicheng,
            'uid': user_main.yonghuid,
            'touxiang': user_main.avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            **group_info,
        }

        # 管事信息
        guanshi_data = {
            'gszhstatus': guanshi_profile.zhuangtai,
            'yaoqingzongshu': guanshi_profile.yaogingshuliang,
            'fenyongzonge': str(guanshi_profile.chongzhifenrun),
            'fenyongtixian': str(guanshi_profile.yue),
            'yichongzhiDashou': guanshi_profile.jinrichongzhi,
        }
        data.update(guanshi_data)

        dashou_data = self._zhuangbei_dashou_fanhui(dashou_profile)
        data.update(dashou_data)

        return data




from rest_framework_simplejwt.authentication import JWTAuthentication
from django.db import IntegrityError


class ZuzhangZhuceView(APIView):
    """
    组长注册/激活接口
    POST /yonghu/zuzhangzhuce
    请求体: {"inviteCode": "xxx"}
    返回:
        {
            "code": 200,
            "msg": "success",
            "data": {
                "ketixian": "0.00",        # 可提现金额
                "guanshiCount": 0,          # 邀请的管事数量
                "fenhongZonge": "0.00"      # 分红总额
            }
        }
    或错误码
    """

    permission_classes = [IsAuthenticated]

    # 硬编码激活码（注意转义特殊字符）
    ACTIVATION_CODE = "jdjdhsavjsjdb64646/'3464jdjs"

    def post(self, request):
        user = request.user
        invite_code = request.data.get('inviteCode', '').strip()

        if not invite_code:
            return Response({'code': 400, 'msg': '邀请码不能为空'}, status=400)

        # 检查是否已是组长
        try:
            zuzhang = UserZuzhang.objects.select_related('user').get(user=user)
            # 已注册，直接返回数据
            data = self._build_response_data(zuzhang, user)
            return Response({'code': 200, 'msg': '已注册', 'data': data})
        except UserZuzhang.DoesNotExist:
            pass

        # 比对激活码
        if invite_code != self.ACTIVATION_CODE:
            return Response({'code': 400, 'msg': '邀请码无效'}, status=400)

        # 生成唯一组长邀请码：时间戳 + 用户ID后6位 + 随机字符
        yaoqingma = self._generate_unique_yaoqingma(user.yonghuid)

        # 创建组长扩展记录
        try:
            with transaction.atomic():
                zuzhang = UserZuzhang.objects.create(
                    user=user,
                    yaoqingma=yaoqingma,
                    fenyong_zonge=0.00,
                    ketixian_jine=0.00,
                    yaoqing_zongshu=0,
                    jinri_fenyong=0.00,
                    jinyue_fenyong=0.00,
                    zhuangtai=1,
                    jinri_tixian=0.00,
                    ewai_tixian_xiane=0.00,
                    kaioi_ewai_tixian=False,
                    kaioi_ewai_fenhong=False,
                    ewai_fenhong_jine=0.00
                )
        except IntegrityError:
            # 极低概率重复，重试一次
            yaoqingma = self._generate_unique_yaoqingma(user.yonghuid, retry=True)
            zuzhang = UserZuzhang.objects.create(
                user=user,
                yaoqingma=yaoqingma,
                # 其他字段默认同上
                fenyong_zonge=0.00,
                ketixian_jine=0.00,
                yaoqing_zongshu=0,
                jinri_fenyong=0.00,
                jinyue_fenyong=0.00,
                zhuangtai=1,
                jinri_tixian=0.00,
                ewai_tixian_xiane=0.00,
                kaioi_ewai_tixian=False,
                kaioi_ewai_fenhong=False,
                ewai_fenhong_jine=0.00
            )

        data = self._build_response_data(zuzhang, user)
        return Response({'code': 200, 'msg': '注册成功', 'data': data})

    def _generate_unique_yaoqingma(self, yonghuid, retry=False):
        """生成唯一邀请码：时间戳+用户ID后6位+随机2位字符"""
        import random, string
        timestamp = str(int(time.time()))[-6:]  # 取后6位
        uid_part = yonghuid[-6:] if len(yonghuid) >= 6 else yonghuid.rjust(6, '0')
        rand_str = ''.join(random.choices(string.ascii_uppercase + string.digits, k=2))
        base = f"Z{timestamp}{uid_part}{rand_str}"
        # 确保唯一性（若已存在则追加随机数，最多尝试3次）
        for _ in range(3):
            if not UserZuzhang.objects.filter(yaoqingma=base).exists():
                return base
            base = base + random.choice(string.digits)
        # 极端情况，再附加时间戳毫秒
        millis = str(time.time()).replace('.', '')[-4:]
        return base + millis

    def _build_response_data(self, zuzhang, user):
        """组装前端所需数据"""
        # 计算邀请的管事数量（通过UserGuanshi表的yaoqingren字段关联到user的yonghuid）
        guanshi_count = UserGuanshi.objects.filter(yaoqingren=user.yonghuid).count()
        return {
            'ketixian': str(zuzhang.ketixian_jine),      # 可提现余额
            'guanshiCount': guanshi_count,                # 邀请管事数
            'fenhongZonge': str(zuzhang.fenyong_zonge)    # 分红总额
        }



class ZuzhangXinxiView(APIView):
    """
    组长信息查询接口
    POST /yonghu/zuzhangxinxi
    请求体: 无
    返回: 同注册接口成功返回格式
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        user = request.user
        try:
            zuzhang = UserZuzhang.objects.get(user=user)
        except UserZuzhang.DoesNotExist:
            return Response({'code': 404, 'msg': '用户不是组长'}, status=404)

        guanshi_count = UserGuanshi.objects.filter(yaoqingren=user.yonghuid).count()
        data = {
            'ketixian': str(zuzhang.ketixian_jine),
            'guanshiCount': guanshi_count,
            'fenhongZonge': str(zuzhang.fenyong_zonge)
        }
        return Response({'code': 200, 'msg': 'success', 'data': data})



















# apps/yonghu/views_dashou_jianquan.py
"""
打手 IM 消息权限鉴权接口
URL: /yonghu/dshqltqx
方法: POST
认证: JWT Token (request.user)

鉴权逻辑（满足任意一条即通过）：
    1. 押金 >= 5 元 → 通过
    2. 拥有未过期会员 → 通过
    3. 存在订单状态为 2 或 8 的订单（作为接单打手） → 通过
    以上均不满足 → 拒绝
"""


class DashouJianquanView(APIView):
    """打手消息权限鉴权"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # ========== 1. 通过 JWT 获取当前登录用户 ==========
        user = request.user  # UserMain 实例

        # ========== 2. 检查是否为已注册打手 ==========
        try:
            dashou = user.dashou_profile  # OneToOneField 反向查询
        except UserDashou.DoesNotExist:
            return Response({
                'code': 0,
                'allow': 0,
                'msg': '您尚未注册打手身份，请先注册'
            })

        # ========== 3. 条件一：押金 >= 5 元 ==========
        if dashou.yajin and dashou.yajin >= 5:
            return Response({
                'code': 0,
                'allow': 1,
                'msg': '鉴权通过（押金满足条件）'
            })

        # ========== 4. 条件二：存在未过期会员 ==========
        # 高效查询：利用 yonghu_id + huiyuan_zhuangtai 复合索引
        huiyuan_list = Huiyuangoumai.objects.filter(
            yonghu_id=user.yonghuid,
            huiyuan_zhuangtai=1  # 只查状态为"可用"的，减少内存遍历
        ).only('id', 'daoqi_time', 'huiyuan_zhuangtai')

        for hy in huiyuan_list:
            if not hy.jiance_shifou_daoqi():  # 未过期返回 False
                return Response({
                    'code': 0,
                    'allow': 1,
                    'msg': '鉴权通过（会员未过期）'
                })

        # ========== 5. 条件三：存在订单状态为 2 或 8 的订单 ==========
        # 利用 jiedan_dashou_id + zhuangtai 复合索引，只查 1 条
        has_valid_order = Dingdan.objects.filter(
            jiedan_dashou_id=user.yonghuid,
            zhuangtai__in=[2, 8]
        ).only('id').exists()  # exists() 高性能判断，只发 SELECT 1 LIMIT 1

        if has_valid_order:
            return Response({
                'code': 0,
                'allow': 1,
                'msg': '鉴权通过（存在有效订单）'
            })

        # ========== 6. 以上均不满足 → 拒绝 ==========
        return Response({
            'code': 0,
            'allow': 0,
            'msg': '消息权限不足，请充值会员或联系管理员'
        })



# apps/yonghu/views_laoban_jianquan.py
"""
老板（普通用户） IM 消息权限鉴权接口
URL: /yonghu/lbhqltqx
方法: POST
认证: JWT Token (request.user)

鉴权逻辑：
    查询平台订单扩展表（DingdanPingtai），
    通过关联的订单主表（Dingdan）查找该老板的订单，
    只要存在任意一条订单状态在 1~8 范围内 → 通过
"""



class LaobanJianquanView(APIView):
    """老板消息权限鉴权"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # ========== 1. 通过 JWT 获取当前登录用户 ==========
        user = request.user  # UserMain 实例

        # ========== 2. 高效查询平台订单扩展表 ==========
        # 利用 DingdanPingtai.laoban_id 索引 + Dingdan.zhuangtai 索引
        # 只查 1 条，用 exists() 实现最高性能
        has_valid_order = DingdanPingtai.objects.filter(
            laoban_id=user.yonghuid
        ).filter(
            dingdan__zhuangtai__in=[1, 2, 3, 4, 5, 6, 7, 8]
        ).only('id').exists()

        if has_valid_order:
            return Response({
                'code': 0,
                'allow': 1,
                'msg': '鉴权通过'
            })

        return Response({
            'code': 0,
            'allow': 0,
            'msg': '您暂无订单记录，消息功能暂不可用'
        })



# views.py (在处罚相关app的views中)
import logging
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from django.db.models import Count, Q, Case, When, IntegerField
from dingdan.models import Fadan
from dingdan.models import FadanShensuTupian

logger = logging.getLogger('xiaochengxu')

class FaKuanJiFenTongJiView(APIView):
    """
    获取罚款与积分处罚统计总览
    路径: POST /yonghu/cffktjhq
    """
    permission_classes = [IsAuthenticated, DashouPermission]

    def post(self, request):
        try:
            user_main = request.user
            yonghuid = user_main.yonghuid

            # ================= 罚款统计 =================
            fadan_stats = Fadan.objects.filter(beichufa_id=yonghuid).aggregate(
                total=Count('id'),
                daijiaona=Count('id', filter=Q(zhuangtai=1)),
                shensuzhong=Count('id', filter=Q(zhuangtai=3)),
                yijiaona=Count('id', filter=Q(zhuangtai=2)),
                yibohui=Count('id', filter=Q(zhuangtai=4)),
            )

            # ================= 积分处罚统计 =================
            jifen_stats = Chufajilu.objects.filter(dashouid=yonghuid).aggregate(
                total=Count('id'),
                daichuli=Count('id', filter=Q(sqzhuangtai=0) | Q(sqzhuangtai=3)),
                yichuli=Count('id', filter=Q(sqzhuangtai=1) | Q(sqzhuangtai=2)),
                # 细分
                daichuli_0=Count('id', filter=Q(sqzhuangtai=0)),
                shensuzhong_3=Count('id', filter=Q(sqzhuangtai=3)),
                yichufa_1=Count('id', filter=Q(sqzhuangtai=1)),
                yibohui_2=Count('id', filter=Q(sqzhuangtai=2)),
            )

            data = {
                "fakuan": {
                    "total": fadan_stats['total'],
                    "daijiaona": fadan_stats['daijiaona'],
                    "shensuzhong": fadan_stats['shensuzhong'],
                    "yijiaona": fadan_stats['yijiaona'],
                    "yibohui": fadan_stats['yibohui'],
                },
                "jifen": {
                    "total": jifen_stats['total'],
                    "daichuli": jifen_stats['daichuli'],
                    "yichuli": jifen_stats['yichuli'],
                    "daichuli_0": jifen_stats['daichuli_0'],
                    "shensuzhong_3": jifen_stats['shensuzhong_3'],
                    "yichufa_1": jifen_stats['yichufa_1'],
                    "yibohui_2": jifen_stats['yibohui_2'],
                }
            }

            return Response({'code': 0, 'msg': '获取统计成功', 'data': data})

        except Exception as e:
            logger.error(f"获取统计异常 {yonghuid}: {e}", exc_info=True)
            return Response({'code': 99, 'msg': '系统繁忙'}, status=500)
class DaShouFaKuanLieBiaoView(APIView):
    """
    打手罚款列表接口
    路径：POST /yonghu/dsfklbhq
    参数：
        page: 页码（默认1）
        page_size: 每页条数（默认10，最大50）
        zhuangtai: 状态筛选（1待缴纳/2已缴纳/3申诉中/4申诉成功，0或不传表示全部）
        sousuo_dingdan_id: 订单号模糊搜索
    返回：{
        list: [{
            id, beichufa_id, guanliandingdan_id, chufaliyou, fakuanjine, zhuangtai,
            yingxiang_qiangdan, shensuliyou, bohuiliyou,
            zhengju_tupian: [...],    // 证据图片（yongtu=1）
            shensu_tupian: [...],     // 申诉图片（yongtu=2）
            create_time, update_time
        }],
        has_more, page, page_size
    }
    """
    permission_classes = [IsAuthenticated, DashouPermission]

    def post(self, request):
        try:
            user_main = request.user
            yonghuid = user_main.yonghuid

            # 获取分页参数
            page = int(request.data.get('page', 1))
            page_size = int(request.data.get('page_size', 10))
            if page_size > 50:
                page_size = 50
            if page_size < 1:
                page_size = 10

            # 状态筛选
            zhuangtai = request.data.get('zhuangtai')
            # 订单号搜索
            sousuo_dingdan_id = request.data.get('sousuo_dingdan_id', '').strip()

            # 基础查询：当前用户的罚单
            qs = Fadan.objects.filter(beichufa_id=yonghuid)

            # 状态筛选
            if zhuangtai is not None and int(zhuangtai) in [1, 2, 3, 4]:
                qs = qs.filter(zhuangtai=int(zhuangtai))

            # 订单号模糊搜索
            if sousuo_dingdan_id:
                qs = qs.filter(guanliandingdan_id__icontains=sousuo_dingdan_id)

            # 按创建时间倒序
            qs = qs.order_by('-create_time')

            # 分页
            paginator = Paginator(qs, page_size)
            try:
                page_obj = paginator.page(page)
            except Exception:
                return Response({
                    'code': 0, 'msg': '获取成功',
                    'data': {'list': [], 'has_more': False, 'page': page, 'page_size': page_size}
                })

            records = list(page_obj)
            fadan_ids = [r.id for r in records]

            # 批量获取图片，按用途分组
            zhengju_map = {}   # key: fadan_id, value: [url, ...]
            shensu_map = {}
            if fadan_ids:
                tupians = FadanShensuTupian.objects.filter(
                    fadan_id__in=fadan_ids
                ).values('fadan_id', 'tupian_url', 'yongtu')
                for t in tupians:
                    fid = t['fadan_id']
                    url = t['tupian_url']
                    if t['yongtu'] == 1:
                        zhengju_map.setdefault(fid, []).append(url)
                    else:
                        shensu_map.setdefault(fid, []).append(url)

            # 组装返回数据
            chufa_list = []
            for r in records:
                rid = r.id
                item = {
                    'id': rid,
                    'beichufa_id': r.beichufa_id,
                    'guanliandingdan_id': r.guanliandingdan_id or '',
                    'chufaliyou': r.chufaliyou or '',
                    'fakuanjine': str(r.fakuanjine),
                    'zhuangtai': r.zhuangtai,
                    'yingxiang_qiangdan': r.yingxiang_qiangdan,
                    'shensuliyou': r.shensuliyou or '',
                    'bohuiliyou': r.bohuiliyou or '',
                    'zhengju_tupian': zhengju_map.get(rid, []),   # 证据图片
                    'shensu_tupian': shensu_map.get(rid, []),     # 申诉图片
                    'create_time': r.create_time.strftime('%Y-%m-%d %H:%M:%S') if r.create_time else '',
                    'update_time': r.update_time.strftime('%Y-%m-%d %H:%M:%S') if r.update_time else '',
                }
                chufa_list.append(item)

            has_more = page_obj.has_next()
            return Response({
                'code': 0,
                'msg': '获取成功',
                'data': {
                    'list': chufa_list,
                    'has_more': has_more,
                    'page': page,
                    'page_size': page_size,
                }
            })

        except Exception as e:
            logger.error(f"获取罚款列表异常 {yonghuid if 'yonghuid' in locals() else ''}: {e}", exc_info=True)
            return Response({'code': 99, 'msg': '系统繁忙'}, status=500)



class FaKuanShenSuView(APIView):
    """
    罚款申诉提交/修改接口
    路径：POST /yonghu/fkss
    参数：
        fadan_id: 罚单ID
        shensu_liyou: 申诉理由
        shensu_tupian_urls: 图片相对URL数组（可空数组，但至少要有理由）
    逻辑：
        - 仅待缴纳状态且无驳回理由的罚单可申诉
        - 允许对已有申诉进行修改：先删除旧申诉图片（yongtu=2），再添加新图片
    """
    permission_classes = [IsAuthenticated, DashouPermission]

    def post(self, request):
        try:
            user_main = request.user
            yonghuid = user_main.yonghuid
            fadan_id = request.data.get('fadan_id')
            shensu_liyou = request.data.get('shensu_liyou', '').strip()
            tupian_urls = request.data.get('shensu_tupian_urls', [])

            if not fadan_id:
                return Response({'code': 400, 'msg': '缺少罚款ID'}, status=400)
            if not shensu_liyou:
                return Response({'code': 400, 'msg': '请输入申诉理由'}, status=400)

            # 查询罚单，确保属于当前打手
            try:
                fadan = Fadan.objects.get(id=fadan_id, beichufa_id=yonghuid)
            except Fadan.DoesNotExist:
                return Response({'code': 404, 'msg': '罚单不存在或无权操作'}, status=404)

            # 只允许待缴纳状态（状态1）且没有驳回理由的罚单申诉
            if fadan.zhuangtai != 1:
                return Response({'code': 400, 'msg': '当前状态不可申诉'}, status=400)
            if fadan.bohuiliyou:
                return Response({'code': 400, 'msg': '该罚单申诉已被驳回，不可再次申诉'}, status=400)

            # 更新罚单状态为申诉中，并记录理由
            fadan.zhuangtai = 3
            fadan.shensuliyou = shensu_liyou
            fadan.save()

            # 删除旧的申诉图片（yongtu=2），仅删除打手自己上传的申诉图
            FadanShensuTupian.objects.filter(fadan=fadan, yongtu=2).delete()

            # 插入新上传的申诉图片
            for url in tupian_urls:
                FadanShensuTupian.objects.create(
                    fadan=fadan,
                    beichufa_id=yonghuid,
                    tupian_url=url,
                    yongtu=2
                )

            return Response({'code': 0, 'msg': '申诉提交成功'})

        except Exception as e:
            logger.error(f"罚款申诉异常 {yonghuid if 'yonghuid' in locals() else ''}: {e}", exc_info=True)
            return Response({'code': 99, 'msg': '系统繁忙'}, status=500)







# 需要替换为你自己项目中的导入路径
from shangpin.models import Czjilu
import string  # 【致命错误修正】必须导入 string
from django.views import View

logger = logging.getLogger('xiaochengxu')

# ==================== 1. 罚款支付下单接口 ====================
class FaKuanPayView(APIView):
    """
    罚款微信支付下单接口（完全照抄 YajinGoumai）
    路径：POST /yonghu/fkjn
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            fadan_id = request.data.get('fadan_id')
            if not fadan_id:
                return Response({'code': 400, 'message': '参数不完整'}, status=status.HTTP_400_BAD_REQUEST)

            try:
                fadan = Fadan.objects.get(id=fadan_id, beichufa_id=request.user.yonghuid)
            except Fadan.DoesNotExist:
                return Response({'code': 404, 'message': '罚单不存在或不属于您'}, status=status.HTTP_404_NOT_FOUND)

            if fadan.zhuangtai not in [1, 3]:
                return Response({'code': 400, 'message': '罚单当前状态不可支付'}, status=status.HTTP_400_BAD_REQUEST)

            jine = float(fadan.fakuanjine)

            timestamp_ms = int(time.time() * 1000)
            timestamp_ns = int(time.time_ns() // 1000) % 1000000
            random_num = random.randint(0, 99)
            dingdanid = f"FK{timestamp_ms:011d}{timestamp_ns:06d}{random_num:02d}"

            chongzhi_jilu = Czjilu.objects.create(
                dingdan_id=dingdanid,
                zhuangtai=9,
                yonghuid=request.user.yonghuid,
                jine=jine,
                leixing=4,
                shuoming=settings.FAKUAN_PAY_DESCRIPTION
            )

            try:
                pay_params = self.generate_wechat_pay_params(
                    dingdanid=dingdanid,
                    jine=jine,
                    openid=request.user.openid,
                    pay_type='fakuan'
                )
            except Exception as e:
                chongzhi_jilu.delete()
                logger.error(f"生成微信支付参数失败: {str(e)}")
                return Response({
                    'code': 500,
                    'message': f'支付参数生成失败: {str(e)}'
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            return Response({
                'code': 200,
                'message': '支付参数生成成功',
                'payParams': pay_params,
                'dingdanid': dingdanid
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"罚款支付下单接口异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': '服务器内部错误，请稍后重试'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def generate_wechat_pay_params(self, dingdanid, jine, openid, pay_type):
        APPID = settings.WEIXIN_APPID
        MCHID = settings.WEIXIN_MCHID
        KEY = settings.WEIXIN_SHANGHUMIYAO

        if pay_type == 'fakuan':
            PAY_DESCRIPTION = settings.FAKUAN_PAY_DESCRIPTION
            NOTIFY_URL = settings.FAKUAN_PAY_NOTIFY_URL   # 回调地址在这里
        else:
            raise Exception('未知的支付类型')

        nonce_str = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
        total_fee = int(jine * 100)
        trade_type = 'JSAPI'
        user_ip = self.get_client_ip()

        # 第一次签名
        sign_data = {
            'appid': APPID,
            'mch_id': MCHID,
            'nonce_str': nonce_str,
            'body': PAY_DESCRIPTION,
            'out_trade_no': dingdanid,
            'total_fee': total_fee,
            'spbill_create_ip': user_ip,
            'notify_url': NOTIFY_URL,    # 关键：把回调地址传入
            'trade_type': trade_type,
            'openid': openid
        }

        sorted_sign_data = sorted(sign_data.items(), key=lambda x: x[0])
        sign_string = '&'.join([f"{key}={value}" for key, value in sorted_sign_data if value])
        sign_string += f'&key={KEY}'
        sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest().upper()

        # 构建 XML，这里必须包含 notify_url
        xml_data = f"""<xml>
<appid>{APPID}</appid>
<body>{PAY_DESCRIPTION}</body>
<mch_id>{MCHID}</mch_id>
<nonce_str>{nonce_str}</nonce_str>
<notify_url>{NOTIFY_URL}</notify_url>
<openid>{openid}</openid>
<out_trade_no>{dingdanid}</out_trade_no>
<spbill_create_ip>{user_ip}</spbill_create_ip>
<total_fee>{total_fee}</total_fee>
<trade_type>{trade_type}</trade_type>
<sign>{sign}</sign>
</xml>"""

        response = requests.post(
            'https://api.mch.weixin.qq.com/pay/unifiedorder',
            data=xml_data.encode('utf-8'),
            headers={'Content-Type': 'application/xml'},
            timeout=10
        )

        root = ET.fromstring(response.content)
        return_code = root.find('return_code').text
        result_code = root.find('result_code').text

        if return_code == 'SUCCESS' and result_code == 'SUCCESS':
            prepay_id = root.find('prepay_id').text
            timestamp = str(int(time.time()))
            nonce_str = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
            package = f'prepay_id={prepay_id}'
            sign_type = 'MD5'

            pay_sign_data = {
                'appId': APPID,
                'timeStamp': timestamp,
                'nonceStr': nonce_str,
                'package': package,
                'signType': sign_type
            }

            sorted_pay_sign_data = sorted(pay_sign_data.items(), key=lambda x: x[0])
            pay_sign_string = '&'.join([f"{key}={value}" for key, value in sorted_pay_sign_data])
            pay_sign_string += f'&key={KEY}'
            pay_sign = hashlib.md5(pay_sign_string.encode('utf-8')).hexdigest().upper()

            return {
                'appId': APPID,
                'timeStamp': timestamp,
                'nonceStr': nonce_str,
                'package': package,
                'signType': sign_type,
                'paySign': pay_sign
            }
        else:
            err_code = root.find('err_code')
            err_code_des = root.find('err_code_des')
            error_details = f"return_code: {return_code}"
            if err_code is not None:
                error_details += f", err_code: {err_code.text}"
            if err_code_des is not None:
                error_details += f", err_code_des: {err_code_des.text}"
            raise Exception(f"微信支付下单失败: {error_details}")

    def get_client_ip(self):
        request = self.request
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip if ip else '127.0.0.1'

# ==================== 2. 罚款支付回调接口 ====================
class FaKuanHuitiaoView(View):
    """
    罚款支付回调接口（严格借鉴 YajinHuitiao 接口，参数一个不少）
    路径：POST /yonghu/fk_huitiao
    """
    def post(self, request):
        try:
            # 1. 解析微信回调XML数据
            request_body = request.body
            logger.info(f"收到微信支付回调，原始数据: {request_body.decode('utf-8')}")

            root = ET.fromstring(request_body)

            # 获取关键字段
            return_code = root.find('return_code').text
            result_code = root.find('result_code').text
            out_trade_no = root.find('out_trade_no').text  # 订单ID
            transaction_id = root.find('transaction_id').text  # 微信交易号
            total_fee = int(root.find('total_fee').text)  # 支付金额（分）

            logger.info(f"回调数据解析: 订单{out_trade_no}, 状态{return_code}/{result_code}, 金额{total_fee}分")

            # 2. 验证基本返回状态
            if return_code != 'SUCCESS' or result_code != 'SUCCESS':
                logger.warning(f"微信支付回调状态异常: {return_code}/{result_code}")
                return self.wechat_response('FAIL', '支付失败')

            # 3. 验证签名（确保是微信发来的）
            if not self.verify_signature(request_body):
                logger.error(f"签名验证失败: {out_trade_no}")
                return self.wechat_response('FAIL', '签名验证失败')

            # 4. 查询订单
            try:
                order = Czjilu.objects.get(dingdan_id=out_trade_no)
                logger.info(f"找到订单: {order.dingdan_id}, 状态: {order.zhuangtai}, 金额: {order.jine}")
            except Czjilu.DoesNotExist:
                logger.error(f"订单不存在: {out_trade_no}")
                return self.wechat_response('FAIL', '订单不存在')

            # 5. 检查订单状态是否为未支付（9）
            if order.zhuangtai != 9:
                logger.warning(f"订单状态不是未支付: {order.dingdan_id}, 当前状态: {order.zhuangtai}")
                # 已处理过的订单直接返回成功，避免微信重复回调
                return self.wechat_response('SUCCESS', 'OK')

            # 6. 验证金额（微信返回的是分，需要转换）
            wechat_amount_yuan = total_fee / 100  # 转换为元
            order_amount_yuan = float(order.jine)  # 订单金额（元）

            # 允许1分钱的误差（浮点数比较）
            if abs(wechat_amount_yuan - order_amount_yuan) > 0.01:
                logger.error(f"金额不一致: 订单金额{order_amount_yuan}元, 支付金额{wechat_amount_yuan}元")
                return self.wechat_response('FAIL', '金额不一致')

            # 7. 更新订单状态为已支付（3）
            order.zhuangtai = 3
            order.save(update_fields=['zhuangtai'])
            logger.info(f"订单状态更新成功: {order.dingdan_id} -> 3")

            # 8. 更新罚单状态为已缴纳（2）
            try:
                # 根据订单中的用户ID和金额匹配待缴纳的罚单
                fadan = Fadan.objects.filter(
                    beichufa_id=order.yonghuid,
                    fakuanjine=order.jine,
                    zhuangtai__in=[1, 3]
                ).first()
                if fadan:
                    fadan.zhuangtai = 2  # 已缴纳
                    fadan.save(update_fields=['zhuangtai'])
                    logger.info(f"罚单 {fadan.id} 已自动标记为已缴纳")

                    from yonghu.fadan_fenhong_utils import process_fadan_fenhong
                    success, msg = process_fadan_fenhong(fadan.id)
                    if not success:
                        logger.error(f"罚单 {fadan.id} 分红处理失败: {msg}")
                    else:
                        logger.info(f"罚单 {fadan.id} 分红处理完成: {msg}")



                    #from utils.fadan_utils import fadan_fenhong
                    #fadan_fenhong(fadan.id)


            except Exception as e:
                logger.error(f"更新罚单状态失败: {str(e)}", exc_info=True)

            # 9. 更新收支记录表
            try:
                from peizhi.models import Szjilu
                from decimal import Decimal

                # 获取订单金额（确保是Decimal类型）
                jine_decimal = Decimal(str(order.jine)) if not isinstance(order.jine, Decimal) else order.jine

                from dingdan.utils import update_daily_income
                update_daily_income(jine_decimal)

                # 查询或创建ID=1的收支记录
                szjilu, created = Szjilu.objects.get_or_create(
                    id=1,
                    defaults={
                        'zongsy': Decimal('0.00'),
                        'zongls': Decimal('0.00'),
                        'zongzc': Decimal('0.00'),
                        'jrzc': Decimal('0.00'),
                        'jrls': Decimal('0.00')
                    }
                )

                # 更新三个字段
                szjilu.zongsy += jine_decimal  # 总收益
                szjilu.zongls += jine_decimal  # 总流水
                szjilu.jrls += jine_decimal  # 今日流水

                szjilu.save()



                logger.info(f"收支记录更新成功: 订单{order.dingdan_id}, 金额{jine_decimal}元")

            except Exception as e:
                # 收支记录更新失败不影响主流程，只记录日志
                logger.error(f"更新收支记录失败: {str(e)}", exc_info=True)

            # 10. 返回成功响应给微信
            logger.info(f"罚款支付回调处理完成: {out_trade_no}")
            return self.wechat_response('SUCCESS', 'OK')

        except ET.ParseError as e:
            logger.error(f"XML解析失败: {str(e)}")
            return self.wechat_response('FAIL', '数据格式错误')
        except Exception as e:
            logger.error(f"罚款支付回调处理异常: {str(e)}", exc_info=True)
            # 返回FAIL让微信重试
            return self.wechat_response('FAIL', '处理异常')

    def verify_signature(self, xml_data):
        """验证微信支付签名（完全照搬 YajinHuitiao 的 verify_signature）"""
        try:
            root = ET.fromstring(xml_data)
            sign = root.find('sign').text

            if not sign:
                logger.error("签名字段不存在")
                return False

            # 获取所有参数并排除sign
            params = {}
            for child in root:
                if child.tag != 'sign' and child.text is not None:
                    params[child.tag] = child.text

            # 按照参数名ASCII码从小到大排序
            sorted_params = sorted(params.items(), key=lambda x: x[0])

            # 拼接字符串
            sign_string = '&'.join([f"{key}={value}" for key, value in sorted_params if value])
            sign_string += f'&key={settings.WEIXIN_SHANGHUMIYAO}'

            # 计算签名
            calculated_sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest().upper()

            is_valid = sign == calculated_sign
            if not is_valid:
                logger.error(f"签名验证失败: 计算签名{calculated_sign}, 收到签名{sign}")

            return is_valid

        except Exception as e:
            logger.error(f"验证签名异常: {str(e)}")
            return False

    def wechat_response(self, return_code, return_msg):
        """返回微信支付回调响应（完全照搬 YajinHuitiao 的 wechat_response）"""
        xml_response = f"""<xml>
<return_code><![CDATA[{return_code}]]></return_code>
<return_msg><![CDATA[{return_msg}]]></return_msg>
</xml>"""

        logger.info(f"返回微信响应: {return_code} - {return_msg}")
        return HttpResponse(xml_response, content_type='application/xml')


# ==================== 3. 支付轮询接口 ====================
class FaKuanPayPollView(APIView):
    """罚款支付轮询接口（借鉴 YajinLunxun）"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            dingdanid = request.data.get('dingdanid')
            if not dingdanid:
                return Response({'code': 400, 'message': '订单ID不能为空'})

            order = Czjilu.objects.get(dingdan_id=dingdanid, yonghuid=request.user.yonghuid)
            if order.zhuangtai == 3:
                return Response({'code': 200, 'message': '支付成功'})
            else:
                return Response({'code': 400, 'message': '订单尚未支付'})
        except Czjilu.DoesNotExist:
            return Response({'code': 400, 'message': '订单不存在'})
        except Exception as e:
            logger.error(f"轮询异常: {str(e)}")
            return Response({'code': 500, 'message': '服务器内部错误'})


# ==================== 4. 支付失败处理接口 ====================
class FaKuanPayFailView(APIView):
    """罚款支付失败处理接口（借鉴 YajinShibai）"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            dingdanid = request.data.get('dingdanid')
            if not dingdanid:
                return Response({'code': 400, 'message': '订单ID不能为空'})

            order = Czjilu.objects.get(dingdan_id=dingdanid, yonghuid=request.user.yonghuid)
            if order.zhuangtai == 9:  # 未支付
                order.delete()
                logger.info(f"用户{request.user.yonghuid}删除未支付订单: {dingdanid}")
                return Response({'code': 200, 'message': '订单已删除'})
            else:
                return Response({'code': 400, 'message': '订单状态不是未支付，无法删除'})
        except Czjilu.DoesNotExist:
            return Response({'code': 400, 'message': '订单不存在'})
        except Exception as e:
            logger.error(f"支付失败处理异常: {str(e)}")
            return Response({'code': 500, 'message': '服务器内部错误'})







from shangpin.models import Czjilu
from dengji.models import Chenghao, ShenheJilu, KaoheCishuFeiyong, YonghuChenghao
from dengji.utils import get_tag_fee   # 您需要确保此函数已定义

logger = logging.getLogger('xiaochengxu')
from dengji.utils import create_shenhe_jilu
from dengji.utils import validate_shenheguan


'''class KaohePayView(APIView):
    """
    考核支付下单接口
    路径：POST /yonghu/khzf
    参数：
        tag_id: 标签ID
        game_nick: 游戏昵称
        remark: 备注
        reapply: 是否再次申请 (true/false)
        jilu_id: 再次申请时的原记录ID（reapply=true时必传）
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            user = request.user
            tag_id = request.data.get('tag_id')
            game_nick = request.data.get('game_nick', '').strip()
            remark = request.data.get('remark', '').strip()
            reapply = request.data.get('reapply', False)
            jilu_id = request.data.get('jilu_id') if reapply else None

            if not tag_id or not game_nick:
                return Response({'code': 400, 'message': '标签ID和游戏昵称不能为空'})

            # 1. 验证标签
            try:
                chenghao = Chenghao.objects.get(id=tag_id)
            except Chenghao.DoesNotExist:
                return Response({'code': 404, 'message': '标签不存在'})

            # 2. 检查用户是否已拥有该标签
            if YonghuChenghao.objects.filter(yonghu=user, chenghao=chenghao).exists():
                return Response({'code': 400, 'message': '您已拥有该标签，无需重复考核'})

            # 3. 检查是否有未完成的申请
            if ShenheJilu.objects.filter(
                shenqingren_id=user.yonghuid,
                chenghao=chenghao,
                zhuangtai__in=[0, 3]   # 审核中、待审核
            ).exists():
                return Response({'code': 400, 'message': '您有未完成的考核申请，请等待结果'})

            # 4. 计算考核次数
            if reapply and jilu_id:
                last = ShenheJilu.objects.filter(
                    jilu_id=jilu_id, shenqingren_id=user.yonghuid, zhuangtai=2
                ).first()
                if not last:
                    return Response({'code': 400, 'message': '原记录不存在或状态不是未通过'})
                new_cishu = last.cishu + 1
            else:
                max_cishu = ShenheJilu.objects.filter(
                    shenqingren_id=user.yonghuid,
                    chenghao=chenghao,
                    zhuangtai__in=[1, 2]
                ).aggregate(max=models.Max('cishu'))['max'] or 0
                new_cishu = max_cishu + 1

            # 5. 获取本次费用
            fee = get_tag_fee(chenghao, new_cishu)
            if fee <= 0:
                return Response({'code': 400, 'message': '本次费用为0，请直接使用免费申请接口'})

            # 6. 生成订单ID
            timestamp_ms = int(time.time() * 1000)
            timestamp_ns = int(time.time_ns() // 1000) % 1000000
            random_num = random.randint(0, 99)
            dingdanid = f"KH{timestamp_ms:011d}{timestamp_ns:06d}{random_num:02d}"

            # 7. 创建支付订单（Czjilu）
            order = Czjilu.objects.create(
                dingdan_id=dingdanid,
                zhuangtai=9,           # 未支付
                yonghuid=user.yonghuid,
                jine=float(fee),
                leixing=5,             # 5-考核支付
                shuoming=settings.KAOHE_PAY_DESCRIPTION
            )

            # 8. 构造 attach 参数（微信回调原样返回）

            # 在原有下单逻辑中增加
            shenheguan_id = request.data.get('shenheguan_id', '').strip()
            attach_data = {
                'tag_id': tag_id,
                'game_nick': game_nick,
                'remark': remark,
                'reapply': reapply,
                'jilu_id': jilu_id if reapply else None,
                'shenheguan_id': shenheguan_id,  # 新增
            }
            # 然后将 attach_data 序列化后作为 attach 参数传给微信支付统一下单

            attach_str = json.dumps(attach_data, ensure_ascii=False)

            # 9. 生成微信支付参数
            try:
                pay_params = self.generate_wechat_pay_params(
                    dingdanid=dingdanid,
                    jine=float(fee),
                    openid=user.openid,
                    attach=attach_str,
                    pay_type='kaohe'
                )
            except Exception as e:
                order.delete()  # 下单失败，删除订单记录
                logger.error(f"生成微信支付参数失败: {str(e)}")
                return Response({'code': 500, 'message': f'支付参数生成失败: {str(e)}'})

            return Response({
                'code': 200,
                'message': '支付参数生成成功',
                'payParams': pay_params,
                'dingdanid': dingdanid
            })

        except Exception as e:
            logger.error(f"考核支付下单异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'message': '服务器内部错误'})

    def generate_wechat_pay_params(self, dingdanid, jine, openid, attach, pay_type):
        """生成微信JSAPI支付参数（完整照搬罚款支付逻辑，仅修改描述和回调地址）"""
        APPID = settings.WEIXIN_APPID
        MCHID = settings.WEIXIN_MCHID
        KEY = settings.WEIXIN_SHANGHUMIYAO

        if pay_type == 'kaohe':
            PAY_DESCRIPTION = settings.KAOHE_PAY_DESCRIPTION
            NOTIFY_URL = settings.KAOHE_PAY_NOTIFY_URL
        else:
            raise Exception('未知支付类型')

        nonce_str = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
        total_fee = int(jine * 100)
        trade_type = 'JSAPI'
        user_ip = self.get_client_ip()

        # 第一次签名（统一下单）
        sign_data = {
            'appid': APPID,
            'mch_id': MCHID,
            'nonce_str': nonce_str,
            'body': PAY_DESCRIPTION,
            'out_trade_no': dingdanid,
            'total_fee': total_fee,
            'spbill_create_ip': user_ip,
            'notify_url': NOTIFY_URL,
            'trade_type': trade_type,
            'openid': openid,
            'attach': attach,                 # 附加数据，回调时原样返回
        }

        sorted_sign_data = sorted(sign_data.items(), key=lambda x: x[0])
        sign_string = '&'.join([f"{key}={value}" for key, value in sorted_sign_data if value])
        sign_string += f'&key={KEY}'
        sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest().upper()

        # 构建XML请求体
        xml_data = f"""<xml>
<appid>{APPID}</appid>
<body>{PAY_DESCRIPTION}</body>
<mch_id>{MCHID}</mch_id>
<nonce_str>{nonce_str}</nonce_str>
<notify_url>{NOTIFY_URL}</notify_url>
<openid>{openid}</openid>
<out_trade_no>{dingdanid}</out_trade_no>
<spbill_create_ip>{user_ip}</spbill_create_ip>
<total_fee>{total_fee}</total_fee>
<trade_type>{trade_type}</trade_type>
<attach><![CDATA[{attach}]]></attach>
<sign>{sign}</sign>
</xml>"""

        response = requests.post(
            'https://api.mch.weixin.qq.com/pay/unifiedorder',
            data=xml_data.encode('utf-8'),
            headers={'Content-Type': 'application/xml'},
            timeout=10
        )

        root = ET.fromstring(response.content)
        return_code = root.find('return_code').text
        result_code = root.find('result_code').text

        if return_code == 'SUCCESS' and result_code == 'SUCCESS':
            prepay_id = root.find('prepay_id').text
            timestamp = str(int(time.time()))
            nonce_str = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
            package = f'prepay_id={prepay_id}'
            sign_type = 'MD5'

            # 第二次签名（前端调起支付用）
            pay_sign_data = {
                'appId': APPID,
                'timeStamp': timestamp,
                'nonceStr': nonce_str,
                'package': package,
                'signType': sign_type,
            }
            sorted_pay_sign_data = sorted(pay_sign_data.items(), key=lambda x: x[0])
            pay_sign_string = '&'.join([f"{key}={value}" for key, value in sorted_pay_sign_data])
            pay_sign_string += f'&key={KEY}'
            pay_sign = hashlib.md5(pay_sign_string.encode('utf-8')).hexdigest().upper()

            return {
                'appId': APPID,
                'timeStamp': timestamp,
                'nonceStr': nonce_str,
                'package': package,
                'signType': sign_type,
                'paySign': pay_sign,
            }
        else:
            err_code = root.find('err_code')
            err_code_des = root.find('err_code_des')
            error_details = f"return_code: {return_code}"
            if err_code is not None:
                error_details += f", err_code: {err_code.text}"
            if err_code_des is not None:
                error_details += f", err_code_des: {err_code_des.text}"
            raise Exception(f"微信支付下单失败: {error_details}")

    def get_client_ip(self):
        request = self.request
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip if ip else '127.0.0.1'



from dengji.utils import create_shenhe_jilu
from dengji.utils import validate_shenheguan
class KaohePayCallbackView(View):
    """
    考核支付回调接口
    路径：/yonghu/kh_huitiao
    """
    def post(self, request):
        try:
            request_body = request.body
            logger.info(f"收到考核支付回调: {request_body.decode('utf-8')}")

            root = ET.fromstring(request_body)

            return_code = root.find('return_code').text
            result_code = root.find('result_code').text
            out_trade_no = root.find('out_trade_no').text
            transaction_id = root.find('transaction_id').text
            total_fee = int(root.find('total_fee').text)

            if return_code != 'SUCCESS' or result_code != 'SUCCESS':
                logger.warning(f"支付状态异常: {return_code}/{result_code}")
                return self.wechat_response('FAIL', '支付失败')

            # 验证签名
            if not self.verify_signature(request_body):
                logger.error("签名验证失败")
                return self.wechat_response('FAIL', '签名验证失败')

            # 查找订单
            try:
                order = Czjilu.objects.get(dingdan_id=out_trade_no, leixing=5)
            except Czjilu.DoesNotExist:
                logger.error(f"考核订单不存在: {out_trade_no}")
                return self.wechat_response('FAIL', '订单不存在')

            if order.zhuangtai != 9:
                logger.warning(f"订单状态非未支付: {order.zhuangtai}")
                return self.wechat_response('SUCCESS', 'OK')

            # 验证金额
            wechat_yuan = total_fee / 100
            if abs(wechat_yuan - float(order.jine)) > 0.01:
                logger.error(f"金额不一致: 订单{order.jine}, 回调{wechat_yuan}")
                return self.wechat_response('FAIL', '金额不一致')

            # 更新订单状态为已支付
            order.zhuangtai = 3
            order.save()

            # 解析 attach 获取业务参数
            attach_element = root.find('attach')
            if attach_element is not None and attach_element.text:
                try:
                    attach_data = json.loads(attach_element.text)
                    tag_id = attach_data.get('tag_id')
                    game_nick = attach_data.get('game_nick', '')
                    remark = attach_data.get('remark', '')
                    reapply = attach_data.get('reapply', False)
                    jilu_id = attach_data.get('jilu_id') if reapply else None
                    shenheguan_id = attach_data.get('shenheguan_id', '').strip()  # 新增

                    # 获取用户
                    user = UserMain.objects.get(yonghuid=order.yonghuid)

                    # 尝试获取标签和费用，用于验证指定考核官是否合法
                    try:
                        chenghao = Chenghao.objects.get(id=tag_id)
                        # 重新计算费用以便验证（实际上订单金额即费用）
                        # 若指定了考核官，进行校验；不合法则忽略指定
                        if shenheguan_id:
                            valid, _ = validate_shenheguan(shenheguan_id, chenghao.bankuai, order.jine, user)
                            if not valid:
                                logger.warning(f"指定考核官无效，忽略: {shenheguan_id}")
                                shenheguan_id = ''  # 忽略无效指定
                    except Exception as e:
                        logger.error(f"验证指定考核官异常: {e}")
                        shenheguan_id = ''  # 异常也忽略

                    # 调用创建审核记录的函数
                    success, msg, record = create_shenhe_jilu(
                        user=user,
                        tag_id=tag_id,
                        game_nick=game_nick,
                        remark=remark,
                        reapply=reapply,
                        jilu_id=jilu_id,
                        shenheguan_id=shenheguan_id,   # 新增
                    )
                    if not success:
                        logger.error(f"创建审核记录失败: {msg}")
                except Exception as e:
                    logger.error(f"解析attach或创建审核记录失败: {e}", exc_info=True)

            # 更新收支记录
            try:
                from peizhi.models import Szjilu
                from decimal import Decimal
                from dingdan.utils import update_daily_income

                jine_decimal = Decimal(str(order.jine))
                update_daily_income(jine_decimal)

                szjilu, _ = Szjilu.objects.get_or_create(
                    id=1,
                    defaults={
                        'zongsy': Decimal('0.00'),
                        'zongls': Decimal('0.00'),
                        'zongzc': Decimal('0.00'),
                        'jrzc': Decimal('0.00'),
                        'jrls': Decimal('0.00'),
                    }
                )
                szjilu.zongsy += jine_decimal
                szjilu.zongls += jine_decimal
                szjilu.jrls += jine_decimal
                szjilu.save()
            except Exception as e:
                logger.error(f"更新收支记录失败: {e}", exc_info=True)

            return self.wechat_response('SUCCESS', 'OK')

        except ET.ParseError as e:
            logger.error(f"XML解析失败: {e}")
            return self.wechat_response('FAIL', '数据格式错误')
        except Exception as e:
            logger.error(f"考核支付回调异常: {e}", exc_info=True)
            return self.wechat_response('FAIL', '处理异常')

    def verify_signature(self, xml_data):
        """验证微信支付签名（与罚款回调完全一致）"""
        try:
            root = ET.fromstring(xml_data)
            sign = root.find('sign').text
            if not sign:
                return False

            params = {}
            for child in root:
                if child.tag != 'sign' and child.text is not None:
                    params[child.tag] = child.text

            sorted_params = sorted(params.items(), key=lambda x: x[0])
            sign_string = '&'.join([f"{key}={value}" for key, value in sorted_params if value])
            sign_string += f'&key={settings.WEIXIN_SHANGHUMIYAO}'
            calculated_sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest().upper()
            return sign == calculated_sign
        except Exception as e:
            logger.error(f"签名验证异常: {e}")
            return False

    def wechat_response(self, return_code, return_msg):
        xml = f"""<xml>
<return_code><![CDATA[{return_code}]]></return_code>
<return_msg><![CDATA[{return_msg}]]></return_msg>
</xml>"""
        return HttpResponse(xml, content_type='application/xml')'''


class KaohePayView(APIView):
    """
    考核支付下单接口
    路径：POST /yonghu/khzf
    参数：
        tag_id: 标签ID
        game_nick: 游戏昵称
        remark: 备注
        reapply: 是否再次申请 (true/false)
        jilu_id: 再次申请时的原记录ID（reapply=true时必传）
        shenheguan_id: 指定考核官ID（可选）
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            user = request.user
            tag_id = request.data.get('tag_id')
            game_nick = request.data.get('game_nick', '').strip()
            remark = request.data.get('remark', '').strip()
            reapply = request.data.get('reapply', False)
            jilu_id = request.data.get('jilu_id') if reapply else None
            shenheguan_id = request.data.get('shenheguan_id', '').strip()

            logger.info(f"用户 {user.yonghuid} 发起考核支付申请，标签ID: {tag_id}, 再次申请: {reapply}")

            if not tag_id or not game_nick:
                logger.warning(f"用户 {user.yonghuid} 参数不完整: tag_id={tag_id}, game_nick={game_nick}")
                return Response({'code': 400, 'message': '标签ID和游戏昵称不能为空'})

            # 1. 检查是否有未支付的考核订单
            unpaid_order = Czjilu.objects.filter(
                yonghuid=user.yonghuid,
                leixing=5,
                zhuangtai=9
            ).exists()
            if unpaid_order:
                logger.warning(f"用户 {user.yonghuid} 存在未支付的考核订单")
                return Response({'code': 400, 'message': '您有未支付的考核订单，请先完成支付或取消'})

            # 2. 验证标签
            try:
                chenghao = Chenghao.objects.get(id=tag_id)
                logger.info(f"标签验证通过: {chenghao.mingcheng}")
            except Chenghao.DoesNotExist:
                logger.error(f"标签不存在: tag_id={tag_id}")
                return Response({'code': 404, 'message': '标签不存在'})

            # 3. 检查用户是否已拥有该标签
            if YonghuChenghao.objects.filter(yonghu=user, chenghao=chenghao).exists():
                logger.warning(f"用户 {user.yonghuid} 已拥有标签 {chenghao.mingcheng}")
                return Response({'code': 400, 'message': '您已拥有该标签，无需重复考核'})

            # 4. 检查是否有未完成的申请
            if ShenheJilu.objects.filter(
                    shenqingren_id=user.yonghuid,
                    chenghao=chenghao,
                    zhuangtai__in=[0, 3]  # 审核中、待审核
            ).exists():
                logger.warning(f"用户 {user.yonghuid} 有未完成的考核申请")
                return Response({'code': 400, 'message': '您有未完成的考核申请，请等待结果'})

            # 5. 计算考核次数和费用
            if reapply and jilu_id:
                last = ShenheJilu.objects.filter(
                    jilu_id=jilu_id,
                    shenqingren_id=user.yonghuid,
                    zhuangtai=2
                ).first()
                if not last:
                    logger.warning(f"用户 {user.yonghuid} 再次申请失败：原记录不存在或状态不是未通过，jilu_id={jilu_id}")
                    return Response({'code': 400, 'message': '原记录不存在或状态不是未通过'})
                new_cishu = last.cishu + 1
                logger.info(f"再次申请，原记录ID: {jilu_id}，新次数: {new_cishu}")
            else:
                max_cishu = ShenheJilu.objects.filter(
                    shenqingren_id=user.yonghuid,
                    chenghao=chenghao,
                    zhuangtai__in=[1, 2]
                ).aggregate(max=models.Max('cishu'))['max'] or 0
                new_cishu = max_cishu + 1
                logger.info(f"首次申请，计算次数: {new_cishu}")

            # 6. 获取本次费用
            fee = get_tag_fee(chenghao, new_cishu)
            logger.info(f"本次考核费用: {fee}元，次数: {new_cishu}")

            if fee <= 0:
                logger.warning(f"费用为0，应使用免费申请接口，tag_id={tag_id}, cishu={new_cishu}")
                return Response({'code': 400, 'message': '本次费用为0，请直接使用免费申请接口'})

            # 7. 生成订单ID
            timestamp_ms = int(time.time() * 1000)
            timestamp_ns = int(time.time_ns() // 1000) % 1000000
            random_num = random.randint(0, 99)
            dingdanid = f"KH{timestamp_ms:011d}{timestamp_ns:06d}{random_num:02d}"
            logger.info(f"生成订单ID: {dingdanid}")

            # 8. 创建支付订单（Czjilu）
            order = Czjilu.objects.create(
                dingdan_id=dingdanid,
                zhuangtai=9,  # 未支付
                yonghuid=user.yonghuid,
                jine=float(fee),
                leixing=5,  # 5-考核支付
                shuoming=settings.KAOHE_PAY_DESCRIPTION
            )
            logger.info(f"创建支付订单成功: {dingdanid}")

            # 9. 保存考核支付临时上下文（用于回调时取业务参数）
            try:
                from dengji.models import KaohePayTemp
                KaohePayTemp.objects.create(
                    dingdan_id=dingdanid,
                    yonghuid=user.yonghuid,
                    tag_id=tag_id,
                    game_nick=game_nick,
                    remark=remark,
                    reapply=reapply,
                    jilu_id=jilu_id if reapply else None,
                    shenheguan_id=shenheguan_id,
                    cishu=new_cishu,
                    fee=fee,
                )
                logger.info(f"保存临时上下文成功: {dingdanid}")
            except Exception as e:
                logger.error(f"保存临时上下文失败: {str(e)}", exc_info=True)
                # 临时表保存失败应该回滚订单
                order.delete()
                return Response({'code': 500, 'message': '系统异常，请稍后重试'})

            # 10. 构造 attach 参数（只传订单ID，确保不超127字节）
            attach_str = json.dumps({'oid': dingdanid}, ensure_ascii=False)
            logger.info(f"attach内容: {attach_str}，长度: {len(attach_str.encode('utf-8'))}字节")

            # 11. 生成微信支付参数
            try:
                pay_params = self.generate_wechat_pay_params(
                    dingdanid=dingdanid,
                    jine=float(fee),
                    openid=user.openid,
                    attach=attach_str,
                    pay_type='kaohe'
                )
                logger.info(f"微信支付参数生成成功: {dingdanid}")
            except Exception as e:
                order.delete()  # 下单失败，删除订单记录
                # 同时删除临时表记录
                try:
                    from dengji.models import KaohePayTemp
                    KaohePayTemp.objects.filter(dingdan_id=dingdanid).delete()
                except Exception as del_e:
                    logger.error(f"删除临时表记录失败: {str(del_e)}")
                logger.error(f"生成微信支付参数失败: {str(e)}", exc_info=True)
                return Response({'code': 500, 'message': f'支付参数生成失败: {str(e)}'})

            return Response({
                'code': 200,
                'message': '支付参数生成成功',
                'payParams': pay_params,
                'dingdanid': dingdanid
            })

        except Exception as e:
            logger.error(f"考核支付下单异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'message': '服务器内部错误'})

    def generate_wechat_pay_params(self, dingdanid, jine, openid, attach, pay_type):
        """生成微信JSAPI支付参数"""
        APPID = settings.WEIXIN_APPID
        MCHID = settings.WEIXIN_MCHID
        KEY = settings.WEIXIN_SHANGHUMIYAO

        if pay_type == 'kaohe':
            PAY_DESCRIPTION = settings.KAOHE_PAY_DESCRIPTION
            NOTIFY_URL = settings.KAOHE_PAY_NOTIFY_URL
        else:
            raise Exception('未知支付类型')

        nonce_str = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
        total_fee = int(jine * 100)
        trade_type = 'JSAPI'
        user_ip = self.get_client_ip()

        logger.info(f"微信支付下单参数: out_trade_no={dingdanid}, total_fee={total_fee}, openid={openid}, ip={user_ip}")

        # 第一次签名（统一下单）
        sign_data = {
            'appid': APPID,
            'mch_id': MCHID,
            'nonce_str': nonce_str,
            'body': PAY_DESCRIPTION,
            'out_trade_no': dingdanid,
            'total_fee': total_fee,
            'spbill_create_ip': user_ip,
            'notify_url': NOTIFY_URL,
            'trade_type': trade_type,
            'openid': openid,
            'attach': attach,
        }

        sorted_sign_data = sorted(sign_data.items(), key=lambda x: x[0])
        sign_string = '&'.join([f"{key}={value}" for key, value in sorted_sign_data if value])
        sign_string += f'&key={KEY}'
        sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest().upper()

        # 构建XML请求体
        xml_data = f"""<xml>
<appid>{APPID}</appid>
<body>{PAY_DESCRIPTION}</body>
<mch_id>{MCHID}</mch_id>
<nonce_str>{nonce_str}</nonce_str>
<notify_url>{NOTIFY_URL}</notify_url>
<openid>{openid}</openid>
<out_trade_no>{dingdanid}</out_trade_no>
<spbill_create_ip>{user_ip}</spbill_create_ip>
<total_fee>{total_fee}</total_fee>
<trade_type>{trade_type}</trade_type>
<attach><![CDATA[{attach}]]></attach>
<sign>{sign}</sign>
</xml>"""

        logger.info(f"微信支付请求XML: {xml_data[:500]}...")  # 只打印前500字符

        response = requests.post(
            'https://api.mch.weixin.qq.com/pay/unifiedorder',
            data=xml_data.encode('utf-8'),
            headers={'Content-Type': 'application/xml'},
            timeout=10
        )

        logger.info(f"微信支付响应: {response.text}")

        root = ET.fromstring(response.content)

        # 安全获取return_code
        return_code_node = root.find('return_code')
        if return_code_node is None or return_code_node.text is None:
            logger.error(f"微信返回缺少return_code节点，原始内容: {response.text}")
            raise Exception('微信支付接口异常，缺少return_code')
        return_code = return_code_node.text

        # 安全获取result_code
        result_code_node = root.find('result_code')
        if result_code_node is None or result_code_node.text is None:
            logger.error(f"微信返回缺少result_code节点，原始内容: {response.text}")
            raise Exception('微信支付接口异常，缺少result_code')
        result_code = result_code_node.text

        if return_code == 'SUCCESS' and result_code == 'SUCCESS':
            prepay_id_node = root.find('prepay_id')
            if prepay_id_node is None or prepay_id_node.text is None:
                logger.error(f"统一下单成功但未返回prepay_id，原始内容: {response.text}")
                raise Exception('微信支付接口异常，缺少prepay_id')
            prepay_id = prepay_id_node.text

            timestamp = str(int(time.time()))
            nonce_str = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
            package = f'prepay_id={prepay_id}'
            sign_type = 'MD5'

            # 第二次签名（前端调起支付用）
            pay_sign_data = {
                'appId': APPID,
                'timeStamp': timestamp,
                'nonceStr': nonce_str,
                'package': package,
                'signType': sign_type,
            }
            sorted_pay_sign_data = sorted(pay_sign_data.items(), key=lambda x: x[0])
            pay_sign_string = '&'.join([f"{key}={value}" for key, value in sorted_pay_sign_data])
            pay_sign_string += f'&key={KEY}'
            pay_sign = hashlib.md5(pay_sign_string.encode('utf-8')).hexdigest().upper()

            logger.info(f"微信支付预下单成功，prepay_id={prepay_id}")

            return {
                'appId': APPID,
                'timeStamp': timestamp,
                'nonceStr': nonce_str,
                'package': package,
                'signType': sign_type,
                'paySign': pay_sign,
            }
        else:
            # 安全获取错误信息
            err_code_node = root.find('err_code')
            err_code = err_code_node.text if err_code_node is not None else '未知错误码'
            err_code_des_node = root.find('err_code_des')
            err_code_des = err_code_des_node.text if err_code_des_node is not None else '未知错误描述'
            error_details = f"return_code: {return_code}, result_code: {result_code}, err_code: {err_code}, err_code_des: {err_code_des}"
            logger.error(f"微信支付下单失败: {error_details}")
            raise Exception(f"微信支付下单失败: {error_details}")

    def get_client_ip(self):
        """获取客户端IP"""
        request = self.request
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR', '127.0.0.1')
        return ip if ip else '127.0.0.1'


class KaohePayCallbackView(View):
    """
    考核支付回调接口
    路径：/yonghu/kh_huitiao
    """

    def post(self, request):
        try:
            request_body = request.body
            logger.info(f"收到考核支付回调: {request_body.decode('utf-8')}")

            root = ET.fromstring(request_body)

            # 安全获取return_code
            return_code_node = root.find('return_code')
            if return_code_node is None or return_code_node.text is None:
                logger.error(f"微信回调XML缺少return_code节点，原始内容: {request_body.decode('utf-8')}")
                return self.wechat_response('FAIL', '数据格式错误')
            return_code = return_code_node.text

            # 安全获取result_code
            result_code_node = root.find('result_code')
            if result_code_node is None or result_code_node.text is None:
                logger.error(f"微信回调XML缺少result_code节点，原始内容: {request_body.decode('utf-8')}")
                return self.wechat_response('FAIL', '数据格式错误')
            result_code = result_code_node.text

            # 安全获取out_trade_no
            out_trade_no_node = root.find('out_trade_no')
            if out_trade_no_node is None or out_trade_no_node.text is None:
                logger.error(f"微信回调XML缺少out_trade_no节点，原始内容: {request_body.decode('utf-8')}")
                return self.wechat_response('FAIL', '数据格式错误')
            out_trade_no = out_trade_no_node.text

            # 安全获取transaction_id
            transaction_id_node = root.find('transaction_id')
            if transaction_id_node is None or transaction_id_node.text is None:
                logger.error(f"微信回调XML缺少transaction_id节点，原始内容: {request_body.decode('utf-8')}")
                return self.wechat_response('FAIL', '数据格式错误')
            transaction_id = transaction_id_node.text

            # 安全获取total_fee
            total_fee_node = root.find('total_fee')
            if total_fee_node is None or total_fee_node.text is None:
                logger.error(f"微信回调XML缺少total_fee节点，原始内容: {request_body.decode('utf-8')}")
                return self.wechat_response('FAIL', '数据格式错误')
            total_fee = int(total_fee_node.text)

            logger.info(
                f"回调参数解析成功: out_trade_no={out_trade_no}, transaction_id={transaction_id}, total_fee={total_fee}")

            if return_code != 'SUCCESS' or result_code != 'SUCCESS':
                logger.warning(f"支付状态异常: return_code={return_code}, result_code={result_code}")
                return self.wechat_response('FAIL', '支付失败')

            # 验证签名
            if not self.verify_signature(request_body):
                logger.error(f"签名验证失败，订单号: {out_trade_no}")
                return self.wechat_response('FAIL', '签名验证失败')
            logger.info(f"签名验证成功，订单号: {out_trade_no}")

            # 查找订单
            try:
                order = Czjilu.objects.get(dingdan_id=out_trade_no, leixing=5)
                logger.info(f"找到订单: {out_trade_no}, 当前状态: {order.zhuangtai}")
            except Czjilu.DoesNotExist:
                logger.error(f"考核订单不存在: {out_trade_no}")
                return self.wechat_response('FAIL', '订单不存在')

            if order.zhuangtai != 9:
                logger.warning(f"订单状态非未支付: {order.zhuangtai}, 订单号: {out_trade_no}")
                # 已支付的订单直接返回成功，避免微信重复回调
                if order.zhuangtai == 3:
                    logger.info(f"订单已支付，直接返回成功: {out_trade_no}")
                    return self.wechat_response('SUCCESS', 'OK')
                return self.wechat_response('FAIL', '订单状态异常')

            # 验证金额
            wechat_yuan = total_fee / 100
            if abs(wechat_yuan - float(order.jine)) > 0.01:
                logger.error(f"金额不一致: 订单金额={order.jine}, 回调金额={wechat_yuan}, 订单号: {out_trade_no}")
                return self.wechat_response('FAIL', '金额不一致')
            logger.info(f"金额验证通过: {wechat_yuan}元")

            # 更新订单状态为已支付
            order.zhuangtai = 3
            order.save()
            logger.info(f"订单状态更新为已支付: {out_trade_no}")

            # 从临时表获取业务参数并创建审核记录
            try:
                from dengji.models import KaohePayTemp
                from dengji.utils import create_shenhe_jilu_from_temp
                from yonghu.models import UserMain

                temp = KaohePayTemp.objects.get(dingdan_id=out_trade_no, yonghuid=order.yonghuid)
                logger.info(f"找到临时表记录: {out_trade_no}, 用户ID: {order.yonghuid}")

                user = UserMain.objects.get(yonghuid=order.yonghuid)
                logger.info(f"获取用户信息成功: {user.yonghuid}")

                success, msg, record = create_shenhe_jilu_from_temp(user, temp)
                if success:
                    logger.info(f"创建审核记录成功: jilu_id={record.jilu_id}, 订单号: {out_trade_no}")
                else:
                    logger.error(f"创建审核记录失败: {msg}, 订单号: {out_trade_no}")
                    # 订单已支付但记录创建失败，需要标记订单异常，人工介入
                    order.zhuangtai = 10  # 10表示支付成功但业务处理失败
                    order.save()
                    logger.error(f"订单状态标记为异常(10): {out_trade_no}")

            except KaohePayTemp.DoesNotExist:
                logger.error(f"临时表无记录，订单号: {out_trade_no}, 用户ID: {order.yonghuid}")
                # 尝试从attach解析（兼容旧数据）
                attach_element = root.find('attach')
                if attach_element is not None and attach_element.text:
                    try:
                        attach_data = json.loads(attach_element.text)
                        logger.info(f"从attach解析数据成功: {attach_data}")
                        # 这里可以保留旧逻辑，但建议只记录日志
                    except Exception as e:
                        logger.error(f"解析attach失败: {str(e)}")
            except Exception as e:
                logger.error(f"处理临时表或创建审核记录异常: {str(e)}", exc_info=True)
                # 标记订单异常
                order.zhuangtai = 10
                order.save()
                logger.error(f"订单状态标记为异常(10): {out_trade_no}")

            # 更新收支记录
            try:
                from peizhi.models import Szjilu
                from decimal import Decimal
                from dingdan.utils import update_daily_income

                jine_decimal = Decimal(str(order.jine))
                update_daily_income(jine_decimal)
                logger.info(f"更新每日收入成功: {jine_decimal}元")

                szjilu, created = Szjilu.objects.get_or_create(
                    id=1,
                    defaults={
                        'zongsy': Decimal('0.00'),
                        'zongls': Decimal('0.00'),
                        'zongzc': Decimal('0.00'),
                        'jrzc': Decimal('0.00'),
                        'jrls': Decimal('0.00'),
                    }
                )
                szjilu.zongsy += jine_decimal
                szjilu.zongls += jine_decimal
                szjilu.jrls += jine_decimal
                szjilu.save()
                logger.info(f"更新收支记录成功: zongsy={szjilu.zongsy}")
            except Exception as e:
                logger.error(f"更新收支记录失败: {str(e)}", exc_info=True)

            logger.info(f"考核支付回调处理完成，订单号: {out_trade_no}")
            return self.wechat_response('SUCCESS', 'OK')

        except ET.ParseError as e:
            logger.error(f"XML解析失败: {str(e)}, 原始数据: {request.body.decode('utf-8')}")
            return self.wechat_response('FAIL', '数据格式错误')
        except Exception as e:
            logger.error(f"考核支付回调异常: {str(e)}", exc_info=True)
            return self.wechat_response('FAIL', '处理异常')

    def verify_signature(self, xml_data):
        """验证微信支付签名"""
        try:
            root = ET.fromstring(xml_data)
            sign_node = root.find('sign')
            if sign_node is None or sign_node.text is None:
                logger.error("微信回调XML缺少sign节点")
                return False
            sign = sign_node.text

            params = {}
            for child in root:
                if child.tag != 'sign' and child.text is not None:
                    params[child.tag] = child.text

            sorted_params = sorted(params.items(), key=lambda x: x[0])
            sign_string = '&'.join([f"{key}={value}" for key, value in sorted_params if value])
            sign_string += f'&key={settings.WEIXIN_SHANGHUMIYAO}'
            calculated_sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest().upper()

            result = sign == calculated_sign
            if not result:
                logger.error(f"签名验证失败: 原签名={sign}, 计算签名={calculated_sign}")
            return result
        except Exception as e:
            logger.error(f"签名验证异常: {str(e)}", exc_info=True)
            return False

    def wechat_response(self, return_code, return_msg):
        """构造微信回调响应XML"""
        xml = f"""<xml>
<return_code><![CDATA[{return_code}]]></return_code>
<return_msg><![CDATA[{return_msg}]]></return_msg>
</xml>"""
        logger.info(f"返回微信响应: {xml}")
        return HttpResponse(xml, content_type='application/xml')




class KaohePayPollView(APIView):
    """考核支付轮询"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        dingdanid = request.data.get('dingdanid')
        if not dingdanid:
            return Response({'code': 400, 'message': '订单ID不能为空'})
        try:
            order = Czjilu.objects.get(dingdan_id=dingdanid, yonghuid=request.user.yonghuid, leixing=5)
            if order.zhuangtai == 3:
                return Response({'code': 200, 'message': '支付成功'})
            return Response({'code': 400, 'message': '订单尚未支付'})
        except Czjilu.DoesNotExist:
            return Response({'code': 400, 'message': '订单不存在'})


class KaohePayFailView(APIView):
    """考核支付失败处理"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        dingdanid = request.data.get('dingdanid')
        if not dingdanid:
            return Response({'code': 400, 'message': '订单ID不能为空'})
        try:
            order = Czjilu.objects.get(dingdan_id=dingdanid, yonghuid=request.user.yonghuid, leixing=5)
            if order.zhuangtai == 9:
                order.delete()
                return Response({'code': 200, 'message': '订单已删除'})
            return Response({'code': 400, 'message': '订单状态无法删除'})
        except Czjilu.DoesNotExist:
            return Response({'code': 400, 'message': '订单不存在'})










class TixianAssetView(APIView):
    """
    获取用户所有可提现资产及费率
    请求方式：POST
    认证：JWT Token
    返回：
    {
        "code": 200,
        "msg": "success",
        "data": {
            "dashou_yue": "123.45",
            "dashou_yajin": "500.00",
            "shangjia_yue": "0.00",
            "guanshi_fenyong": "67.89",
            "zuzhang_fenyong": "0.00",
            "kaoheguan_fenyong": "0.00",
            "dashou_rate": 0.08,
            "dashou_yajin_rate": 0.05,
            "shangjia_rate": 0.06,
            "guanshi_rate": 0.08,
            "zuzhang_rate": 0.05,
            "kaoheguan_rate": 0.07
        }
    }
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        user = request.user
        # 初始化返回数据，默认全部为0
        data = {
            'dashou_yue': '0.00',
            'dashou_yajin': '0.00',
            'shangjia_yue': '0.00',
            'guanshi_fenyong': '0.00',
            'zuzhang_fenyong': '0.00',
            'kaoheguan_fenyong': '0.00',
            'dashou_rate': 0.00,
            'dashou_yajin_rate': 0.00,
            'shangjia_rate': 0.00,
            'guanshi_rate': 0.00,
            'zuzhang_rate': 0.00,
            'kaoheguan_rate': 0.00,
        }

        # ------------------- 打手资产 -------------------
        try:
            dashou = user.dashou_profile
            data['dashou_yue'] = str(dashou.yue)
            data['dashou_yajin'] = str(dashou.yajin)
        except ObjectDoesNotExist:
            pass

        # ------------------- 商家资产 -------------------
        try:
            shangjia = user.shop_profile
            data['shangjia_yue'] = str(shangjia.yue)
        except ObjectDoesNotExist:
            pass

        # ------------------- 管事资产 -------------------
        try:
            guanshi = user.guanshi_profile
            data['guanshi_fenyong'] = str(guanshi.yue)
        except ObjectDoesNotExist:
            pass

        # ------------------- 组长资产 -------------------
        try:
            zuzhang = user.zuzhang_profile
            data['zuzhang_fenyong'] = str(zuzhang.ketixian_jine)
        except ObjectDoesNotExist:
            pass

        # ------------------- 审核官（考核官）资产 -------------------
        try:
            kaoheguan = user.shenheguan_profile
            data['kaoheguan_fenyong'] = str(kaoheguan.yue)
        except ObjectDoesNotExist:
            pass

        # ------------------- 费率查询（从 Lilubiao 获取） -------------------
        # 打手提现费率 (类型 '5')
        lilu_obj = Lilubiao.objects.filter(fadanpingtai='5').first()
        data['dashou_rate'] = float(lilu_obj.lilu) if lilu_obj and lilu_obj.lilu is not None else 0.00

        # 打手保证金提现费率 (类型 '11')
        lilu_obj = Lilubiao.objects.filter(fadanpingtai='11').first()
        data['dashou_yajin_rate'] = float(lilu_obj.lilu) if lilu_obj and lilu_obj.lilu is not None else 0.00

        # 商家提现费率 (类型 '10')
        lilu_obj = Lilubiao.objects.filter(fadanpingtai='10').first()
        data['shangjia_rate'] = float(lilu_obj.lilu) if lilu_obj and lilu_obj.lilu is not None else 0.00

        # 管事提现费率 (类型 '6')
        lilu_obj = Lilubiao.objects.filter(fadanpingtai='6').first()
        data['guanshi_rate'] = float(lilu_obj.lilu) if lilu_obj and lilu_obj.lilu is not None else 0.00

        # 组长提现费率 (类型 '8')
        lilu_obj = Lilubiao.objects.filter(fadanpingtai='8').first()
        data['zuzhang_rate'] = float(lilu_obj.lilu) if lilu_obj and lilu_obj.lilu is not None else 0.00

        # 审核官（考核官）提现费率 (类型 '9')
        lilu_obj = Lilubiao.objects.filter(fadanpingtai='9').first()
        data['kaoheguan_rate'] = float(lilu_obj.lilu) if lilu_obj and lilu_obj.lilu is not None else 0.00

        return Response({
            'code': 200,
            'msg': '获取成功',
            'data': data
        }, status=status.HTTP_200_OK)







# views.py 或相应的视图文件


class GuanshiContactView(APIView):
    """
    管事获取自己的邀请人（组长）信息
    路径: /api/yonghu/guanshi_contact
    方法: POST
    权限: JWT认证
    请求体: 无（仅需携带合法token）
    成功返回:
        code: 200,
        data: {
            uid: "1234567",       // 组长用户ID
            nicheng: "张三",      // 组长昵称
            touxiang: "avatar/xxx.jpg"  // 组长头像相对路径（前端拼接完整URL）
        }
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 1. 获取当前登录用户（必须已通过JWT认证）
        current_user = request.user  # 类型: UserMain

        # 2. 校验是否为管事身份（存在管事扩展表记录）
        try:
            guanshi_profile = current_user.guanshi_profile
        except ObjectDoesNotExist:
            return Response({
                'code': 403,
                'msg': '您还不是管事，无法获取组长信息',
                'data': None
            })

        # 3. 获取邀请人ID（管事扩展表中的 yaoqingren 字段存储的是邀请人的 yonghuid）
        inviter_yonghuid = guanshi_profile.yaoqingren
        if not inviter_yonghuid:
            return Response({
                'code': 404,
                'msg': '未找到邀请人信息',
                'data': None
            })

        # 4. 根据邀请人用户ID查询用户主表
        try:
            inviter_user = UserMain.objects.get(yonghuid=inviter_yonghuid)
        except UserMain.DoesNotExist:
            logger.error(f"邀请人用户不存在: yonghuid={inviter_yonghuid}")
            return Response({
                'code': 404,
                'msg': '邀请人账号异常',
                'data': None
            })

        # 5. 获取邀请人昵称（从老板扩展表取，若不存在则给默认值）
        try:
            inviter_nicheng = inviter_user.boss_profile.nickname
        except ObjectDoesNotExist:
            inviter_nicheng = '组长'  # 兜底昵称

        # 6. 构造返回数据
        response_data = {
            'uid': inviter_user.yonghuid,
            'nicheng': inviter_nicheng,
            'touxiang': inviter_user.avatar or ''  # 头像相对路径
        }

        return Response({
            'code': 200,
            'msg': '获取成功',
            'data': response_data
        })