"""商品发布与管理后台视图。

包含商品类型/专区/商品发布、规则图片上传、会员信息查询/修改/发布、
管理员商品/公告/专区/轮播/类型修改、商品内容获取与修改、规则修改。
"""
# ==================== 标准库 ====================
import os
import json
import time
import random
import string
import uuid
import hashlib
import requests
import logging
import decimal
from datetime import timedelta
from decimal import Decimal, InvalidOperation, ROUND_CEILING
import defusedxml.ElementTree as ET

# ==================== Django 内置 ====================
from django.conf import settings
from django.db import transaction, connection
from django.db.models import Q
from gvsdsdk.fluent import db, func, FQ
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse
from django.utils import timezone

# ==================== DRF 框架 ====================
from rest_framework.views import APIView, View
from rest_framework.response import Response
from rest_framework import permissions, status
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
from rest_framework.throttling import AnonRateThrottle

# ==================== 项目工具函数 ====================
from utils.oss_utils import validate_image, upload_to_oss, delete_from_oss
from utils.money import format_yuan, quantize_yuan, yuan_to_fen
from backend.utils import (
    update_guanshi_daily_by_action,
    update_guanshi_xufei_daily,
    update_zuzhang_daily_by_action
)
from users.fadan_fenhong_utils import process_fadan_fenhong

# ==================== 各App模型 ====================
from ..models import (
    ShangpinLeixing, ShangpinZhuanqu, Shangpin, Huiyuan,
    Czjilu, Gsfenhong, Huiyuangoumai, DuociFenhong
)
from users.models import (
    AdminProfile, UserDashou, UserGuanshi, UserZuzhang, UserShangjia
)
from users.business_models import User

from orders.models import CommissionRate
from config.models import Gonggao, Lunbo

from orders.models import Penalty  # 用于罚款类型
from jituan.services.club_config import (
    get_commission_rate,
    get_commission_rate_object,
    get_huiyuan_price,
    get_huiyuan_fenchong,
)
from jituan.services.club_context import resolve_effective_club_id
from jituan.services.club_write import resolve_club_id_for_write
from jituan.services.club_user import get_payment_openid
from jituan.services.club_penalty import resolve_gsfenhong_club_id

import traceback

# ==================== 日志实例 ====================
logger = logging.getLogger(__name__)


class ShangpinLeixingFabuView(APIView):
    """
    商品类型发布接口
    接收图片、类型介绍、抢单要求类型等字段
    需要管理员权限
    """
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser)  # 需要处理文件上传

    def post(self, request):
        try:
            # === 1. 权限验证 ===
            # 获取当前用户
            user_main = request.user

            # 1.1 验证前端传递的账号是否匹配（使用phone字段）
            zhanghao = request.data.get('zhanghao', '').strip()
            if not zhanghao:
                return Response(
                    {'code': 401, 'msg': '未提供账号信息', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 验证账号是否匹配（使用phone字段比较）
            if user_main.Phone != zhanghao:
                return Response(
                    {'code': 401, 'msg': '账号验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.2 验证是否为管理员（检查user_type字段）
            if user_main.UserType != 'admin':
                return Response(
                    {'code': 401, 'msg': '权限不足', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.3 验证管理员扩展表（使用AdminProfile模型）
            try:
                admin_profile = AdminProfile.query.get(user=user_main)
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'msg': '管理员信息不存在', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # === 2. 接收并验证字段 ===
            # 2.1 必填字段验证
            jieshao = request.data.get('jieshao', '').strip()
            yaoqiuleixing = request.data.get('yaoqiuleixing')


            if not jieshao:
                return Response(
                    {'code': 400, 'msg': '类型介绍不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            if yaoqiuleixing not in ['1', '2']:
                return Response(
                    {'code': 400, 'msg': '抢单要求类型无效', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2.2 验证图片
            tupian_file = request.FILES.get('file')
            if not tupian_file:

                return Response(
                    {'code': 400, 'msg': '请上传类型图片', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证图片格式和大小
            is_valid, error_msg = validate_image(tupian_file)
            if not is_valid:
                return Response(
                    {'code': 400, 'msg': f'图片验证失败: {error_msg}', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2.3 根据抢单要求类型验证对应字段
            huiyuan_id = request.data.get('huiyuan_id', '').strip()
            yongjin = request.data.get('yongjin', '').strip()


            # 转换yaoqiuleixing为整数便于处理
            yaoqiuleixing_int = int(yaoqiuleixing)

            if yaoqiuleixing_int == 1:  # 会员抢单
                if not huiyuan_id:
                    return Response(
                        {'code': 400, 'msg': '会员抢单必须选择会员', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                # 验证会员ID是否存在
                try:
                    huiyuan_obj = Huiyuan.query.get(huiyuan_id=huiyuan_id)
                except Huiyuan.DoesNotExist:
                    return Response(
                        {'code': 400, 'msg': '会员ID不存在', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                # 会员ID为字符串，佣金为空
                yongjin_value = None
                huiyuan_id_value = huiyuan_id
            else:  # yaoqiuleixing_int == 2 佣金抢单
                if not yongjin:
                    return Response(
                        {'code': 400, 'msg': '佣金抢单必须填写佣金金额', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                try:
                    # 验证佣金为有效数字
                    yongjin_value = float(yongjin)
                    if yongjin_value <= 0:
                        return Response(
                            {'code': 400, 'msg': '佣金金额必须大于0', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                except ValueError:
                    return Response(
                        {'code': 400, 'msg': '佣金金额格式错误', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                huiyuan_id_value = None

            # === 3. 创建商品类型记录 ===
            with transaction.atomic():
                # 3.1 创建商品类型对象
                leixing_obj = ShangpinLeixing(
                    jieshao=jieshao,
                    yaoqiuleixing=yaoqiuleixing_int,
                    huiyuan_id=huiyuan_id_value,
                    yongjin=yongjin_value,
                    # tupian_url 先留空，上传成功后再更新
                )

                # 保存到数据库获取ID
                leixing_obj.save()
                leixing_id = leixing_obj.id

                # === 4. 处理图片上传 ===
                try:
                    # 4.1 生成文件名和路径
                    file_extension = os.path.splitext(tupian_file.name)[1].lower()
                    if not file_extension:
                        file_extension = '.jpg'

                    # 生成唯一文件名：商品类型ID + 随机UUID + 后缀
                    unique_filename = f"{leixing_id}_{uuid.uuid4().hex}{file_extension}"

                    # 构建OSS文件路径：a_long/leixing/{leixing_id}/{filename}
                    oss_folder = 'a_long'  # 根文件夹
                    leixing_folder = 'leixing'  # 类型文件夹

                    # 构建完整路径
                    oss_file_path = f"{oss_folder}/{leixing_folder}/{leixing_id}/{unique_filename}"

                    # 4.2 上传到OSS
                    tupian_url = upload_to_oss(tupian_file, oss_file_path)

                    if not tupian_url:
                        # 上传失败，抛出异常触发回滚
                        raise Exception("图片上传到OSS失败")

                    # 4.3 更新商品类型的图片URL（存储相对路径）
                    leixing_obj.tupian_url = oss_file_path  # 存相对路径，方便拼接
                    leixing_obj.save()

                except Exception as oss_error:
                    # 图片上传失败，事务会回滚，商品类型记录也会被删除
                    print(f"OSS上传失败: {oss_error}")
                    # 手动抛出异常触发事务回滚
                    raise Exception(f"图片上传失败: {str(oss_error)}")

                # === 5. 构建返回数据 ===
                response_data = {
                    'id': leixing_id,
                    'jieshao': jieshao,
                    'yaoqiuleixing': yaoqiuleixing_int,
                    'tupian_url': leixing_obj.tupian_url,  # 相对路径
                    'huiyuan_id': huiyuan_id_value,
                    'yongjin': str(yongjin_value) if yongjin_value else None
                }

                # 返回成功响应
                return Response({
                    'code': 0,
                    'msg': '商品类型添加成功',
                    'data': response_data
                })

        except Exception as e:
            # 捕获所有异常，返回500错误
            traceback.print_exc()
            return Response({
                'code': 500,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class ShangpinZhuanquFabuView(APIView):
    """
    商品专区发布接口
    接收专区名称、类型ID
    需要管理员权限
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            # === 1. 权限验证 ===
            user_main = request.user

            # 1.1 验证账号（使用phone字段）
            zhanghao = request.data.get('zhanghao', '').strip()
            if not zhanghao:
                return Response(
                    {'code': 401, 'msg': '未提供账号信息', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if user_main.Phone != zhanghao:
                return Response(
                    {'code': 401, 'msg': '账号验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.2 验证是否为管理员（检查user_type字段）
            if user_main.UserType != 'admin':
                return Response(
                    {'code': 401, 'msg': '权限不足', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.3 验证管理员扩展表（使用AdminProfile模型）
            try:
                admin_profile = AdminProfile.query.get(user=user_main)
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'msg': '管理员信息不存在', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # === 2. 接收并验证字段 ===
            mingzi = request.data.get('mingzi', '').strip()
            leixing_id = request.data.get('leixing_id')
            tupian_url = (request.data.get('tupian_url') or '').strip()

            # 2.1 验证必填字段
            if not mingzi:
                return Response(
                    {'code': 400, 'msg': '专区名称不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            if not leixing_id:
                return Response(
                    {'code': 400, 'msg': '类型ID不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2.2 验证类型ID是否存在
            try:
                # 验证商品类型是否存在
                leixing_obj = ShangpinLeixing.query.get(id=leixing_id)
            except ShangpinLeixing.DoesNotExist:
                return Response(
                    {'code': 400, 'msg': '商品类型不存在', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2.3 验证名称长度（15汉字以内）
            if len(mingzi) > 45:  # 数据库字段最大长度
                return Response(
                    {'code': 400, 'msg': '专区名称过长', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # === 3. 创建商品专区记录 ===
            club_id = resolve_club_id_for_write(request)
            zhuanqu_obj = ShangpinZhuanqu(
                mingzi=mingzi,
                leixing_id=leixing_id,
                club_id=club_id,
                tupian_url=tupian_url,
            )

            zhuanqu_obj.save()

            # === 4. 构建返回数据 ===
            response_data = {
                'id': zhuanqu_obj.id,
                'mingzi': mingzi,
                'leixing_id': leixing_id,
                'tupian_url': tupian_url,
            }

            # 返回成功响应
            return Response({
                'code': 0,
                'msg': '商品专区添加成功',
                'data': response_data
            })

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


class ShangpinFabuView(APIView):
    """
    商品发布接口
    接收商品信息、图片等字段
    需要管理员权限
    """
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser)  # 需要处理文件上传

    def post(self, request):
        try:
            # === 1. 权限验证 ===
            user_main = request.user

            # 1.1 验证账号（使用phone字段）
            zhanghao = request.data.get('zhanghao', '').strip()
            if not zhanghao:
                return Response(
                    {'code': 401, 'msg': '未提供账号信息', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if user_main.Phone != zhanghao:
                return Response(
                    {'code': 401, 'msg': '账号验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.2 验证是否为管理员（检查user_type字段）
            if user_main.UserType != 'admin':
                return Response(
                    {'code': 401, 'msg': '权限不足', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.3 验证管理员扩展表（使用AdminProfile模型）
            try:
                admin_profile = AdminProfile.query.get(user=user_main)
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'msg': '管理员信息不存在', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # === 2. 接收并验证字段 ===
            # 2.1 验证必填字段
            biaoti = request.data.get('biaoti', '').strip()
            jiage = request.data.get('jiage', '').strip()
            kucun = request.data.get('kucun', '').strip()
            leixing_id = request.data.get('leixing_id')
            zhuanqu_id = request.data.get('zhuanqu_id')
            yaoqiuleixing = request.data.get('yaoqiuleixing')
            jieshao = request.data.get('jieshao', '').strip()

            # 验证图片
            shangpin_tupian = request.FILES.get('shangpin_tupian')
            if not shangpin_tupian:

                return Response(
                    {'code': 400, 'msg': '请上传商品图片', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证图片格式和大小
            is_valid, error_msg = validate_image(shangpin_tupian)
            if not is_valid:
                return Response(
                    {'code': 400, 'msg': f'商品图片验证失败: {error_msg}', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2.2 验证必填字段是否为空
            required_fields = {
                'biaoti': biaoti,
                'jiage': jiage,
                'kucun': kucun,
                'leixing_id': leixing_id,
                'zhuanqu_id': zhuanqu_id,
                'yaoqiuleixing': yaoqiuleixing,
                'jieshao': jieshao
            }

            for field_name, field_value in required_fields.items():
                if not field_value:
                    return Response(
                        {'code': 400, 'msg': f'{field_name}不能为空', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

            # 2.3 验证数值字段
            try:
                jiage_value = float(jiage)
                if jiage_value <= 0:
                    return Response(
                        {'code': 400, 'msg': '商品价格必须大于0', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
            except ValueError:
                return Response(
                    {'code': 400, 'msg': '商品价格格式错误', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            try:
                kucun_value = int(kucun)
                if kucun_value < 0:
                    return Response(
                        {'code': 400, 'msg': '库存不能为负数', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
            except ValueError:
                return Response(
                    {'code': 400, 'msg': '库存必须为整数', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证抢单要求类型
            if yaoqiuleixing not in ['1', '2']:
                return Response(
                    {'code': 400, 'msg': '抢单要求类型无效', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # === 3. 验证关联数据 ===
            # 3.1 验证商品类型
            try:
                leixing_obj = ShangpinLeixing.query.get(id=leixing_id)
            except ShangpinLeixing.DoesNotExist:
                return Response(
                    {'code': 400, 'msg': '商品类型不存在', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 3.2 根据抢单要求类型验证商品类型
            yaoqiuleixing_int = int(yaoqiuleixing)

            if yaoqiuleixing_int == 1:  # 会员抢单
                # 需要验证商品类型的抢单要求类型是否为1
                if leixing_obj.yaoqiuleixing != 1:
                    return Response(
                        {'code': 400, 'msg': '商品类型与抢单要求类型不匹配', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 获取会员ID（从前端或商品类型）
                huiyuan_id = request.data.get('huiyuan_id', leixing_obj.huiyuan_id)
                if not huiyuan_id:
                    return Response(
                        {'code': 400, 'msg': '会员ID不能为空', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 验证会员是否存在
                try:
                    huiyuan_obj = Huiyuan.query.get(huiyuan_id=huiyuan_id)
                except Huiyuan.DoesNotExist:
                    return Response(
                        {'code': 400, 'msg': '会员不存在', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 设置会员相关字段
                huiyuan_id_value = huiyuan_id
                yongjin_value = None
            else:  # 佣金抢单
                # 需要验证商品类型的抢单要求类型是否为2
                if leixing_obj.yaoqiuleixing != 2:
                    return Response(
                        {'code': 400, 'msg': '商品类型与抢单要求类型不匹配', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 获取佣金（从前端或商品类型）
                yongjin = request.data.get('yongjin', leixing_obj.yongjin)
                if not yongjin:
                    return Response(
                        {'code': 400, 'msg': '佣金金额不能为空', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                try:
                    yongjin_value = float(yongjin)
                    if yongjin_value <= 0:
                        return Response(
                            {'code': 400, 'msg': '佣金金额必须大于0', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                except ValueError:
                    return Response(
                        {'code': 400, 'msg': '佣金金额格式错误', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                huiyuan_id_value = None

            # 3.3 验证商品专区
            try:
                zhuanqu_obj = ShangpinZhuanqu.query.get(id=zhuanqu_id, leixing_id=leixing_id)
            except ShangpinZhuanqu.DoesNotExist:
                return Response(
                    {'code': 400, 'msg': '商品专区不存在或与商品类型不匹配', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # === 4. 创建商品记录 ===
            with transaction.atomic():
                # 4.1 获取其他字段
                xuzhi = request.data.get('xuzhi', '').strip()
                xiaoliang = request.data.get('xiaoliang', '0').strip()

                # 转换销量为整数
                try:
                    duiwai_xiaoliang_value = int(xiaoliang) if xiaoliang else 0
                except ValueError:
                    duiwai_xiaoliang_value = 0

                # 4.2 创建商品对象
                club_id = resolve_club_id_for_write(request)
                shangpin_obj = Shangpin(
                    biaoqian=biaoti,
                    jiage=jiage_value,
                    kucun=kucun_value,
                    leixing_id=leixing_id,
                    zhuanqu_id=zhuanqu_id,
                    duiwai_xiaoliang=duiwai_xiaoliang_value,
                    jieshao=jieshao,
                    xiadan_xuzhi=xuzhi,
                    yaoqiuleixing=yaoqiuleixing_int,
                    huiyuan_id=huiyuan_id_value,
                    yongjin=yongjin_value,
                    club_id=club_id,
                    # tupian_url 先留空，上传成功后再更新
                )

                # 保存到数据库获取ID
                shangpin_obj.save()
                shangpin_id = shangpin_obj.id

                # === 5. 处理商品图片上传 ===
                try:
                    # 5.1 生成文件名和路径
                    file_extension = os.path.splitext(shangpin_tupian.name)[1].lower()
                    if not file_extension:
                        file_extension = '.jpg'

                    # 构建OSS文件路径：a_long/Spcc{shangpin_id}/{filename}
                    oss_folder = 'a_long'  # 根文件夹
                    spcc_folder = f"Spcc{shangpin_id}"  # 商品图片文件夹

                    # 生成文件名：Spcc{shangpin_id}{file_extension}
                    unique_filename = f"Spcc{shangpin_id}{file_extension}"

                    # 构建完整路径
                    oss_file_path = f"{oss_folder}/{spcc_folder}/{unique_filename}"

                    # 5.2 上传到OSS
                    tupian_url = upload_to_oss(shangpin_tupian, oss_file_path)

                    if not tupian_url:
                        # 上传失败，抛出异常触发回滚
                        raise Exception("商品图片上传到OSS失败")

                    # 5.3 更新商品的图片URL（存储相对路径）
                    shangpin_obj.tupian_url = oss_file_path  # 存相对路径
                    shangpin_obj.save()

                except Exception as oss_error:
                    # 图片上传失败，事务会回滚，商品记录也会被删除
                    #print(f"商品图片OSS上传失败: {oss_error}")
                    # 手动抛出异常触发事务回滚
                    raise Exception(f"商品图片上传失败: {str(oss_error)}")

                # === 6. 构建返回数据 ===
                response_data = {
                    'shangpin_id': shangpin_id,
                    'biaoti': biaoti,
                    'jiage': str(jiage_value),
                    'kucun': kucun_value,
                    'leixing_id': leixing_id,
                    'zhuanqu_id': zhuanqu_id,
                    'xiaoliang': duiwai_xiaoliang_value,
                    'jieshao': jieshao,
                    'xuzhi': xuzhi,
                    'yaoqiuleixing': yaoqiuleixing_int,
                    'huiyuan_id': huiyuan_id_value,
                    'yongjin': str(yongjin_value) if yongjin_value else None,
                    'tupian_url': shangpin_obj.tupian_url  # 相对路径
                }

                # 返回成功响应
                return Response({
                    'code': 0,
                    'msg': '商品发布成功',
                    'data': response_data
                })

        except Exception as e:
            # 捕获所有异常，返回500错误
            traceback.print_exc()
            return Response({
                'code': 500,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class GuizeTupianShangchuanView(APIView):
    """
    规则图片上传接口
    接收商品ID和规则图片
    需要管理员权限
    """
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser)  # 需要处理文件上传

    def post(self, request):
        try:
            # === 1. 权限验证 ===
            user_main = request.user

            # 1.1 验证账号（使用phone字段）
            zhanghao = request.data.get('zhanghao', '').strip()
            if not zhanghao:
                return Response(
                    {'code': 401, 'msg': '未提供账号信息', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if user_main.Phone != zhanghao:
                return Response(
                    {'code': 401, 'msg': '账号验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.2 验证是否为管理员（检查user_type字段）
            if user_main.UserType != 'admin':
                return Response(
                    {'code': 401, 'msg': '权限不足', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.3 验证管理员扩展表（使用AdminProfile模型）
            try:
                admin_profile = AdminProfile.query.get(user=user_main)
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'msg': '管理员信息不存在', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # === 2. 接收并验证字段 ===
            # 2.1 验证商品ID
            shangpin_id = request.data.get('shangpin_id')
            if not shangpin_id:
                return Response(
                    {'code': 400, 'msg': '商品ID不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2.2 验证规则图片
            guize_tupian = request.FILES.get('guize_tupian')
            if not guize_tupian:
                return Response(
                    {'code': 400, 'msg': '请上传规则图片', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证图片格式和大小
            is_valid, error_msg = validate_image(guize_tupian)
            if not is_valid:
                return Response(
                    {'code': 400, 'msg': f'规则图片验证失败: {error_msg}', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # === 3. 验证商品是否存在 ===
            try:
                shangpin_obj = Shangpin.query.get(id=shangpin_id)
            except Shangpin.DoesNotExist:
                return Response(
                    {'code': 400, 'msg': '商品不存在', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # === 4. 处理规则图片上传 ===
            try:
                # 4.1 生成文件名和路径
                file_extension = os.path.splitext(guize_tupian.name)[1].lower()
                if not file_extension:
                    file_extension = '.jpg'

                # 构建OSS文件路径：a_long/Spgz{shangpin_id}/{filename}
                oss_folder = 'a_long'  # 根文件夹
                spgz_folder = f"Spgz{shangpin_id}"  # 规则图片文件夹

                # 生成文件名：Spgz{shangpin_id}{file_extension}
                unique_filename = f"Spgz{shangpin_id}{file_extension}"

                # 构建完整路径
                oss_file_path = f"{oss_folder}/{spgz_folder}/{unique_filename}"

                # 4.2 上传到OSS
                tupian_url = upload_to_oss(guize_tupian, oss_file_path)

                if not tupian_url:
                    # 上传失败
                    return Response({
                        'code': 500,
                        'msg': '规则图片上传失败',
                        'data': None
                    }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

                # 4.3 更新商品的规则图片URL（存储相对路径）
                shangpin_obj.guize_tupian = oss_file_path  # 存相对路径
                shangpin_obj.save()

            except Exception as oss_error:
                # OSS上传失败
                print(f"规则图片OSS上传失败: {oss_error}")
                return Response({
                    'code': 500,
                    'msg': f'规则图片上传失败: {str(oss_error)}',
                    'data': None
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # === 5. 构建返回数据 ===
            response_data = {
                'shangpin_id': shangpin_id,
                'guize_tupian_url': oss_file_path  # 相对路径
            }

            # 返回成功响应
            return Response({
                'code': 0,
                'msg': '规则图片上传成功',
                'data': response_data
            })

        except Exception as e:
            # 捕获所有异常，返回500错误
            traceback.print_exc()
            return Response({
                'code': 500,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)





class AdHuiyuanHqView(APIView):
    """
    管理员获取会员信息和商品类型接口
    需要管理员权限
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            # === 1. 权限验证 ===
            # 获取当前用户
            user_main = request.user

            # 1.1 验证前端传递的账号是否匹配（使用phone字段）
            zhanghao = request.data.get('zhanghao', '').strip()
            if not zhanghao:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 验证账号是否匹配（使用phone字段比较）
            if user_main.Phone != zhanghao:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.2 验证是否为管理员（检查user_type字段）
            if user_main.UserType != 'admin':
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.3 验证管理员扩展表（使用AdminProfile模型）
            try:
                admin_profile = AdminProfile.query.get(user=user_main)
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # === 2. 查询会员表数据 ===
            # 查询所有会员数据，按创建时间倒序排列
            huiyuan_queryset = Huiyuan.query.all().order_by('-CreateTime')

            # 构建会员数据列表
            huiyuan_list = []
            for huiyuan in huiyuan_queryset:
                huiyuan_data = {
                    'huiyuan_id': huiyuan.huiyuan_id,  # 会员ID
                    'jieshao': huiyuan.jieshao,  # 会员介绍（会员标题）
                    'jtjieshao': huiyuan.jtjieshao if huiyuan.jtjieshao else '',  # 会员规则介绍（具体介绍）
                    'jiage': str(huiyuan.jiage),  # 会员价格（转换为字符串，避免Decimal序列化问题）
                    'guanshifc': str(huiyuan.guanshifc),  # 管事分成（转换为字符串）
                    'goumai_cishu': huiyuan.goumai_cishu,  # 购买次数（销量）
                    'CreateTime': huiyuan.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if huiyuan.CreateTime else None,
                    # 创建时间
                    'UpdateTime': huiyuan.UpdateTime.strftime('%Y-%m-%d %H:%M:%S') if huiyuan.UpdateTime else None
                    # 更新时间
                }
                huiyuan_list.append(huiyuan_data)

            # === 3. 查询商品类型表数据 ===
            # 筛选抢单要求类型等于数字1的所有数据（yaoqiuleixing=1）
            shangpinleixing_queryset = ShangpinLeixing.query.filter(
                yaoqiuleixing=1  # 抢单要求类型为1（会员抢单）
            ).order_by('id')  # 按ID排序

            # 构建商品类型数据列表
            shangpinleixing_list = []
            for leixing in shangpinleixing_queryset:
                # 注意：这里只需要特定的字段
                leixing_data = {
                    'id': leixing.id,  # 商品类型ID
                    'huiyuan_id': leixing.huiyuan_id,  # 会员ID（关联字段）
                    'jieshao': leixing.jieshao,  # 类型介绍（商品类型名称）
                    'tupian_url': leixing.tupian_url if leixing.tupian_url else ''  # 商品类型图片相对URL
                }
                shangpinleixing_list.append(leixing_data)

            # === 4. 构建返回数据 ===
            response_data = {
                'huiyuanList': huiyuan_list,
                'shangpinleixingList': shangpinleixing_list
            }

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

        except Exception as e:
            # 捕获所有异常，返回500错误
            traceback.print_exc()
            return Response({
                'code': 500,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)





class HuiyuanXiugaiView(APIView):
    """
    会员修改接口
    需要管理员权限
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            # === 1. 权限验证 ===
            user_main = request.user

            # 1.1 验证前端传递的账号是否匹配（使用phone字段）
            zhanghao = request.data.get('zhanghao', '').strip()
            if not zhanghao:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if user_main.Phone != zhanghao:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.2 验证是否为管理员（检查user_type字段）
            if user_main.UserType != 'admin':
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.3 验证管理员扩展表
            try:
                admin_profile = AdminProfile.query.get(user=user_main)
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # === 2. 接收并验证必填字段 ===
            huiyuan_id = request.data.get('huiyuan_id', '').strip()
            if not huiyuan_id:
                return Response(
                    {'code': 400, 'msg': '会员ID不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # === 3. 查询会员数据 ===
            try:
                huiyuan_obj = Huiyuan.query.get(huiyuan_id=huiyuan_id)
            except Huiyuan.DoesNotExist:
                return Response(
                    {'code': 400, 'msg': '会员不存在', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # === 4. 更新会员信息 ===
            # 4.1 获取前端传递的字段（只更新有值的字段）
            jieshao = request.data.get('jieshao', '').strip()
            jtjieshao = request.data.get('jtjieshao', '').strip()
            jiage = request.data.get('jiage', '').strip()
            guanshifc = request.data.get('guanshifc', '').strip()

            # 4.2 更新字段
            if jieshao:
                # 验证名称长度（30个字符以内）
                if len(jieshao) > 30:
                    return Response(
                        {'code': 400, 'msg': '会员名称不能超过30个字符', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                huiyuan_obj.jieshao = jieshao

            if jtjieshao:
                # 验证介绍长度（没有长度限制，但做一下基本检查）
                if len(jtjieshao) > 2000:
                    return Response(
                        {'code': 400, 'msg': '会员介绍过长', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                huiyuan_obj.jtjieshao = jtjieshao

            if jiage:
                try:
                    jiage_value = float(jiage)
                    if jiage_value < 0:
                        return Response(
                            {'code': 400, 'msg': '会员价格不能为负数', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                    if jiage_value > 100000:
                        return Response(
                            {'code': 400, 'msg': '会员价格不能超过10万元', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                    huiyuan_obj.jiage = jiage_value
                except ValueError:
                    return Response(
                        {'code': 400, 'msg': '会员价格格式错误', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

            if guanshifc:
                try:
                    guanshifc_value = float(guanshifc)
                    if guanshifc_value < 0:
                        return Response(
                            {'code': 400, 'msg': '管事分成不能为负数', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                    # 检查管事分成是否超过会员价格
                    if hasattr(huiyuan_obj, 'jiage') and huiyuan_obj.jiage:
                        if guanshifc_value > float(huiyuan_obj.jiage):
                            return Response(
                                {'code': 400, 'msg': '管事分成不能超过会员价格', 'data': None},
                                status=status.HTTP_400_BAD_REQUEST
                            )
                    huiyuan_obj.guanshifc = guanshifc_value
                except ValueError:
                    return Response(
                        {'code': 400, 'msg': '管事分成格式错误', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

            # 4.3 检查是否有任何字段需要更新
            if not (jieshao or jtjieshao or jiage or guanshifc):
                return Response(
                    {'code': 400, 'msg': '没有需要更新的字段', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 4.4 保存更新
            huiyuan_obj.save()

            # === 5. 构建返回数据 ===
            response_data = {
                'huiyuan_id': huiyuan_obj.huiyuan_id,
                'jieshao': huiyuan_obj.jieshao,
                'jtjieshao': huiyuan_obj.jtjieshao if huiyuan_obj.jtjieshao else '',
                'jiage': str(huiyuan_obj.jiage),
                'guanshifc': str(huiyuan_obj.guanshifc),
                'goumai_cishu': huiyuan_obj.goumai_cishu,
                'CreateTime': huiyuan_obj.CreateTime.strftime(
                    '%Y-%m-%d %H:%M:%S') if huiyuan_obj.CreateTime else None,
                'UpdateTime': huiyuan_obj.UpdateTime.strftime(
                    '%Y-%m-%d %H:%M:%S') if huiyuan_obj.UpdateTime else None
            }

            # 返回成功响应
            return Response({
                'code': 0,
                'msg': '会员信息修改成功',
                'data': response_data
            })

        except Exception as e:
            # 捕获所有异常，返回500错误
            traceback.print_exc()
            return Response({
                'code': 500,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)







class AdHuiyuanFbView(APIView):
    """
    会员发布接口
    需要管理员权限
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            # === 1. 权限验证 ===
            user_main = request.user

            # 1.1 验证前端传递的账号是否匹配
            zhanghao = request.data.get('zhanghao', '').strip()
            if not zhanghao:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if user_main.Phone != zhanghao:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.2 验证是否为管理员
            if user_main.UserType != 'admin':
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.3 验证管理员扩展表
            try:
                admin_profile = AdminProfile.query.get(user=user_main)
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # === 2. 接收并验证字段 ===
            jieshao = request.data.get('jieshao', '').strip()
            jtjieshao = request.data.get('jtjieshao', '').strip()
            jiage = request.data.get('jiage', '').strip()
            guanshifc = request.data.get('guanshifc', '').strip()

            # 2.1 验证必填字段
            if not jieshao:
                return Response(
                    {'code': 400, 'msg': '会员名称不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            if not jiage:
                return Response(
                    {'code': 400, 'msg': '会员价格不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            if not guanshifc:
                return Response(
                    {'code': 400, 'msg': '管事分成不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2.2 验证字段长度和格式
            if len(jieshao) > 30:
                return Response(
                    {'code': 400, 'msg': '会员名称不能超过30个字符', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            if jtjieshao and len(jtjieshao) > 2000:
                return Response(
                    {'code': 400, 'msg': '会员介绍过长', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2.3 验证价格和分成格式
            try:
                jiage_value = float(jiage)
                if jiage_value <= 0:
                    return Response(
                        {'code': 400, 'msg': '会员价格必须大于0', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                if jiage_value > 100000:
                    return Response(
                        {'code': 400, 'msg': '会员价格不能超过10万元', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
            except ValueError:
                return Response(
                    {'code': 400, 'msg': '会员价格格式错误', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            try:
                guanshifc_value = float(guanshifc)
                if guanshifc_value < 0:
                    return Response(
                        {'code': 400, 'msg': '管事分成不能为负数', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                if guanshifc_value > jiage_value:
                    return Response(
                        {'code': 400, 'msg': '管事分成不能超过会员价格', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
            except ValueError:
                return Response(
                    {'code': 400, 'msg': '管事分成格式错误', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # === 3. 生成会员ID ===
            # 生成6位唯一会员ID，格式：V + 5位随机数字字母
            def generate_huiyuan_id():
                # 使用V开头，后跟5位随机字符（数字和大写字母）
                chars = string.digits + string.ascii_uppercase
                while True:
                    random_part = ''.join(random.choices(chars, k=5))
                    huiyuan_id = f"V{random_part}"
                    # 检查是否已存在
                    if not Huiyuan.query.filter(huiyuan_id=huiyuan_id).exists():
                        return huiyuan_id

            huiyuan_id = generate_huiyuan_id()

            # === 4. 创建会员记录 ===
            with transaction.atomic():
                huiyuan_obj = Huiyuan(
                    huiyuan_id=huiyuan_id,
                    jieshao=jieshao,
                    jtjieshao=jtjieshao if jtjieshao else '',
                    jiage=jiage_value,
                    guanshifc=guanshifc_value,
                    goumai_cishu=0,  # 初始购买次数为0
                )

                huiyuan_obj.save()

            # === 5. 构建返回数据 ===
            response_data = {
                'huiyuan_id': huiyuan_obj.huiyuan_id,
                'jieshao': huiyuan_obj.jieshao,
                'jtjieshao': huiyuan_obj.jtjieshao,
                'jiage': str(huiyuan_obj.jiage),
                'guanshifc': str(huiyuan_obj.guanshifc),
                'goumai_cishu': huiyuan_obj.goumai_cishu,
                'CreateTime': huiyuan_obj.CreateTime.strftime(
                    '%Y-%m-%d %H:%M:%S') if huiyuan_obj.CreateTime else None,
                'UpdateTime': huiyuan_obj.UpdateTime.strftime(
                    '%Y-%m-%d %H:%M:%S') if huiyuan_obj.UpdateTime else None
            }

            # 返回成功响应
            return Response({
                'code': 0,
                'msg': '会员发布成功',
                'data': response_data
            })

        except Exception as e:
            # 捕获所有异常，返回500错误
            traceback.print_exc()
            return Response({
                'code': 500,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

class AdShangpinHuQu(APIView):
    """
    后台商品管理页面数据获取接口
    路径: /shangpin/adsphq/
    方法: POST
    权限: JWT认证 + 管理员权限
    功能: 获取商品管理页面需要的所有数据
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取前端传递的账号
            qianzhanghao = request.data.get('zhanghao', '').strip()
            if not qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 从JWT Token获取当前用户
            dangqianyonghu = request.user

            # 3. 验证账号匹配
            if not hasattr(dangqianyonghu, 'Phone') or str(dangqianyonghu.Phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

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

            # 5. 验证管理员扩展表数据
            try:
                guanliyuan = dangqianyonghu.AdminProfile
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 查询公告与轮播（按俱乐部，默认抢单池）
            from jituan.services.display_config import get_gonggao_content, get_lunbo_urls
            shangpingonggao = get_gonggao_content(request, notice_type=1)
            shangpinlunbo = get_lunbo_urls(request, page_key='order_pool', image_type=1)

            # 8. 查询商品类型数据
            shangpinleixing_data = ShangpinLeixing.query.all().values(
                'id',  # 类型ID
                'jieshao',  # 类型介绍（类型名称）
                'tupian_url',  # 类型图片URL
                'yaoqiuleixing',  # 抢单要求类型（1=会员抢单，2=佣金抢单）
                'huiyuan_id',  # 会员ID（如果yaoqiuleixing=1）
                'yongjin'  # 佣金要求（如果yaoqiuleixing=2）
            )

            # 9. 查询商品专区数据（按当前俱乐部）
            admin_club_id = resolve_effective_club_id(request, getattr(request, 'user', None)) or 'xq'
            shangpinzhuanqu_data = ShangpinZhuanqu.query.filter(club_id=admin_club_id).values(
                'id',  # 专区ID
                'mingzi',  # 专区名称
                'leixing_id',  # 所属类型ID
                'club_id',
            )

            # 10. 查询会员数据
            huiyuan_data = Huiyuan.query.all().values(
                'huiyuan_id',  # 会员ID
                'jieshao',  # 会员介绍（会员名称）
                'jiage'  # 会员价格
            )

            # 11. 查询商品数据（按当前俱乐部）
            shangpin_data = Shangpin.query.filter(club_id=admin_club_id).values(
                'id',  # 商品ID
                'biaoqian',  # 商品标题/标签
                'jiage',  # 商品价格
                'leixing_id',  # 商品类型ID
                'zhuanqu_id',  # 商品专区ID
                'tupian_url',  # 商品图片URL
                'duiwai_xiaoliang',  # 商品对外销量
                'club_id',
            )

            # 12. 构造返回数据
            response_data = {
                'code': 0,
                'message': '获取成功',
                'data': {
                    'shangpingonggao': shangpingonggao,  # 商品公告
                    'shangpinlunbo': shangpinlunbo,  # 轮播图相对URL数组
                    'shangpinleixing': list(shangpinleixing_data),  # 商品类型列表
                    'shangpinzhuanqu': list(shangpinzhuanqu_data),  # 商品专区列表
                    'huiyuanliebiao': list(huiyuan_data),  # 会员列表
                    'shangpinliebiao': list(shangpin_data),  # 商品列表
                }
            }

            return Response(response_data, status=status.HTTP_200_OK)

        except Exception as e:
            print(f"获取商品管理数据异常: {e}")
            return Response(
                {'code': 500, 'message': '服务器内部错误'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )



# shangpin/views.py

class AdGonggaoXiuGai(APIView):
    """
    后台编辑公告接口
    路径: /shangpin/adggxg/
    方法: POST
    权限: JWT认证 + 管理员权限
    功能: 修改公告内容
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取前端传递的账号
            qianzhanghao = request.data.get('zhanghao', '').strip()
            if not qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 从JWT Token获取当前用户
            dangqianyonghu = request.user

            # 3. 验证账号匹配
            if not hasattr(dangqianyonghu, 'Phone') or str(dangqianyonghu.Phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

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

            # 5. 验证管理员扩展表数据
            try:
                guanliyuan = dangqianyonghu.AdminProfile
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 获取公告内容
            gonggao_neirong = request.data.get('gonggao', '').strip()

            # 7. 验证公告内容
            if not gonggao_neirong:
                return Response(
                    {'code': 400, 'message': '公告内容不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            if len(gonggao_neirong) > 300:
                return Response(
                    {'code': 400, 'message': '公告内容不能超过300字', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 8. 查询公告表，类型为1的公告
            gonggao_obj = Gonggao.query.filter(NoticeType=1).first()

            # 如果不存在，则创建
            if not gonggao_obj:
                gonggao_obj = Gonggao(NoticeType=1)

            # 9. 更新公告内容
            gonggao_obj.Content = gonggao_neirong
            gonggao_obj.save()

            # 10. 返回成功响应
            return Response({
                'code': 0,
                'message': '公告更新成功',
                'data': {
                    'gonggao': gonggao_neirong
                }
            })

        except Exception as e:
            print(f"编辑公告异常: {e}")
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


class AdZhuanquXiuGai(APIView):
    """
    后台修改专区名称接口
    路径: /shangpin/adzqxg/
    方法: POST
    权限: JWT认证 + 管理员权限
    功能: 修改专区名称
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 权限验证
            qianzhanghao = request.data.get('zhanghao', '').strip()
            if not qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            dangqianyonghu = request.user

            if not hasattr(dangqianyonghu, 'Phone') or str(dangqianyonghu.Phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if dangqianyonghu.UserType != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            try:
                guanliyuan = dangqianyonghu.AdminProfile
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 获取专区ID和新的专区名称（可选图标）
            zhuanqu_id = request.data.get('zhuanqu_id')
            mingzi = request.data.get('mingzi', '').strip()
            tupian_url = request.data.get('tupian_url', None)

            if not zhuanqu_id:
                return Response(
                    {'code': 400, 'message': '专区ID不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            if not mingzi:
                return Response(
                    {'code': 400, 'message': '专区名称不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            if len(mingzi) > 10:
                return Response(
                    {'code': 400, 'message': '专区名称不能大于10个字', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 3. 查询专区
            try:
                zhuanqu_obj = ShangpinZhuanqu.query.get(id=zhuanqu_id)
            except ShangpinZhuanqu.DoesNotExist:
                return Response(
                    {'code': 400, 'message': '专区不存在', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 4. 更新专区名称（及可选图标；未传 tupian_url 则不改图）
            zhuanqu_obj.mingzi = mingzi
            if tupian_url is not None:
                zhuanqu_obj.tupian_url = (tupian_url or '').strip()
            zhuanqu_obj.save()

            # 5. 返回成功响应
            return Response({
                'code': 0,
                'message': '专区名称修改成功',
                'data': {
                    'id': zhuanqu_obj.id,
                    'mingzi': zhuanqu_obj.mingzi,
                    'leixing_id': zhuanqu_obj.leixing_id,
                    'tupian_url': getattr(zhuanqu_obj, 'tupian_url', '') or '',
                }
            })

        except Exception as e:
            print(f"修改专区名称异常: {e}")
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )




class AdLunboXiuGai(APIView):
    """
    后台编辑轮播图接口
    路径: /shangpin/adlunboxg/
    方法: POST
    权限: JWT认证 + 管理员权限
    功能: 添加或删除轮播图
    """

    permission_classes = [IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser,JSONParser)

    def post(self, request):
        try:
            # 1. 权限验证
            qianzhanghao = request.data.get('zhanghao', '').strip()
            if not qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            dangqianyonghu = request.user

            if not hasattr(dangqianyonghu, 'Phone') or str(dangqianyonghu.Phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if dangqianyonghu.UserType != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            try:
                guanliyuan = dangqianyonghu.AdminProfile
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 获取操作类型
            action = request.data.get('action', '').strip()  # 'add' 或 'delete'

            if action not in ['add', 'delete']:
                return Response(
                    {'code': 400, 'message': '操作类型无效', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 3. 处理删除操作
            if action == 'delete':
                tupian_url = request.data.get('tupian_url', '').strip()

                if not tupian_url:
                    return Response(
                        {'code': 400, 'message': '图片URL不能为空', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 查询轮播图记录
                lunbo_obj = Lunbo.query.filter(ImageURL=tupian_url, ImageType=1).first()

                if not lunbo_obj:
                    return Response(
                        {'code': 400, 'message': '轮播图不存在', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 从OSS删除图片
                delete_success = delete_from_oss(tupian_url)

                if not delete_success:
                    return Response(
                        {'code': 500, 'message': 'OSS删除失败', 'data': None},
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR
                    )

                # 从数据库删除记录
                lunbo_obj.delete()

                return Response({
                    'code': 0,
                    'message': '删除成功',
                    'data': None
                })

            # 4. 处理添加操作
            else:  # action == 'add'
                tupian_file = request.FILES.get('file')

                if not tupian_file:
                    
            
                    return Response(
                        {'code': 400, 'message': '请上传图片', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 验证图片
                is_valid, error_msg = validate_image(tupian_file)
                if not is_valid:
                    #print(f"[轮播图上传] 图片验证失败详情: {error_msg}")
                    # 还可以记录文件大小、名称等信息
                    #print(f"[轮播图上传] 问题文件: {tupian_file.name}, Size: {tupian_file.size}")
                    #print(is_valid)
                    return Response(
                        {'code': 400, 'message': f'图片验证失败: {error_msg}', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 生成文件名和路径
                file_extension = os.path.splitext(tupian_file.name)[1].lower()
                if not file_extension:
                    file_extension = '.jpg'

                # 生成6位随机字符串作为文件名
                random_str = ''.join(random.choices(string.ascii_lowercase + string.digits, k=6))
                unique_filename = f"{random_str}{file_extension}"

                # 构建OSS文件路径：a_long/lunbo/{filename}
                oss_folder = 'a_long'
                lunbo_folder = 'lunbo'

                oss_file_path = f"{oss_folder}/{lunbo_folder}/{unique_filename}"

                # 上传到OSS
                tupian_url = upload_to_oss(tupian_file, oss_file_path)

                if not tupian_url:
                    return Response(
                        {'code': 500, 'message': '图片上传失败', 'data': None},
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR
                    )

                # 创建轮播图记录
                lunbo_obj = Lunbo.query.create(
                    ImageURL=oss_file_path,  # 存相对路径
                    ImageType=1
                )

                return Response({
                    'code': 0,
                    'message': '添加成功',
                    'data': {
                        'tupian_url': lunbo_obj.ImageURL
                    }
                })

        except Exception as e:
            #print(f"编辑轮播图异常: {e}")
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )





class AdLeixingXiuGai(APIView):
    """
    后台编辑商品类型接口 - 优化版
    支持：只改图片、只改字段、两者都改
    拒绝：两者都不改
    """

    permission_classes = [IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser, JSONParser)  # 添加JSONParser支持

    def post(self, request):
        try:
            # 1. 权限验证（保持不变）
            qianzhanghao = request.data.get('zhanghao', '').strip()
            if not qianzhanghao:
                return Response({'code': 401, 'message': '身份验证失败'}, status=status.HTTP_401_UNAUTHORIZED)

            dangqianyonghu = request.user
            if not hasattr(dangqianyonghu, 'Phone') or str(dangqianyonghu.Phone) != qianzhanghao:
                return Response({'code': 401, 'message': '身份验证失败'}, status=status.HTTP_401_UNAUTHORIZED)

            if dangqianyonghu.UserType != 'admin':
                return Response({'code': 401, 'message': '身份验证失败'}, status=status.HTTP_401_UNAUTHORIZED)

            try:
                guanliyuan = dangqianyonghu.AdminProfile
            except AdminProfile.DoesNotExist:
                return Response({'code': 401, 'message': '身份验证失败'}, status=status.HTTP_401_UNAUTHORIZED)

            # 2. 获取商品类型ID
            leixing_id = request.data.get('leixing_id')
            if not leixing_id:
                return Response({'code': 400, 'message': '商品类型ID不能为空', 'data': None},
                                status=status.HTTP_400_BAD_REQUEST)

            # 3. 查询商品类型
            try:
                leixing_obj = ShangpinLeixing.query.get(id=leixing_id)
            except ShangpinLeixing.DoesNotExist:
                return Response({'code': 400, 'message': '商品类型不存在', 'data': None},
                                status=status.HTTP_400_BAD_REQUEST)

            # 4. 获取字段并初始化变更标记
            has_changed = False
            jieshao = request.data.get('jieshao', '').strip()
            yaoqiuleixing = request.data.get('yaoqiuleixing')
            huiyuan_id = request.data.get('huiyuan_id', '').strip()
            yongjin = request.data.get('yongjin', '').strip()
            tupian_url = request.data.get('tupian_url', '').strip()  # 原有图片URL

            # 5. 检查非图片字段是否有变更
            if jieshao and jieshao != leixing_obj.jieshao:
                leixing_obj.jieshao = jieshao
                has_changed = True

            if yaoqiuleixing and int(yaoqiuleixing) != leixing_obj.yaoqiuleixing:
                leixing_obj.yaoqiuleixing = int(yaoqiuleixing)
                has_changed = True

                # 根据类型清空另一个字段
                if leixing_obj.yaoqiuleixing == 1:
                    leixing_obj.yongjin = None
                    if huiyuan_id:
                        leixing_obj.huiyuan_id = huiyuan_id
                        # 验证会员存在
                        try:
                            Huiyuan.query.get(huiyuan_id=huiyuan_id)
                        except Huiyuan.DoesNotExist:
                            return Response({'code': 400, 'msg': '会员ID不存在', 'data': None},
                                            status=status.HTTP_400_BAD_REQUEST)
                else:  # 类型2
                    leixing_obj.huiyuan_id = None
                    if yongjin:
                        try:
                            leixing_obj.yongjin = float(yongjin)
                            if leixing_obj.yongjin <= 0:
                                return Response({'code': 400, 'message': '佣金金额必须大于0', 'data': None},
                                                status=status.HTTP_400_BAD_REQUEST)
                        except ValueError:
                            return Response({'code': 400, 'message': '佣金金额格式错误', 'data': None},
                                            status=status.HTTP_400_BAD_REQUEST)

            # ===== 在现有代码的第5步后面添加 =====

            # 5.5 检查抢单要求类型不变时，会员ID或佣金是否有变更
            if yaoqiuleixing and int(yaoqiuleixing) == leixing_obj.yaoqiuleixing:
                # 类型没有变化，但需要检查对应字段的变化

                # 情况1：会员抢单 (yaoqiuleixing == 1)
                if leixing_obj.yaoqiuleixing == 1:
                    # 检查会员ID是否变更
                    if huiyuan_id and huiyuan_id != leixing_obj.huiyuan_id:
                        # 验证会员存在
                        try:
                            Huiyuan.query.get(huiyuan_id=huiyuan_id)
                        except Huiyuan.DoesNotExist:
                            return Response({'code': 400, 'msg': '会员ID不存在', 'data': None},
                                            status=status.HTTP_400_BAD_REQUEST)

                        leixing_obj.huiyuan_id = huiyuan_id
                        has_changed = True
                        # print(f"会员ID变更: {leixing_obj.huiyuan_id} -> {huiyuan_id}")

                # 情况2：佣金抢单 (yaoqiuleixing == 2)
                elif leixing_obj.yaoqiuleixing == 2:
                    # 检查佣金是否变更
                    if yongjin:
                        try:
                            new_yongjin = float(yongjin)
                            if new_yongjin <= 0:
                                return Response({'code': 400, 'message': '佣金金额必须大于0', 'data': None},
                                                status=status.HTTP_400_BAD_REQUEST)

                            # 判断是否有变化（考虑None的情况）
                            current_yongjin = leixing_obj.yongjin
                            if (current_yongjin is None and new_yongjin != 0) or \
                                    (current_yongjin is not None and abs(
                                        float(current_yongjin) - new_yongjin) > 0.001):
                                leixing_obj.yongjin = new_yongjin
                                has_changed = True
                                # print(f"佣金变更: {current_yongjin} -> {new_yongjin}")

                        except ValueError:
                            return Response({'code': 400, 'message': '佣金金额格式错误', 'data': None},
                                            status=status.HTTP_400_BAD_REQUEST)

            # ===== 添加结束 =====

            # 6. 处理图片上传（如果有新图片）
            tupian_file = request.FILES.get('file')
            if tupian_file:
                # 验证图片
                is_valid, error_msg = validate_image(tupian_file)
                if not is_valid:
                    return Response({'code': 400, 'message': f'图片验证失败: {error_msg}', 'data': None},
                                    status=status.HTTP_400_BAD_REQUEST)

                # 删除旧图片（如果存在）
                if leixing_obj.tupian_url:
                    delete_from_oss(leixing_obj.tupian_url)

                # 生成文件名和路径
                file_extension = os.path.splitext(tupian_file.name)[1].lower() or '.jpg'
                oss_folder = 'a_long'
                leixing_folder = 'leixing'

                # 使用原文件名或生成新文件名
                if leixing_obj.tupian_url:
                    original_filename = leixing_obj.tupian_url.split('/')[-1]
                else:
                    original_filename = f"{leixing_id}_{uuid.uuid4().hex}{file_extension}"

                oss_file_path = f"{oss_folder}/{leixing_folder}/{leixing_id}/{original_filename}"

                # 上传到OSS
                new_tupian_url = upload_to_oss(tupian_file, oss_file_path)
                if not new_tupian_url:
                    return Response({'code': 500, 'message': '图片上传失败', 'data': None},
                                    status=status.HTTP_500_INTERNAL_SERVER_ERROR)

                leixing_obj.tupian_url = oss_file_path  # 存相对路径
                has_changed = True
            elif tupian_url and tupian_url != leixing_obj.tupian_url:
                # 前端传了新URL（可能是从其他地方选择的）
                leixing_obj.tupian_url = tupian_url
                has_changed = True

            # 7. 验证是否至少有变更
            if not has_changed:
                return Response({
                    'code': 400,
                    'message': '没有检测到任何更改',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 8. 保存并返回
            leixing_obj.save()
            # 8. 保存商品类型
            leixing_obj.save()

            # 🔴 ===========【新增：同步更新关联商品】===========
            try:
                # 1. 准备商品更新字典
                shangpin_update_fields = {}

                # 始终同步抢单要求类型
                shangpin_update_fields['yaoqiuleixing'] = leixing_obj.yaoqiuleixing

                # 根据抢单类型，同步对应字段并清空另一个
                if leixing_obj.yaoqiuleixing == 1:  # 会员抢单
                    if leixing_obj.huiyuan_id:  # 仅当会员ID非空时更新
                        shangpin_update_fields['huiyuan_id'] = leixing_obj.huiyuan_id
                    # 清空佣金字段
                    shangpin_update_fields['yongjin'] = None
                elif leixing_obj.yaoqiuleixing == 2:  # 佣金抢单
                    if leixing_obj.yongjin:  # 仅当佣金非空时更新
                        shangpin_update_fields['yongjin'] = leixing_obj.yongjin
                    # 清空会员字段
                    shangpin_update_fields['huiyuan_id'] = None

                # 2. 执行批量更新（确保只有实际有变化的字段才会执行）
                if shangpin_update_fields:
                    # 查询所有属于该类型的商品（使用filter而非all以提高效率）
                    affected_count = Shangpin.query.filter(
                        leixing_id=leixing_obj.id
                    ).update(**shangpin_update_fields)

                    # 可选：记录日志以便追踪
                    # logger.info(f"商品类型{leixing_obj.id}修改成功，已同步更新{affected_count}个关联商品")

            except Exception as sync_error:
                # 商品同步失败不影响商品类型本身的修改，但记录错误
                # 可根据需求决定是否抛出异常回滚整个事务
                # 当前设计：记录错误但允许商品类型修改成功
                logger.error(f"修改十五")

                # 可在此添加更详细的错误日志记录
            # 🔴 ===========【新增结束】===========







            response_data = {
                'id': leixing_obj.id,
                'jieshao': leixing_obj.jieshao,
                'tupian_url': leixing_obj.tupian_url,
                'yaoqiuleixing': leixing_obj.yaoqiuleixing,
                'huiyuan_id': leixing_obj.huiyuan_id,
                'yongjin': str(leixing_obj.yongjin) if leixing_obj.yongjin else None
            }

            return Response({
                'code': 0,
                'message': '商品类型修改成功',
                'data': response_data
            })

        except Exception as e:
            print(f"编辑商品类型异常: {e}")
            return Response({'code': 500, 'message': '服务器内部错误', 'data': None},
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)





class AdShangpinNeiRongHuoQu(APIView):
    """
    后台获取商品详情接口
    路径: /shangpin/adspnrhq/
    方法: POST
    权限: JWT认证 + 管理员权限
    功能: 获取指定商品的详细信息
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

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

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

            # 2. 权限验证
            dangqianyonghu = request.user

            # 验证phone字段匹配
            if not hasattr(dangqianyonghu, 'Phone') or str(dangqianyonghu.Phone) != qianzhanghao:
                logger.warning(
                    f"账号不匹配: 当前用户phone={getattr(dangqianyonghu, 'Phone', '无')}, 前端账号={qianzhanghao}")
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 验证用户类型
            if dangqianyonghu.UserType != 'admin':
                logger.warning(f"非管理员访问: user_type={dangqianyonghu.UserType}")
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 3. 验证管理员扩展表
            try:
                guanliyuan = dangqianyonghu.AdminProfile
            except AdminProfile.DoesNotExist:
                logger.warning(f"管理员扩展表不存在: user_id={dangqianyonghu.id}")
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 查询商品数据
            try:
                shangpin_obj = Shangpin.query.get(id=shangpin_id)
            except Shangpin.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '商品不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 5. 构建返回数据（与前端字段对应）
            response_data = {
                'tupian_url': shangpin_obj.tupian_url or '',  # 商品图片相对URL
                'biaoti': shangpin_obj.biaoqian or '',  # 商品标题（前端用biaoti，对应biaoqian）
                'jieshao': shangpin_obj.jieshao or '',  # 商品介绍
                'jiage': str(shangpin_obj.jiage) if shangpin_obj.jiage else '0.00',  # 商品价格
                'kucun': shangpin_obj.kucun,  # 商品库存
                'zhenshixiaoliang': shangpin_obj.zhenshi_xiaoliang,  # 商品真实销量
                'duiwaixiaoliang': shangpin_obj.duiwai_xiaoliang,  # 商品对外销量
                'xiadanxuzhi': shangpin_obj.xiadan_xuzhi or '',  # 下单须知
                'guizetupian_url': shangpin_obj.guize_tupian or '',  # 规则图片相对URL
                'yajin': str(shangpin_obj.yajin) if hasattr(shangpin_obj, 'yajin') and shangpin_obj.yajin else None,
                # 押金（可能不存在）
                'chuangjianshijian': shangpin_obj.CreateTime.strftime(
                    '%Y-%m-%d %H:%M:%S') if shangpin_obj.CreateTime else '',
                'genggaishijian': shangpin_obj.UpdateTime.strftime(
                    '%Y-%m-%d %H:%M:%S') if shangpin_obj.UpdateTime else '',
                # 额外字段，前端可能不需要但可以保留
                'leixing_id': shangpin_obj.leixing_id,
                'zhuanqu_id': shangpin_obj.zhuanqu_id,
                'yaoqiuleixing': shangpin_obj.yaoqiuleixing,
                'huiyuan_id': shangpin_obj.huiyuan_id,
                'yongjin': str(shangpin_obj.yongjin) if shangpin_obj.yongjin else None,
            }

            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
            )







class AdShangpinXiuGai(APIView):
    """
    后台更改商品数据接口 - 修复版
    修复：1. 每次上传生成新文件名 2. 解决浏览器缓存问题
    """

    permission_classes = [IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser, JSONParser)

    def post(self, request):
        try:
            # 1. 权限验证
            qianzhanghao = request.data.get('zhanghao', '').strip()
            shangpin_id = request.data.get('shangpin_id')

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

            # 验证身份
            dangqianyonghu = request.user

            if not hasattr(dangqianyonghu, 'Phone') or str(dangqianyonghu.Phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if dangqianyonghu.UserType != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            try:
                guanliyuan = dangqianyonghu.AdminProfile
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 判断操作类型：删除还是修改
            action = request.data.get('action', 'update').strip().lower()

            if action == 'delete':
                return self._delete_shangpin(shangpin_id)
            else:
                return self._update_shangpin(request, shangpin_id)

        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 _delete_shangpin(self, shangpin_id):
        """删除商品逻辑"""
        try:
            # 查询商品
            try:
                shangpin_obj = Shangpin.query.get(id=shangpin_id)
            except Shangpin.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '商品不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 获取图片URL（如果有）
            tupian_url = shangpin_obj.tupian_url
            guizetupian_url = shangpin_obj.guize_tupian

            # 异步或同步删除OSS图片
            if tupian_url:
                try:
                    delete_from_oss(tupian_url)
                except Exception as e:
                    logger.warning(f"删除商品图片失败: {tupian_url}, 错误: {e}")

            if guizetupian_url:
                try:
                    delete_from_oss(guizetupian_url)
                except Exception as e:
                    logger.warning(f"删除规则图片失败: {guizetupian_url}, 错误: {e}")

            # 删除数据库记录
            shangpin_obj.delete()

            return Response({
                'code': 0,
                'message': '删除成功',
                'data': {
                    'shangpin_id': shangpin_id,
                    'deleted': True
                }
            })

        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 _update_shangpin(self, request, shangpin_id):
        """修改商品逻辑 - 修复：每次上传生成新文件名"""
        try:
            # 查询商品
            try:
                shangpin_obj = Shangpin.query.get(id=shangpin_id)
            except Shangpin.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '商品不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            has_changes = False

            # 获取原图片URL（如果有）
            old_tupian_url = shangpin_obj.tupian_url

            # 3. 处理商品图片上传（如果有新商品图片）
            tupian_file = request.FILES.get('tupian_file')
            new_tupian_url = None

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

                # 生成新文件名：时间戳 + 随机数 + 原扩展名
                timestamp = int(time.time() * 1000) % 100000000  # 8位时间戳
                random_num = random.randint(1000, 9999)
                file_extension = os.path.splitext(tupian_file.name)[1].lower() or '.jpg'
                new_filename = f"sp_{timestamp}_{random_num}{file_extension}"

                # 确定OSS路径
                oss_folder = 'a_long'
                shangpin_folder = 'shangpin'
                oss_file_path = f"{oss_folder}/{shangpin_folder}/{new_filename}"

                # 删除旧图片（如果存在）
                if old_tupian_url:
                    try:
                        delete_from_oss(old_tupian_url)
                        logger.info(f"已删除旧商品图片: {old_tupian_url}")
                    except Exception as e:
                        logger.warning(f"删除旧商品图片失败: {old_tupian_url}, 错误: {e}")
                        # 继续上传新图片，不中断流程

                # 上传到OSS
                new_tupian_url = upload_to_oss(tupian_file, oss_file_path)

                if not new_tupian_url:
                    return Response(
                        {'code': 500, 'message': '商品图片上传失败', 'data': None},
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR
                    )

                # 更新数据库中的图片URL
                shangpin_obj.tupian_url = oss_file_path  # 存相对路径
                has_changes = True
                logger.info(f"商品图片更新成功: {oss_file_path}")

            # 4. 处理其他字段（只更新有变化的字段）
            # 注意：这里同时处理 request.data（文本字段）和可能有文件的情况
            field_mapping = {
                'biaoti': 'biaoqian',
                'jieshao': 'jieshao',
                'jiage': 'jiage',
                'kucun': 'kucun',
                'duiwaixiaoliang': 'duiwai_xiaoliang',
                'xiadanxuzhi': 'xiadan_xuzhi',
                'yajin': 'yajin',
            }

            for front_field, db_field in field_mapping.items():
                # 注意：request.data 可能包含文件和其他字段，但DRF会处理好
                if front_field in request.data:
                    new_value = request.data.get(front_field)

                    # 空字符串处理
                    if new_value == '':
                        new_value = None

                    if new_value is not None:
                        # 获取当前值
                        current_value = getattr(shangpin_obj, db_field)

                        # 类型转换
                        try:
                            if db_field in ['jiage', 'yajin']:
                                # 价格和押金
                                if new_value:
                                    new_value = Decimal(str(new_value))
                                else:
                                    new_value = None
                            elif db_field in ['kucun', 'duiwai_xiaoliang']:
                                # 库存和对外销量
                                if new_value:
                                    new_value = int(float(new_value))
                                else:
                                    new_value = 0
                        except (ValueError, TypeError, InvalidOperation) as e:
                            logger.warning(f"字段{front_field}转换失败: {new_value}, 错误: {e}")
                            continue

                        # 检查是否有变化（处理None值）
                        if current_value != new_value:
                            setattr(shangpin_obj, db_field, new_value)
                            has_changes = True

            # 5. 如果没有检测到任何更改
            if not has_changes:
                return Response({
                    'code': 400,
                    'message': '没有检测到任何更改',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 6. 保存更改
            shangpin_obj.save()

            # 7. 返回更新后的数据
            response_data = {
                'tupian_url': shangpin_obj.tupian_url or '',
                'biaoti': shangpin_obj.biaoqian or '',
                'jieshao': shangpin_obj.jieshao or '',
                'jiage': str(shangpin_obj.jiage) if shangpin_obj.jiage else '0.00',
                'kucun': shangpin_obj.kucun,
                'duiwaixiaoliang': shangpin_obj.duiwai_xiaoliang,
                'xiadanxuzhi': shangpin_obj.xiadan_xuzhi or '',
                'yajin': str(shangpin_obj.yongjin) if shangpin_obj.yongjin else None,
                'genggaishijian': shangpin_obj.UpdateTime.strftime(
                    '%Y-%m-%d %H:%M:%S') if shangpin_obj.UpdateTime else '',
            }

            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
            )


class AdShangpinGuizeXiuGai(APIView):
    """
    后台规则图片更换接口 - 修复版
    修复：每次上传生成新文件名，避免浏览器缓存
    """

    permission_classes = [IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser, JSONParser)

    def post(self, request):
        try:
            # 1. 权限验证
            qianzhanghao = request.data.get('zhanghao', '').strip()
            shangpin_id = request.data.get('shangpin_id')
            action = request.data.get('action', 'update').strip().lower()

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

            # 验证身份
            dangqianyonghu = request.user

            if not hasattr(dangqianyonghu, 'Phone') or str(dangqianyonghu.Phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if dangqianyonghu.UserType != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            try:
                guanliyuan = dangqianyonghu.AdminProfile
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 查询商品
            try:
                shangpin_obj = Shangpin.query.get(id=shangpin_id)
            except Shangpin.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '商品不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 3. 处理不同操作
            if action == 'delete':
                return self._delete_guize_image(shangpin_obj)
            elif action == 'update':
                return self._update_guize_image(request, shangpin_obj)
            else:
                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 _delete_guize_image(self, shangpin_obj):
        """删除规则图片"""
        guizetupian_url = shangpin_obj.guize_tupian

        if guizetupian_url:
            # 从OSS删除
            try:
                delete_success = delete_from_oss(guizetupian_url)
                '''if delete_success:
                    logger.info(f"已删除规则图片: {guizetupian_url}")
                else:
                    logger.warning(f"OSS删除失败，但继续删除数据库记录: {guizetupian_url}")'''
            except Exception as e:
                logger.warning(f"删除规则图片异常: {e}")

            # 清除数据库记录
            shangpin_obj.guize_tupian = ''
            shangpin_obj.save()

        return Response({
            'code': 0,
            'message': '删除成功',
            'data': {
                'guizetupian_url': ''
            }
        })

    def _update_guize_image(self, request, shangpin_obj):
        """更新规则图片 - 修复：每次上传生成新文件名"""
        guize_file = request.FILES.get('guize_file')

        if not guize_file:
            return Response(
                {'code': 400, 'message': '请上传规则图片', 'data': None},
                status=status.HTTP_400_BAD_REQUEST
            )

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

        # 获取原规则图片URL
        old_guizetupian_url = shangpin_obj.guize_tupian

        # 生成新文件名：时间戳 + 随机数 + 原扩展名
        timestamp = int(time.time() * 1000) % 100000000  # 8位时间戳
        random_num = random.randint(1000, 9999)
        file_extension = os.path.splitext(guize_file.name)[1].lower() or '.jpg'
        new_filename = f"gz_{timestamp}_{random_num}{file_extension}"

        # 确定OSS路径
        oss_folder = 'a_long'
        guize_folder = 'guize'  # 修改为你的要求：a_long/guize/
        oss_file_path = f"{oss_folder}/{guize_folder}/{new_filename}"

        # 删除旧图片（如果存在）
        if old_guizetupian_url:
            try:
                delete_from_oss(old_guizetupian_url)
                #logger.info(f"已删除旧规则图片: {old_guizetupian_url}")
            except Exception as e:
                logger.warning(f"删除旧规则图片失败: {old_guizetupian_url}, 错误: {e}")
                # 继续上传新图片，不中断流程

        # 上传到OSS
        new_guizetupian_url = upload_to_oss(guize_file, oss_file_path)

        if not new_guizetupian_url:
            return Response(
                {'code': 500, 'message': '规则图片上传失败', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

        # 更新数据库（存相对路径）
        shangpin_obj.guize_tupian = oss_file_path
        shangpin_obj.save()

        #logger.info(f"规则图片更新成功: {oss_file_path}")

        return Response({
            'code': 0,
            'message': '规则图片更新成功',
            'data': {
                'guizetupian_url': oss_file_path  # 返回相对路径
            }
        })




# views.py


